[gtk+/wip/frame-synchronization: 817/857] GdkFrameClock: add freeze/thaw



commit 30f5599163793cd72eb1eefde7674da21a3bebf5
Author: Owen W. Taylor <otaylor fishsoup net>
Date:   Wed Oct 3 19:42:13 2012 -0400

    GdkFrameClock: add freeze/thaw
    
    Add the ability to freeze a frame clock, which pauses its operation,
    then thaw it again later to resume.
    
    Initially this is used to implement freezing updates when we are
    waiting for ConfigureNotify in response to changing the size of
    a toplevel.
    
    We need a per-window clock for this to work properly, so add that
    for the X11 backend.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=685460

 gdk/gdkframeclock.c     |   17 ++++++++
 gdk/gdkframeclock.h     |    6 +++
 gdk/gdkframeclockidle.c |   94 ++++++++++++++++++++++++++++++++++++++++-------
 gdk/gdkwindow.c         |    2 +
 gdk/x11/gdkwindow-x11.c |    5 ++
 5 files changed, 110 insertions(+), 14 deletions(-)
---
diff --git a/gdk/gdkframeclock.c b/gdk/gdkframeclock.c
index 9fcf642..d385123 100644
--- a/gdk/gdkframeclock.c
+++ b/gdk/gdkframeclock.c
@@ -226,6 +226,23 @@ gdk_frame_clock_request_phase (GdkFrameClock      *clock,
 }
 
 
+void
+gdk_frame_clock_freeze (GdkFrameClock *clock)
+{
+  g_return_if_fail (GDK_IS_FRAME_CLOCK (clock));
+
+  GDK_FRAME_CLOCK_GET_IFACE (clock)->freeze (clock);
+}
+
+
+void
+gdk_frame_clock_thaw (GdkFrameClock *clock)
+{
+  g_return_if_fail (GDK_IS_FRAME_CLOCK (clock));
+
+  GDK_FRAME_CLOCK_GET_IFACE (clock)->thaw (clock);
+}
+
 /**
  * gdk_frame_clock_get_requested:
  * @clock: the clock
diff --git a/gdk/gdkframeclock.h b/gdk/gdkframeclock.h
index fe0ea58..a733b55 100644
--- a/gdk/gdkframeclock.h
+++ b/gdk/gdkframeclock.h
@@ -61,6 +61,9 @@ struct _GdkFrameClockInterface
                                         GdkFrameClockPhase  phase);
   GdkFrameClockPhase (* get_requested) (GdkFrameClock      *clock);
 
+  void     (* freeze)              (GdkFrameClock *clock);
+  void     (* thaw)                (GdkFrameClock *clock);
+
   /* signals */
   /* void (* frame_requested)    (GdkFrameClock *clock); */
   /* void (* before_paint)       (GdkFrameClock *clock); */
@@ -77,6 +80,9 @@ void               gdk_frame_clock_request_phase (GdkFrameClock      *clock,
                                                   GdkFrameClockPhase  phase);
 GdkFrameClockPhase gdk_frame_clock_get_requested (GdkFrameClock      *clock);
 
+void     gdk_frame_clock_freeze              (GdkFrameClock *clock);
+void     gdk_frame_clock_thaw                (GdkFrameClock *clock);
+
 /* Convenience API */
 void  gdk_frame_clock_get_frame_time_val (GdkFrameClock  *clock,
                                           GTimeVal       *timeval);
diff --git a/gdk/gdkframeclockidle.c b/gdk/gdkframeclockidle.c
index bdcb16a..2911237 100644
--- a/gdk/gdkframeclockidle.c
+++ b/gdk/gdkframeclockidle.c
@@ -37,6 +37,7 @@ struct _GdkFrameClockIdlePrivate
   guint64 frame_time;
 
   guint idle_id;
+  guint freeze_count;
 
   GdkFrameClockPhase requested;
   GdkFrameClockPhase phase;
