[clutter] timeline: Add a new "stopped" signal



commit de4d70af69a5e33421c468275a3e0e2dc7aaf624
Author: Emmanuele Bassi <ebassi linux intel com>
Date:   Fri May 25 19:41:14 2012 -0400

    timeline: Add a new "stopped" signal
    
    The ::stopped signal is emitted when the timeline has been completely
    exhausted or when the timeline has been programmatically stopped by
    using clutter_timeline_stop(); the notification at the end of the
    timeline run allows to write handlers without having to check whether
    the current repeat is the last one, like we are forced to do when using
    the ::completed signal.
    
    Based on the patch by: Jasper St. Pierre <jstpierre mecheye net>
    
    https://bugzilla.gnome.org/show_bug.cgi?id=676854

 clutter/clutter-actor.c      |   52 +++++++++++++++-----------------------
 clutter/clutter-marshal.list |    1 +
 clutter/clutter-timeline.c   |   56 ++++++++++++++++++++++++++++++++++++++---
 clutter/clutter-timeline.h   |    3 +-
 clutter/clutter-transition.c |   25 +++++++-----------
 examples/basic-actor.c       |    9 +++---
 6 files changed, 90 insertions(+), 56 deletions(-)
---
diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c
index d4b26a1..ca563bd 100644
--- a/clutter/clutter-actor.c
+++ b/clutter/clutter-actor.c
@@ -17272,39 +17272,29 @@ transition_closure_free (gpointer data)
 }
 
 static void
