summaryrefslogtreecommitdiff
path: root/gdk
diff options
context:
space:
mode:
Diffstat (limited to 'gdk')
-rw-r--r--gdk/gdk.symbols2
-rw-r--r--gdk/gdkframeclock.c44
-rw-r--r--gdk/gdkframeclock.h5
-rw-r--r--gdk/gdkframeclockidle.c93
-rw-r--r--gdk/gdkframeclockprivate.h2
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);