@@ -72,6 +73,7 @@ gdk_frame_clock_idle_init (GdkFrameClockIdle *frame_clock_idle)
   priv = frame_clock_idle->priv;
 
   priv->timer = g_timer_new ();
+  priv->freeze_count = 0;
 }
 
 static void
@@ -138,7 +140,7 @@ maybe_start_idle (GdkFrameClockIdle *clock_idle)
 {
   GdkFrameClockIdlePrivate *priv = clock_idle->priv;
 
-  if (priv->idle_id == 0 && priv->requested != 0)
+  if (priv->idle_id == 0 && priv->freeze_count == 0 && priv->requested != 0)
     {
       priv->idle_id = gdk_threads_add_idle_full (GDK_PRIORITY_REDRAW,
                                                  gdk_frame_clock_paint_idle,
@@ -160,19 +162,51 @@ gdk_frame_clock_paint_idle (void *data)
 
   priv->frame_time = compute_frame_time (clock_idle);
 
-  priv->phase = GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT;
-  priv->requested &= ~GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT;
-  g_signal_emit_by_name (G_OBJECT (clock), "before-paint");
-  priv->phase = GDK_FRAME_CLOCK_PHASE_LAYOUT;
-  priv->requested &= ~GDK_FRAME_CLOCK_PHASE_LAYOUT;
-  g_signal_emit_by_name (G_OBJECT (clock), "layout");
-  priv->phase = GDK_FRAME_CLOCK_PHASE_PAINT;
-  priv->requested &= ~GDK_FRAME_CLOCK_PHASE_PAINT;
-  g_signal_emit_by_name (G_OBJECT (clock), "paint");
-  priv->phase = GDK_FRAME_CLOCK_PHASE_AFTER_PAINT;
-  priv->requested &= ~GDK_FRAME_CLOCK_PHASE_AFTER_PAINT;
-  g_signal_emit_by_name (G_OBJECT (clock), "after-paint");
-  priv->phase = GDK_FRAME_CLOCK_PHASE_NONE;
+  switch (priv->phase)
+    {
+    case GDK_FRAME_CLOCK_PHASE_NONE:
+    case GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT:
+      if (priv->freeze_count == 0)
+	{
+	  priv->phase = GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT;
+          priv->requested &= ~GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT;
+          /* We always emit ::before-paint and ::after-paint even if
+           * not explicitly requested, and unlike other phases,
+           * they don't get repeated if you freeze/thaw while
+           * in them. */
+	  g_signal_emit_by_name (G_OBJECT (clock), "before-paint");
+	  priv->phase = GDK_FRAME_CLOCK_PHASE_LAYOUT;
+	}
+    case GDK_FRAME_CLOCK_PHASE_LAYOUT:
+      if (priv->freeze_count == 0)
+	{
+	  priv->phase = GDK_FRAME_CLOCK_PHASE_LAYOUT;
+          if (priv->requested & GDK_FRAME_CLOCK_PHASE_LAYOUT)
+            {
+              priv->requested &= ~GDK_FRAME_CLOCK_PHASE_LAYOUT;
+              g_signal_emit_by_name (G_OBJECT (clock), "layout");
+            }
+	}
+    case GDK_FRAME_CLOCK_PHASE_PAINT:
+      if (priv->freeze_count == 0)
+	{
+	  priv->phase = GDK_FRAME_CLOCK_PHASE_PAINT;
+          if (priv->requested & GDK_FRAME_CLOCK_PHASE_PAINT)
+            {
+              priv->requested &= ~GDK_FRAME_CLOCK_PHASE_PAINT;
+              g_signal_emit_by_name (G_OBJECT (clock), "paint");
+            }
+	}
+    case GDK_FRAME_CLOCK_PHASE_AFTER_PAINT:
+      if (priv->freeze_count == 0)
+	{
+	  priv->phase = GDK_FRAME_CLOCK_PHASE_AFTER_PAINT;
+          priv->requested &= ~GDK_FRAME_CLOCK_PHASE_AFTER_PAINT;
+	  g_signal_emit_by_name (G_OBJECT (clock), "after-paint");
+          /* the ::after-paint phase doesn't get repeated on freeze/thaw */
+	  priv->phase = GDK_FRAME_CLOCK_PHASE_NONE;
+	}
+    }
 
   maybe_start_idle (clock_idle);
 
@@ -199,11 +233,43 @@ gdk_frame_clock_idle_get_requested (GdkFrameClock *clock)
 }
 
 static void
+gdk_frame_clock_idle_freeze (GdkFrameClock *clock)
+{
+  GdkFrameClockIdlePrivate *priv = GDK_FRAME_CLOCK_IDLE (clock)->priv;
+
+  priv->freeze_count++;
+
+  if (priv->freeze_count == 1)
+    {
+      if (priv->idle_id)
+	{
+	  g_source_remove (priv->idle_id);
+	  priv->idle_id = 0;
+	}
+    }
+}
+
+static void
+gdk_frame_clock_idle_thaw (GdkFrameClock *clock)
+{
+  GdkFrameClockIdle *clock_idle = GDK_FRAME_CLOCK_IDLE (clock);
+  GdkFrameClockIdlePrivate *priv = clock_idle->priv;
+
+  g_return_if_fail (priv->freeze_count > 0);
+
+  priv->freeze_count--;
+  if (priv->freeze_count == 0)
+    maybe_start_idle (clock_idle);
+}
+
+static void
 gdk_frame_clock_idle_interface_init (GdkFrameClockInterface *iface)
 {
   iface->get_frame_time = gdk_frame_clock_idle_get_frame_time;
   iface->request_phase = gdk_frame_clock_idle_request_phase;
   iface->get_requested = gdk_frame_clock_idle_get_requested;
+  iface->freeze = gdk_frame_clock_idle_freeze;
+  iface->thaw = gdk_frame_clock_idle_thaw;
 }
 
 GdkFrameClock *
diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
index e3b5026..0505d3f 100644
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@ -4919,6 +4919,7 @@ gdk_window_freeze_toplevel_updates_libgtk_only (GdkWindow *window)
   g_return_if_fail (window->window_type != GDK_WINDOW_CHILD);
 
   window->update_and_descendants_freeze_count++;
+  gdk_frame_clock_freeze (gdk_window_get_frame_clock (window));
 }
 
 /**
@@ -4939,6 +4940,7 @@ gdk_window_thaw_toplevel_updates_libgtk_only (GdkWindow *window)
   g_return_if_fail (window->update_and_descendants_freeze_count > 0);
 
   window->update_and_descendants_freeze_count--;
+  gdk_frame_clock_thaw (gdk_window_get_frame_clock (window));
 
   gdk_window_schedule_update (window);
 }
diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c
index e86cf7d..e86a733 100644
--- a/gdk/x11/gdkwindow-x11.c
+++ b/gdk/x11/gdkwindow-x11.c
@@ -35,6 +35,7 @@
 #include "gdkasync.h"
 #include "gdkeventsource.h"
 #include "gdkdisplay-x11.h"
+#include "gdkframeclockidle.h"
 #include "gdkprivate-x11.h"
 
 #include <stdlib.h>
@@ -712,6 +713,7 @@ _gdk_x11_display_create_window_impl (GdkDisplay    *display,
   GdkWindowImplX11 *impl;
   GdkX11Screen *x11_screen;
   GdkX11Display *display_x11;
+  GdkFrameClock *clock;
 
   Window xparent;
   Visual *xvisual;
@@ -856,6 +858,9 @@ _gdk_x11_display_create_window_impl (GdkDisplay    *display,
   gdk_x11_event_source_select_events ((GdkEventSource *) display_x11->event_source,
                                       GDK_WINDOW_XID (window), event_mask,
                                       StructureNotifyMask | PropertyChangeMask);
+
+  clock = g_object_new (GDK_TYPE_FRAME_CLOCK_IDLE, NULL);
+  gdk_window_set_frame_clock (window, clock);
 }
 
 static GdkEventMask


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