[gtk+/wip/frame-synchronization: 5/19] GdkPaintClock: add freeze/thaw



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

    GdkPaintClock: add freeze/thaw
    
    Add the ability to freeze a paint 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.

 gdk/gdkpaintclock.c     |   17 ++++++++
 gdk/gdkpaintclock.h     |    6 +++
 gdk/gdkpaintclockidle.c |   94 ++++++++++++++++++++++++++++++++++++++++-------
 gdk/gdkwindow.c         |    2 +
 gdk/x11/gdkwindow-x11.c |    5 ++
 5 files changed, 110 insertions(+), 14 deletions(-)
---
diff --git a/gdk/gdkpaintclock.c b/gdk/gdkpaintclock.c
index 5de34d6..3185703 100644
--- a/gdk/gdkpaintclock.c
+++ b/gdk/gdkpaintclock.c
@@ -226,6 +226,23 @@ gdk_paint_clock_request_phase (GdkPaintClock      *clock,
 }
 
 
+void
+gdk_paint_clock_freeze (GdkPaintClock *clock)
+{
+  g_return_if_fail (GDK_IS_PAINT_CLOCK (clock));
+
+  GDK_PAINT_CLOCK_GET_IFACE (clock)->freeze (clock);
+}
+
+
+void
+gdk_paint_clock_thaw (GdkPaintClock *clock)
+{
+  g_return_if_fail (GDK_IS_PAINT_CLOCK (clock));
+
+  GDK_PAINT_CLOCK_GET_IFACE (clock)->thaw (clock);
+}
+
 /**
  * gdk_paint_clock_get_requested:
  * @clock: the clock
diff --git a/gdk/gdkpaintclock.h b/gdk/gdkpaintclock.h
index 0bafc1e..ec821fd 100644
--- a/gdk/gdkpaintclock.h
+++ b/gdk/gdkpaintclock.h
@@ -61,6 +61,9 @@ struct _GdkPaintClockInterface
                                         GdkPaintClockPhase  phase);
   GdkPaintClockPhase (* get_requested) (GdkPaintClock      *clock);
 
+  void     (* freeze)              (GdkPaintClock *clock);
+  void     (* thaw)                (GdkPaintClock *clock);
+
   /* signals */
   /* void (* frame_requested)    (GdkPaintClock *clock); */
   /* void (* before_paint)       (GdkPaintClock *clock); */
@@ -77,6 +80,9 @@ void               gdk_paint_clock_request_phase (GdkPaintClock      *clock,
                                                   GdkPaintClockPhase  phase);
 GdkPaintClockPhase gdk_paint_clock_get_requested (GdkPaintClock      *clock);
 
+void     gdk_paint_clock_freeze              (GdkPaintClock *clock);
+void     gdk_paint_clock_thaw                (GdkPaintClock *clock);
+
 /* Convenience API */
 void  gdk_paint_clock_get_frame_time_val (GdkPaintClock  *clock,
                                           GTimeVal       *timeval);
diff --git a/gdk/gdkpaintclockidle.c b/gdk/gdkpaintclockidle.c
index adbdbe7..88f376c 100644
--- a/gdk/gdkpaintclockidle.c
+++ b/gdk/gdkpaintclockidle.c
@@ -37,6 +37,7 @@ struct _GdkPaintClockIdlePrivate
   guint64 frame_time;
 
   guint idle_id;
+  guint freeze_count;
 
   GdkPaintClockPhase requested;
   GdkPaintClockPhase phase;
@@ -72,6 +73,7 @@ gdk_paint_clock_idle_init (GdkPaintClockIdle *paint_clock_idle)
   priv = paint_clock_idle->priv;
 
   priv->timer = g_timer_new ();
+  priv->freeze_count = 0;
 }
 
 static void
