From: Owen W. Taylor Date: Wed, 3 Oct 2012 23:42:13 +0000 (-0400) Subject: GdkFrameClock: add freeze/thaw X-Git-Url: http://pileus.org/git/?a=commitdiff_plain;h=1824796bfb643378b72fdacffa9d923379266819;p=~andy%2Fgtk 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 --- diff --git a/gdk/gdkframeclock.c b/gdk/gdkframeclock.c index 9fcf642c3..d38512384 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 fe0ea58b6..a733b558a 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 bdcb16a08..291123768 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); @@ -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 * diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index e3b5026c8..0505d3fb6 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 e86cf7d2c..e86a73322 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 @@ -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