]> Pileus Git - ~andy/gtk/commitdiff
Add gdk_frame_clock_begin/end_updating()
authorOwen W. Taylor <otaylor@fishsoup.net>
Fri, 15 Feb 2013 22:04:39 +0000 (17:04 -0500)
committerAlexander Larsson <alexl@redhat.com>
Mon, 18 Feb 2013 16:14:24 +0000 (17:14 +0100)
Add an API to start or stop continually updating the frame clock.
This is a slight convenience for applcations and avoids the problem
of getting one more frame run after an animation stops, but the
primary motivation for this is because it looks like we might have
to use timeBeginPeriod()/timeEndPeriod() on Windows to get reasonably
accurate timing, and for that we'll need to know if there is an
animation running.

https://bugzilla.gnome.org/show_bug.cgi?id=693934

gdk/gdk.symbols
gdk/gdkframeclock.c
gdk/gdkframeclock.h
gdk/gdkframeclockidle.c
gdk/gdkframeclockprivate.h
gtk/gtkstylecontext.c
gtk/gtkwidget.c
tests/video-timer.c

index b01f3e5191acafa0552f33c5cd49f0d24b20d9f9..1f99c6406c973c20c1151bc0e82616ea0d36f53b 100644 (file)
@@ -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
index 4d1c7658b9e5af91bba0f5fd8ffbddb09f30c323..1994b00e8ba3e6c0d4982a971e27f2add69a88c3 100644 (file)
@@ -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)
index f6529795afa51465645757c4e4b2235171662d9a..a82d5cf59429366960589fd01929b101dce486ef 100644 (file)
@@ -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);
index d07c1d80bb7d4e3f1297759c5b110e7e538453c7..0db5bfdbc3af5c5f54859a2d41098204770d9dc2 100644 (file)
@@ -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");
@@ -435,26 +468,36 @@ gdk_frame_clock_idle_request_phase (GdkFrameClock      *clock,
   maybe_start_idle (clock_idle);
 }
 
+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;
 
index fd505bec6b179671f27a4617963fe00772d6871f..27629e38aaf42daf8e251dbdbf507c107f460590 100644 (file)
@@ -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);
index 7fa5ee7ba18c6affcff692cff228819bbf18e886..f5d1e86ea5a888f1a11729c50a188ad0b805d756 100644 (file)
@@ -739,9 +739,6 @@ gtk_style_context_update (GdkFrameClock  *clock,
                           GtkStyleContext *context)
 {
   _gtk_style_context_queue_invalidate (context, GTK_CSS_CHANGE_ANIMATE);
-
-  /* A little blech to request one more than we need */
-  gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_UPDATE);
 }
 
 static gboolean
@@ -762,6 +759,7 @@ gtk_style_context_disconnect_update (GtkStyleContext *context)
       g_signal_handler_disconnect (priv->frame_clock,
                                    priv->frame_clock_update_id);
       priv->frame_clock_update_id = 0;
+      gdk_frame_clock_end_updating (priv->frame_clock);
     }
 }
 
@@ -776,7 +774,7 @@ gtk_style_context_connect_update (GtkStyleContext *context)
                                                       "update",
                                                       G_CALLBACK (gtk_style_context_update),
                                                       context);
-      gdk_frame_clock_request_phase (priv->frame_clock, GDK_FRAME_CLOCK_PHASE_UPDATE);
+      gdk_frame_clock_begin_updating (priv->frame_clock);
     }
 }
 
index 231d27b7738b75f3edcf44b28a5ef9db820f80c8..8a7fb18f699bbc7ae6af282aa8c10b3bf5c45906 100644 (file)
@@ -4554,6 +4554,7 @@ unref_tick_callback_info (GtkWidget           *widget,
       g_signal_handlers_disconnect_by_func (frame_clock,
                                             (gpointer) gtk_widget_on_frame_clock_update,
                                             widget);
+      gdk_frame_clock_end_updating (frame_clock);
     }
 }
 
@@ -4596,10 +4597,6 @@ gtk_widget_on_frame_clock_update (GdkFrameClock *frame_clock,
       unref_tick_callback_info (widget, info, l);
       l = next;
     }
-
-  if (priv->tick_callbacks != NULL)
-    gdk_frame_clock_request_phase (frame_clock,
-                                   GDK_FRAME_CLOCK_PHASE_UPDATE);
 }
 
 static guint tick_callback_id;
@@ -4651,8 +4648,7 @@ gtk_widget_add_tick_callback (GtkWidget       *widget,
       g_signal_connect (frame_clock, "update",
                         G_CALLBACK (gtk_widget_on_frame_clock_update),
                         widget);
-      gdk_frame_clock_request_phase (frame_clock,
-                                     GDK_FRAME_CLOCK_PHASE_UPDATE);
+      gdk_frame_clock_begin_updating (frame_clock);
     }
 
   info = g_slice_new0 (GtkTickCallbackInfo);
@@ -4702,8 +4698,7 @@ gtk_widget_connect_frame_clock (GtkWidget     *widget,
       g_signal_connect (frame_clock, "update",
                         G_CALLBACK (gtk_widget_on_frame_clock_update),
                         widget);
-      gdk_frame_clock_request_phase (frame_clock,
-                                     GDK_FRAME_CLOCK_PHASE_UPDATE);
+      gdk_frame_clock_begin_updating (frame_clock);
     }
 
   if (priv->context)
@@ -4720,9 +4715,12 @@ gtk_widget_disconnect_frame_clock (GtkWidget     *widget,
     _gtk_container_stop_idle_sizer (GTK_CONTAINER (widget));
 
   if (priv->tick_callbacks)
-    g_signal_handlers_disconnect_by_func (frame_clock,
-                                          (gpointer) gtk_widget_on_frame_clock_update,
-                                          widget);
+    {
+      g_signal_handlers_disconnect_by_func (frame_clock,
+                                            (gpointer) gtk_widget_on_frame_clock_update,
+                                            widget);
+      gdk_frame_clock_end_updating (frame_clock);
+    }
 
   if (priv->context)
     gtk_style_context_set_frame_clock (priv->context, NULL);
index 1ddc260267c7ef4c2d9c0c7c38ccbef495dddf9a..f85824004973f7899146442ec3ab84b149b452c5 100644 (file)
@@ -350,8 +350,6 @@ on_update (GdkFrameClock *frame_clock,
 
       gtk_widget_queue_draw (window);
     }
-
-  gdk_frame_clock_request_phase (frame_clock, GDK_FRAME_CLOCK_PHASE_UPDATE);
 }
 
 static GOptionEntry options[] = {
@@ -393,7 +391,7 @@ main(int argc, char **argv)
   frame_clock = gtk_widget_get_frame_clock (window);
   g_signal_connect (frame_clock, "update",
                     G_CALLBACK (on_update), NULL);
-  gdk_frame_clock_request_phase (frame_clock, GDK_FRAME_CLOCK_PHASE_UPDATE);
+  gdk_frame_clock_begin_updating (frame_clock);
 
   gtk_main ();