}
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)
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,
* 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
BOXED:UINT,UINT
DOUBLE:VOID
UINT:VOID
+VOID:BOOLEAN
VOID:BOXED
VOID:BOXED,FLAGS
VOID:INT
PAUSED,
COMPLETED,
MARKER_REACHED,
+ STOPPED,
LAST_SIGNAL
};
*
* 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"),
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
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)
{
priv->current_repeat = 0;
}
else
- {
- _clutter_master_clock_remove_timeline (master_clock, timeline);
- }
+ _clutter_master_clock_remove_timeline (master_clock, timeline);
}
static gboolean
* 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);
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);
}
/**
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;
}
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);
}
}
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;
}
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);
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);