[gtk+/wip/frame-synchronization: 819/857] Use _NET_WM_FRAME_DRAWN to synchronize frame drawing



commit 5f9fb32b0c22c0f70c8434bbcd3e87a4975e89dd
Author: Owen W. Taylor <otaylor fishsoup net>
Date:   Tue Sep 18 09:37:03 2012 -0400

    Use _NET_WM_FRAME_DRAWN to synchronize frame drawing
    
    As part of the extended _NET_WM_SYNC_REQUEST_COUNTER protocol,
    we get a _NET_WM_FRAME_DRAWN message for each frame we draw. Use this
    to synchronize the updates we are doing with the compositing manager's
    drawing, and ultimately with with display refresh.
    
    We now set the sync request counters on all windows, including
    override-redirect windows, since it is also useful to do synchronized,
    atomic updates for such windows.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=685460

 gdk/x11/gdkdisplay-x11.c |   22 +++++++++++++++
 gdk/x11/gdkwindow-x11.c  |   66 ++++++++++++++++++++++++++++++++++++++++++++-
 gdk/x11/gdkwindow-x11.h  |    3 ++
 3 files changed, 89 insertions(+), 2 deletions(-)
---
diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c
index 5af36d2..5afb11c 100644
--- a/gdk/x11/gdkdisplay-x11.c
+++ b/gdk/x11/gdkdisplay-x11.c
@@ -681,6 +681,13 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
                                              GDK_WINDOW_STATE_ICONIFIED);
             }
 
+          if (window_impl->toplevel &&
+              window_impl->toplevel->frame_pending)
+            {
+              window_impl->toplevel->frame_pending = FALSE;
+              gdk_frame_clock_thaw (gdk_window_get_frame_clock (event->any.window));
+            }
+
           _gdk_x11_window_grab_check_unmap (window, xevent->xany.serial);
         }
 
@@ -1132,6 +1139,21 @@ _gdk_wm_protocols_filter (GdkXEvent *xev,
       return GDK_FILTER_REMOVE;
     }
 
+  else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_FRAME_DRAWN"))
+    {
+      GdkWindowImplX11 *window_impl;
+
+      window_impl = GDK_WINDOW_IMPL_X11 (event->any.window->impl);
+      if (window_impl->toplevel &&
+          window_impl->toplevel->frame_pending)
+        {
+          window_impl->toplevel->frame_pending = FALSE;
+          gdk_frame_clock_thaw (gdk_window_get_frame_clock (event->any.window));
+        }
+
+      return GDK_FILTER_REMOVE;
+    }
+
   return GDK_FILTER_CONTINUE;
 }
 
diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c
index 6b8a0e8..99d2f7f 100644
--- a/gdk/x11/gdkwindow-x11.c
+++ b/gdk/x11/gdkwindow-x11.c
@@ -213,6 +213,51 @@ set_sync_counter(Display     *display,
     XSyncSetCounter(display, counter, sync_value);
 }
 
+static void
+gdk_x11_window_begin_frame (GdkWindow *window)
+{
+  GdkWindowImplX11 *impl;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  impl = GDK_WINDOW_IMPL_X11 (window->impl);
+
+  if (!WINDOW_IS_TOPLEVEL (window) ||
+      impl->toplevel->extended_update_counter == None)
+    return;
+
+  impl->toplevel->current_counter_value += 1;
+  set_sync_counter(GDK_WINDOW_XDISPLAY (impl->wrapper),
+		   impl->toplevel->extended_update_counter,
+		   impl->toplevel->current_counter_value);
+}
+
+static void
+gdk_x11_window_end_frame (GdkWindow *window)
+{
+  GdkWindowImplX11 *impl;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  impl = GDK_WINDOW_IMPL_X11 (window->impl);
+
+  if (!WINDOW_IS_TOPLEVEL (window) ||
+      impl->toplevel->extended_update_counter == None)
+    return;
+
+  impl->toplevel->current_counter_value += 1;
+  set_sync_counter(GDK_WINDOW_XDISPLAY (impl->wrapper),
+		   impl->toplevel->extended_update_counter,
+		   impl->toplevel->current_counter_value);
+
+  if (gdk_x11_screen_supports_net_wm_hint (gdk_window_get_screen (window),
+                                           gdk_atom_intern_static_string ("_NET_WM_FRAME_DRAWN")))
+    {
+      impl->toplevel->frame_pending = TRUE;
+      gdk_frame_clock_freeze (gdk_window_get_frame_clock (window));
+    }
+}
+
 /*****************************************************
  * X11 specific implementations of generic functions *
  *****************************************************/
@@ -616,9 +661,8 @@ ensure_sync_counter (GdkWindow *window)
     {
       GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
       GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window);
-      GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (window->impl);
 
-      if (toplevel && impl->use_synchronized_configure &&
+      if (toplevel &&
 	  toplevel->update_counter == None &&
 	  GDK_X11_DISPLAY (display)->use_sync)
 	{
@@ -718,6 +762,20 @@ setup_toplevel_window (GdkWindow *window,
   ensure_sync_counter (window);
 }
 
+static void
+on_frame_clock_before_paint (GdkFrameClock *clock,
+                             GdkWindow     *window)
+{
+  gdk_x11_window_begin_frame (window);
+}
+
+static void
+on_frame_clock_after_paint (GdkFrameClock *clock,
+                            GdkWindow     *window)
+{
+  gdk_x11_window_end_frame (window);
+}
+
 void
 _gdk_x11_display_create_window_impl (GdkDisplay    *display,
                                      GdkWindow     *window,
@@ -878,6 +936,10 @@ _gdk_x11_display_create_window_impl (GdkDisplay    *display,
 
   clock = g_object_new (GDK_TYPE_FRAME_CLOCK_IDLE, NULL);
   gdk_window_set_frame_clock (window, clock);
+  g_signal_connect (clock, "before-paint",
+                    G_CALLBACK (on_frame_clock_before_paint), window);
+  g_signal_connect (clock, "after-paint",
+                    G_CALLBACK (on_frame_clock_after_paint), window);
 }
 
 static GdkEventMask
diff --git a/gdk/x11/gdkwindow-x11.h b/gdk/x11/gdkwindow-x11.h
index b4b7376..c423652 100644
--- a/gdk/x11/gdkwindow-x11.h
+++ b/gdk/x11/gdkwindow-x11.h
@@ -126,6 +126,9 @@ struct _GdkToplevelX11
   /* Set if the WM is presenting us as focused, i.e. with active decorations
    */
   guint have_focused : 1;
+
+  /* If we're expecting a response from the compositor after painting a frame */
+  guint frame_pending : 1;
   
   gulong map_serial;	/* Serial of last transition from unmapped */
   


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]