]> Pileus Git - ~andy/gtk/commitdiff
GdkFrameClock: add freeze/thaw
authorOwen W. Taylor <otaylor@fishsoup.net>
Wed, 3 Oct 2012 23:42:13 +0000 (19:42 -0400)
committerOwen W. Taylor <otaylor@fishsoup.net>
Thu, 14 Feb 2013 22:19:48 +0000 (17:19 -0500)
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
gdk/gdkframeclock.h
gdk/gdkframeclockidle.c
gdk/gdkwindow.c
gdk/x11/gdkwindow-x11.c

index 9fcf642c363240bb0b3f23fc3bf8b14bd326ce66..d385123842168dd5dbabc757c8f97942397f0fdc 100644 (file)
@@ -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
index fe0ea58b603023f3cb790b6412b50e80a0db0fe9..a733b558a9ec2b9ccde64dd9324f693ed192454d 100644 (file)
@@ -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);
index bdcb16a08a27e92e3af29bbafa2af50d948b5957..29112376874da2145d8b4df00583b93af40b52bd 100644 (file)
@@ -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);
 
@@ -198,12 +232,44 @@ gdk_frame_clock_idle_get_requested (GdkFrameClock *clock)
   return priv->requested;
 }
 
+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 *
index e3b5026c8321aedcc8c4330694ae8a63242364ac..0505d3fb6e698c816f2cad62b83dc8114e3f41ec 100644 (file)
@@ -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);
 }
index e86cf7d2c8b0dbb7d91b468977322e708d89e9f9..e86a73322ce8b1444de9b121bad1e498b29ed18c 100644 (file)
@@ -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