@@ -138,7 +140,7 @@ maybe_start_idle (GdkPaintClockIdle *clock_idle)
 {
   GdkPaintClockIdlePrivate *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_paint_clock_paint_idle,
@@ -160,19 +162,51 @@ gdk_paint_clock_paint_idle (void *data)
 
   priv->frame_time = compute_frame_time (clock_idle);
 
-  priv->phase = GDK_PAINT_CLOCK_PHASE_BEFORE_PAINT;
-  priv->requested &= ~GDK_PAINT_CLOCK_PHASE_BEFORE_PAINT;
-  g_signal_emit_by_name (G_OBJECT (clock), "before-paint");
-  priv->phase = GDK_PAINT_CLOCK_PHASE_LAYOUT;
-  priv->requested &= ~GDK_PAINT_CLOCK_PHASE_LAYOUT;
-  g_signal_emit_by_name (G_OBJECT (clock), "layout");
-  priv->phase = GDK_PAINT_CLOCK_PHASE_PAINT;
-  priv->requested &= ~GDK_PAINT_CLOCK_PHASE_PAINT;
-  g_signal_emit_by_name (G_OBJECT (clock), "paint");
-  priv->phase = GDK_PAINT_CLOCK_PHASE_AFTER_PAINT;
-  priv->requested &= ~GDK_PAINT_CLOCK_PHASE_AFTER_PAINT;
-  g_signal_emit_by_name (G_OBJECT (clock), "after-paint");
-  priv->phase = GDK_PAINT_CLOCK_PHASE_NONE;
+  switch (priv->phase)
+    {
+    case GDK_PAINT_CLOCK_PHASE_NONE:
+    case GDK_PAINT_CLOCK_PHASE_BEFORE_PAINT:
+      if (priv->freeze_count == 0)
+	{
+	  priv->phase = GDK_PAINT_CLOCK_PHASE_BEFORE_PAINT;
+          priv->requested &= ~GDK_PAINT_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_PAINT_CLOCK_PHASE_LAYOUT;
+	}
+    case GDK_PAINT_CLOCK_PHASE_LAYOUT:
+      if (priv->freeze_count == 0)
+	{
+	  priv->phase = GDK_PAINT_CLOCK_PHASE_LAYOUT;
+          if (priv->requested & GDK_PAINT_CLOCK_PHASE_LAYOUT)
+            {
+              priv->requested &= ~GDK_PAINT_CLOCK_PHASE_LAYOUT;
+              g_signal_emit_by_name (G_OBJECT (clock), "layout");
+            }
+	}
+    case GDK_PAINT_CLOCK_PHASE_PAINT:
+      if (priv->freeze_count == 0)
+	{
+	  priv->phase = GDK_PAINT_CLOCK_PHASE_PAINT;
+          if (priv->requested & GDK_PAINT_CLOCK_PHASE_PAINT)
+            {
+              priv->requested &= ~GDK_PAINT_CLOCK_PHASE_PAINT;
+              g_signal_emit_by_name (G_OBJECT (clock), "paint");
+            }
+	}
+    case GDK_PAINT_CLOCK_PHASE_AFTER_PAINT:
+      if (priv->freeze_count == 0)
+	{
+	  priv->phase = GDK_PAINT_CLOCK_PHASE_AFTER_PAINT;
+          priv->requested &= ~GDK_PAINT_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_PAINT_CLOCK_PHASE_NONE;
+	}
+    }
 
   maybe_start_idle (clock_idle);
 
@@ -199,11 +233,43 @@ gdk_paint_clock_idle_get_requested (GdkPaintClock *clock)
 }
 
 static void
+gdk_paint_clock_idle_freeze (GdkPaintClock *clock)
+{
+  GdkPaintClockIdlePrivate *priv = GDK_PAINT_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_paint_clock_idle_thaw (GdkPaintClock *clock)
+{
+  GdkPaintClockIdle *clock_idle = GDK_PAINT_CLOCK_IDLE (clock);
+  GdkPaintClockIdlePrivate *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_paint_clock_idle_interface_init (GdkPaintClockInterface *iface)
 {
   iface->get_frame_time = gdk_paint_clock_idle_get_frame_time;
   iface->request_phase = gdk_paint_clock_idle_request_phase;
   iface->get_requested = gdk_paint_clock_idle_get_requested;
+  iface->freeze = gdk_paint_clock_idle_freeze;
+  iface->thaw = gdk_paint_clock_idle_thaw;
 }
 
 GdkPaintClock *
diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
index 5d65c08..459d8dd 100644
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@ -4836,6 +4836,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_paint_clock_freeze (gdk_window_get_paint_clock (window));
 }
 
 /**
@@ -4856,6 +4857,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_paint_clock_thaw (gdk_window_get_paint_clock (window));
 
   gdk_window_schedule_update (window);
 }
diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c
index e4b880f..9c11ecd 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 "gdkpaintclockidle.h"
 #include "gdkprivate-x11.h"
 
 #include <stdlib.h>
@@ -711,6 +712,7 @@ _gdk_x11_display_create_window_impl (GdkDisplay    *display,
   GdkWindowImplX11 *impl;
   GdkX11Screen *x11_screen;
   GdkX11Display *display_x11;
+  GdkPaintClock *clock;
 
   Window xparent;
   Visual *xvisual;
@@ -855,6 +857,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_PAINT_CLOCK_IDLE, NULL);
+  gdk_window_set_paint_clock (window, clock);
 }
 
 static GdkEventMask



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