-on_transition_completed (ClutterTransition *transition,
-                         TransitionClosure *clos)
+on_transition_stopped (ClutterTransition *transition,
+                       gboolean           is_finished,
+                       TransitionClosure *clos)
 {
-  ClutterTimeline *timeline = CLUTTER_TIMELINE (transition);
   ClutterActor *actor = clos->actor;
   ClutterAnimationInfo *info;
-  gint n_repeats, cur_repeat;
-
-  info = _clutter_actor_get_animation_info (actor);
 
   /* reset the caches used by animations */
   clutter_actor_store_content_box (actor, NULL);
 
-  /* ensure that we remove the transition only at the end
-   * of its run; we emit ::completed for every repeat
-   */
-  n_repeats = clutter_timeline_get_repeat_count (timeline);
-  cur_repeat = clutter_timeline_get_current_repeat (timeline);
+  if (!is_finished)
+    return;
 
-  if (cur_repeat == n_repeats)
-    {
-      if (clutter_transition_get_remove_on_complete (transition))
-        {
-          /* we take a reference here because removing the closure
-           * will release the reference on the transition, and we
-           * want the transition to survive the signal emission;
-           * the master clock will release the last reference at
-           * the end of the frame processing.
-           */
-          g_object_ref (transition);
-          g_hash_table_remove (info->transitions, clos->name);
-        }
-    }
+  info = _clutter_actor_get_animation_info (actor);
+
+  /* we take a reference here because removing the closure
+   * will release the reference on the transition, and we
+   * want the transition to survive the signal emission;
+   * the master clock will release the last reference at
+   * the end of the frame processing.
+   */
+  g_object_ref (transition);
+  g_hash_table_remove (info->transitions, clos->name);
 
   /* if it's the last transition then we clean up */
   if (g_hash_table_size (info->transitions) == 0)
@@ -17585,8 +17575,8 @@ clutter_actor_add_transition (ClutterActor      *self,
   clos->actor = self;
   clos->transition = g_object_ref (transition);
   clos->name = g_strdup (name);
-  clos->completed_id = g_signal_connect (timeline, "completed",
-                                         G_CALLBACK (on_transition_completed),
+  clos->completed_id = g_signal_connect (timeline, "stopped",
+                                         G_CALLBACK (on_transition_stopped),
                                          clos);
 
   CLUTTER_NOTE (ANIMATION,
@@ -17842,13 +17832,13 @@ clutter_actor_get_easing_delay (ClutterActor *self)
  *   clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
  *
  *   transition = clutter_actor_get_transition (actor, "rotation-angle-y");
- *   g_signal_connect (transition, "completed",
- *                     G_CALLBACK (on_transition_complete),
+ *   g_signal_connect (transition, "stopped",
+ *                     G_CALLBACK (on_transition_stopped),
  *                     actor);
  * ]|
  *
- * will call the <function>on_transition_complete</function> callback when
- * the transition is complete.
+ * will call the <function>on_transition_stopped</function> callback when
+ * the transition is finished.
  *
  * Return value: (transfer none): a #ClutterTransition, or %NULL is none
  *   was found to match the passed name; the returned instance is owned
diff --git a/clutter/clutter-marshal.list b/clutter/clutter-marshal.list
index 509aa0b..34e402f 100644
--- a/clutter/clutter-marshal.list
+++ b/clutter/clutter-marshal.list
@@ -7,6 +7,7 @@ BOOLEAN:OBJECT,FLOAT,FLOAT
 BOXED:UINT,UINT
 DOUBLE:VOID
 UINT:VOID
+VOID:BOOLEAN
 VOID:BOXED
 VOID:BOXED,FLAGS
 VOID:INT
diff --git a/clutter/clutter-timeline.c b/clutter/clutter-timeline.c
index 9cc5212..ae1d3e0 100644
--- a/clutter/clutter-timeline.c
+++ b/clutter/clutter-timeline.c
@@ -187,6 +187,7 @@ enum
   PAUSED,
   COMPLETED,
   MARKER_REACHED,
+  STOPPED,
 
   LAST_SIGNAL
 };
@@ -684,6 +685,10 @@ clutter_timeline_class_init (ClutterTimelineClass *klass)
    *
    * This signal will be emitted even if the #ClutterTimeline is set to be
    * repeating.
+   *
+   * If you want to get notification on whether the #ClutterTimeline has
+   * been stopped or has finished its run, including its eventual repeats,
+   * you should use the #ClutterTimeline::stopped signal instead.
    */
   timeline_signals[COMPLETED] =
     g_signal_new (I_("completed"),
@@ -766,6 +771,33 @@ clutter_timeline_class_init (ClutterTimelineClass *klass)
                   G_TYPE_NONE, 2,
                   G_TYPE_STRING,
                   G_TYPE_INT);
+  /**
+   * ClutterTimeline::stopped:
+   * @timeline: the #ClutterTimeline that emitted the signal
+   * @is_finished: %TRUE if the signal was emitted at the end of the
+   *   timeline.
+   *
+   * The #ClutterTimeline::stopped signal is emitted when the timeline
+   * has been stopped, either because clutter_timeline_stop() has been
+   * called, or because it has been exhausted.
+   *
+   * This is different from the #ClutterTimeline::completed signal,
+   * which gets emitted after every repeat finishes.
+   *
+   * If the #ClutterTimeline has is marked as infinitely repeating,
+   * this signal will never be emitted.
+   *
+   * Since: 1.12
+   */
+  timeline_signals[STOPPED] =
+    g_signal_new (I_("stopped"),
+		  G_TYPE_FROM_CLASS (object_class),
+		  G_SIGNAL_RUN_LAST,
+		  G_STRUCT_OFFSET (ClutterTimelineClass, completed),
+		  NULL, NULL,
+		  _clutter_marshal_VOID__BOOLEAN,
+		  G_TYPE_NONE, 1,
+                  G_TYPE_BOOLEAN);
 }
 
 static void
@@ -897,12 +929,13 @@ set_is_playing (ClutterTimeline *timeline,
   ClutterTimelinePrivate *priv = timeline->priv;
   ClutterMasterClock *master_clock;
 
-  is_playing = is_playing != FALSE;
+  is_playing = !!is_playing;
 
   if (is_playing == priv->is_playing)
     return;
 
   priv->is_playing = is_playing;
+
   master_clock = _clutter_master_clock_get_default ();
   if (priv->is_playing)
     {
@@ -911,9 +944,7 @@ set_is_playing (ClutterTimeline *timeline,
       priv->current_repeat = 0;
     }
   else
-    {
-      _clutter_master_clock_remove_timeline (master_clock, timeline);
-    }
+    _clutter_master_clock_remove_timeline (master_clock, timeline);
 }
 
 static gboolean
@@ -1002,7 +1033,8 @@ clutter_timeline_do_frame (ClutterTimeline *timeline)
            * priv->repeat_count. Are we limiting the things that could be
            * done in the above new-frame signal handler?
            */
-	  set_is_playing (timeline, FALSE);
+          set_is_playing (timeline, FALSE);
+          g_signal_emit (timeline, timeline_signals[STOPPED], 0, TRUE);
         }
 
       g_signal_emit (timeline, timeline_signals[COMPLETED], 0);
@@ -1156,8 +1188,22 @@ clutter_timeline_pause (ClutterTimeline *timeline)
 void
 clutter_timeline_stop (ClutterTimeline *timeline)
 {
+  gboolean was_playing;
+
+  g_return_if_fail (CLUTTER_IS_TIMELINE (timeline));
+
+  /* we check the is_playing here because pause() will return immediately
+   * if the timeline wasn't playing, so we don't know if it was actually
+   * stopped, and yet we still don't want to emit a ::stopped signal if
+   * the timeline was not playing in the first place.
+   */
+  was_playing = timeline->priv->is_playing;
+
   clutter_timeline_pause (timeline);
   clutter_timeline_rewind (timeline);
+
+  if (was_playing)
+    g_signal_emit (timeline, timeline_signals[STOPPED], 0, FALSE);
 }
 
 /**
diff --git a/clutter/clutter-timeline.h b/clutter/clutter-timeline.h
index 488b4af..f7e2463 100644
--- a/clutter/clutter-timeline.h
+++ b/clutter/clutter-timeline.h
@@ -104,13 +104,14 @@ struct _ClutterTimelineClass
   void (*marker_reached) (ClutterTimeline *timeline,
                           const gchar     *marker_name,
                           gint             msecs);
+  void (*stopped)        (ClutterTimeline *timeline,
+                          gboolean         is_finished);
 
   /*< private >*/
   void (*_clutter_timeline_1) (void);
   void (*_clutter_timeline_2) (void);
   void (*_clutter_timeline_3) (void);
   void (*_clutter_timeline_4) (void);
-  void (*_clutter_timeline_5) (void);
 };
 
 GType clutter_timeline_get_type (void) G_GNUC_CONST;
diff --git a/clutter/clutter-transition.c b/clutter/clutter-transition.c
index a38f298..576d6b2 100644
--- a/clutter/clutter-transition.c
+++ b/clutter/clutter-transition.c
@@ -124,24 +124,19 @@ clutter_transition_new_frame (ClutterTimeline *timeline,
 }
 
 static void
-clutter_transition_completed (ClutterTimeline *timeline)
+clutter_transition_stopped (ClutterTimeline *timeline,
+                            gboolean         is_finished)
 {
   ClutterTransitionPrivate *priv = CLUTTER_TRANSITION (timeline)->priv;
 
-  if (priv->animatable != NULL && priv->remove_on_complete)
+  if (is_finished &&
+      priv->animatable != NULL &&
+      priv->remove_on_complete)
     {
-      int n_repeats, cur_repeat;
-
-      n_repeats = clutter_timeline_get_repeat_count (timeline);
-      cur_repeat = clutter_timeline_get_current_repeat (timeline);
-
-      if (n_repeats == 0 || cur_repeat == n_repeats)
-        {
-          clutter_transition_detach (CLUTTER_TRANSITION (timeline),
-                                     priv->animatable);
-          g_clear_object (&priv->animatable);
-          g_object_unref (timeline);
-        }
+      clutter_transition_detach (CLUTTER_TRANSITION (timeline),
+                                 priv->animatable);
+      g_clear_object (&priv->animatable);
+      g_object_unref (timeline);
     }
 }
 
@@ -232,7 +227,7 @@ clutter_transition_class_init (ClutterTransitionClass *klass)
   klass->detached = clutter_transition_real_detached;
 
   timeline_class->new_frame = clutter_transition_new_frame;
-  timeline_class->completed = clutter_transition_completed;
+  timeline_class->stopped = clutter_transition_stopped;
 
   gobject_class->set_property = clutter_transition_set_property;
   gobject_class->get_property = clutter_transition_get_property;
diff --git a/examples/basic-actor.c b/examples/basic-actor.c
index 5778223..384b196 100644
--- a/examples/basic-actor.c
+++ b/examples/basic-actor.c
@@ -49,8 +49,9 @@ on_crossing (ClutterActor *actor,
 }
 
 static void
-on_transition_complete (ClutterTransition *transition,
-                        ClutterActor      *actor)
+on_transition_stopped (ClutterTransition *transition,
+                       gboolean           is_finished,
+                       ClutterActor      *actor)
 {
   clutter_actor_save_easing_state (actor);
   clutter_actor_set_easing_duration (actor, 250);
@@ -74,8 +75,8 @@ animate_rotation (ClutterActor *actor,
                               SIZE / 2.0f, 0.f, 0.f);
 
   transition = clutter_actor_get_transition (actor, "rotation-angle-y");
-  g_signal_connect (transition, "completed",
-                    G_CALLBACK (on_transition_complete),
+  g_signal_connect (transition, "stopped",
+                    G_CALLBACK (on_transition_stopped),
                     actor);
 
   clutter_actor_restore_easing_state (actor);



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