diff options
Diffstat (limited to 'gdk')
-rw-r--r-- | gdk/gdk.symbols | 2 | ||||
-rw-r--r-- | gdk/gdkframeclock.c | 44 | ||||
-rw-r--r-- | gdk/gdkframeclock.h | 5 | ||||
-rw-r--r-- | gdk/gdkframeclockidle.c | 93 | ||||
-rw-r--r-- | gdk/gdkframeclockprivate.h | 2 |
5 files changed, 121 insertions, 25 deletions
diff --git a/gdk/gdk.symbols b/gdk/gdk.symbols index b01f3e5191..1f99c6406c 100644 --- a/gdk/gdk.symbols +++ b/gdk/gdk.symbols @@ -188,6 +188,8 @@ gdk_events_pending gdk_event_type_get_type gdk_filter_return_get_type gdk_flush +gdk_frame_clock_begin_updating +gdk_frame_clock_end_updating gdk_frame_clock_get_current_timings gdk_frame_clock_get_frame_counter gdk_frame_clock_get_frame_time diff --git a/gdk/gdkframeclock.c b/gdk/gdkframeclock.c index 4d1c7658b9..1994b00e8b 100644 --- a/gdk/gdkframeclock.c +++ b/gdk/gdkframeclock.c @@ -285,7 +285,12 @@ gdk_frame_clock_get_frame_time (GdkFrameClock *frame_clock) * corresponding the requested phase will be emitted the next * time the frame clock processes. Multiple calls to * gdk_frame_clock_request_phase() will be combined togethe - * and only one frame processed. + * and only one frame processed. If you are displaying animated + * content and want to continually request the + * %GDK_FRAME_CLOCK_PHASE_UPDATE phase for a period of time, + * you should use gdk_frame_clock_begin_updating() instead, since + * this allows GTK+ to adjust system parameters to get maximally + * smooth animations. * * Since: 3.8 */ @@ -298,6 +303,43 @@ gdk_frame_clock_request_phase (GdkFrameClock *frame_clock, GDK_FRAME_CLOCK_GET_CLASS (frame_clock)->request_phase (frame_clock, phase); } +/** + * gdk_frame_clock_begin_updating: + * @frame_clock: a #GdkFrameClock + * + * Starts updates for an animation. Until a matching call to + * gdk_frame_clock_end_updating() is made, the frame clock will continually + * request a new frame with the %GDK_FRAME_CLOCK_PHASE_UPDATE phase. + * This function may be called multiple times and frames will be + * requested until gdk_frame_clock_end_updating() is called the same + * number of times. + * + * Since: 3.8 + */ +void +gdk_frame_clock_begin_updating (GdkFrameClock *frame_clock) +{ + g_return_if_fail (GDK_IS_FRAME_CLOCK (frame_clock)); + + GDK_FRAME_CLOCK_GET_CLASS (frame_clock)->begin_updating (frame_clock); +} + +/** + * gdk_frame_clock_end_updating: + * @frame_clock: a #GdkFrameClock + * + * Stops updates for an animation. See the documentation for + * gdk_frame_clock_begin_updating(). + * + * Since: 3.8 + */ +void +gdk_frame_clock_end_updating (GdkFrameClock *frame_clock) +{ + g_return_if_fail (GDK_IS_FRAME_CLOCK (frame_clock)); + + GDK_FRAME_CLOCK_GET_CLASS (frame_clock)->end_updating (frame_clock); +} void _gdk_frame_clock_freeze (GdkFrameClock *clock) diff --git a/gdk/gdkframeclock.h b/gdk/gdkframeclock.h index f6529795af..a82d5cf594 100644 --- a/gdk/gdkframeclock.h +++ b/gdk/gdkframeclock.h @@ -82,6 +82,11 @@ GDK_AVAILABLE_IN_3_8 void gdk_frame_clock_request_phase (GdkFrameClock *frame_clock, GdkFrameClockPhase phase); +GDK_AVAILABLE_IN_3_8 +void gdk_frame_clock_begin_updating (GdkFrameClock *frame_clock); +GDK_AVAILABLE_IN_3_8 +void gdk_frame_clock_end_updating (GdkFrameClock *frame_clock); + /* Frame history */ GDK_AVAILABLE_IN_3_8 gint64 gdk_frame_clock_get_frame_counter (GdkFrameClock *frame_clock); diff --git a/gdk/gdkframeclockidle.c b/gdk/gdkframeclockidle.c index d07c1d80bb..0db5bfdbc3 100644 --- a/gdk/gdkframeclockidle.c +++ b/gdk/gdkframeclockidle.c @@ -45,6 +45,7 @@ struct _GdkFrameClockIdlePrivate guint flush_idle_id; guint paint_idle_id; guint freeze_count; + guint updating_count; GdkFrameClockPhase requested; GdkFrameClockPhase phase; @@ -192,12 +193,26 @@ gdk_frame_clock_idle_get_frame_time (GdkFrameClock *clock) return priv->frame_time; } +#define RUN_FLUSH_IDLE(priv) \ + ((priv)->freeze_count == 0 && \ + ((priv)->requested & GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS) != 0) + +/* The reason why we track updating_count separately here and don't + * just add GDK_FRAME_CLOCK_PHASE_UPDATE into ->request on every frame + * is so that we can avoid doing one more frame when an animation + * is cancelled. + */ +#define RUN_PAINT_IDLE(priv) \ + ((priv)->freeze_count == 0 && \ + (((priv)->requested & ~GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS) != 0 || \ + (priv)->updating_count > 0)) + static void maybe_start_idle (GdkFrameClockIdle *clock_idle) { GdkFrameClockIdlePrivate *priv = clock_idle->priv; - if (priv->freeze_count == 0 && priv->requested != 0) + if (RUN_FLUSH_IDLE (priv) || RUN_PAINT_IDLE (priv)) { guint min_interval = 0; @@ -208,8 +223,7 @@ maybe_start_idle (GdkFrameClockIdle *clock_idle) min_interval = (min_interval_us + 500) / 1000; } - if (priv->flush_idle_id == 0 && - (priv->requested & GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS) != 0) + if (priv->flush_idle_id == 0 && RUN_FLUSH_IDLE (priv)) { priv->flush_idle_id = gdk_threads_add_timeout_full (GDK_PRIORITY_EVENTS + 1, min_interval, @@ -218,9 +232,7 @@ maybe_start_idle (GdkFrameClockIdle *clock_idle) (GDestroyNotify) g_object_unref); } - if (priv->paint_idle_id == 0 && - !priv->in_paint_idle && - (priv->requested & ~GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS) != 0) + if (priv->paint_idle_id == 0 && RUN_PAINT_IDLE (priv)) { priv->paint_idle_id = gdk_threads_add_timeout_full (GDK_PRIORITY_REDRAW, min_interval, @@ -231,6 +243,24 @@ maybe_start_idle (GdkFrameClockIdle *clock_idle) } } +static void +maybe_stop_idle (GdkFrameClockIdle *clock_idle) +{ + GdkFrameClockIdlePrivate *priv = clock_idle->priv; + + if (priv->flush_idle_id != 0 && !RUN_FLUSH_IDLE (priv)) + { + g_source_remove (priv->flush_idle_id); + priv->flush_idle_id = 0; + } + + if (priv->paint_idle_id != 0 && !RUN_PAINT_IDLE (priv)) + { + g_source_remove (priv->paint_idle_id); + priv->paint_idle_id = 0; + } +} + static gint64 compute_min_next_frame_time (GdkFrameClockIdle *clock_idle, gint64 last_frame_time) @@ -265,7 +295,8 @@ gdk_frame_clock_flush_idle (void *data) g_signal_emit_by_name (G_OBJECT (clock), "flush-events"); - if ((priv->requested & ~GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS) != 0) + if ((priv->requested & ~GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS) != 0 || + priv->updating_count > 0) priv->phase = GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT; else priv->phase = GDK_FRAME_CLOCK_PHASE_NONE; @@ -287,7 +318,8 @@ gdk_frame_clock_paint_idle (void *data) priv->min_next_frame_time = 0; skip_to_resume_events = - (priv->requested & ~(GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS | GDK_FRAME_CLOCK_PHASE_RESUME_EVENTS)) == 0; + (priv->requested & ~(GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS | GDK_FRAME_CLOCK_PHASE_RESUME_EVENTS)) == 0 && + priv->updating_count == 0; if (priv->phase > GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT) { @@ -325,7 +357,8 @@ gdk_frame_clock_paint_idle (void *data) case GDK_FRAME_CLOCK_PHASE_UPDATE: if (priv->freeze_count == 0) { - if (priv->requested & GDK_FRAME_CLOCK_PHASE_UPDATE) + if ((priv->requested & GDK_FRAME_CLOCK_PHASE_UPDATE) != 0 || + priv->updating_count > 0) { priv->requested &= ~GDK_FRAME_CLOCK_PHASE_UPDATE; g_signal_emit_by_name (G_OBJECT (clock), "update"); @@ -436,25 +469,35 @@ gdk_frame_clock_idle_request_phase (GdkFrameClock *clock, } static void +gdk_frame_clock_idle_begin_updating (GdkFrameClock *clock) +{ + GdkFrameClockIdle *clock_idle = GDK_FRAME_CLOCK_IDLE (clock); + GdkFrameClockIdlePrivate *priv = clock_idle->priv; + + priv->updating_count++; + maybe_start_idle (clock_idle); +} + +static void +gdk_frame_clock_idle_end_updating (GdkFrameClock *clock) +{ + GdkFrameClockIdle *clock_idle = GDK_FRAME_CLOCK_IDLE (clock); + GdkFrameClockIdlePrivate *priv = clock_idle->priv; + + g_return_if_fail (priv->updating_count > 0); + + priv->updating_count--; + maybe_stop_idle (clock_idle); +} + +static void gdk_frame_clock_idle_freeze (GdkFrameClock *clock) { - GdkFrameClockIdlePrivate *priv = GDK_FRAME_CLOCK_IDLE (clock)->priv; + GdkFrameClockIdle *clock_idle = GDK_FRAME_CLOCK_IDLE (clock); + GdkFrameClockIdlePrivate *priv = clock_idle->priv; priv->freeze_count++; - - if (priv->freeze_count == 1) - { - if (priv->flush_idle_id) - { - g_source_remove (priv->flush_idle_id); - priv->flush_idle_id = 0; - } - if (priv->paint_idle_id) - { - g_source_remove (priv->paint_idle_id); - priv->paint_idle_id = 0; - } - } + maybe_stop_idle (clock_idle); } static void @@ -489,6 +532,8 @@ gdk_frame_clock_idle_class_init (GdkFrameClockIdleClass *klass) frame_clock_class->get_frame_time = gdk_frame_clock_idle_get_frame_time; frame_clock_class->request_phase = gdk_frame_clock_idle_request_phase; + frame_clock_class->begin_updating = gdk_frame_clock_idle_begin_updating; + frame_clock_class->end_updating = gdk_frame_clock_idle_end_updating; frame_clock_class->freeze = gdk_frame_clock_idle_freeze; frame_clock_class->thaw = gdk_frame_clock_idle_thaw; diff --git a/gdk/gdkframeclockprivate.h b/gdk/gdkframeclockprivate.h index fd505bec6b..27629e38aa 100644 --- a/gdk/gdkframeclockprivate.h +++ b/gdk/gdkframeclockprivate.h @@ -49,6 +49,8 @@ struct _GdkFrameClockClass void (* request_phase) (GdkFrameClock *clock, GdkFrameClockPhase phase); + void (* begin_updating) (GdkFrameClock *clock); + void (* end_updating) (GdkFrameClock *clock); void (* freeze) (GdkFrameClock *clock); void (* thaw) (GdkFrameClock *clock); |