From 28c2eeef951207f73f5c2584b3a471271ccdbdcf Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Sat, 21 Jul 2012 12:49:53 -0400 Subject: [PATCH] actor: Add ::transition-stopped The ::transition-stopped signal can be used to get notification of the end of a transition. --- clutter/clutter-actor.c | 97 +++++++++++++++++++++++++++++++----- clutter/clutter-marshal.list | 1 + examples/basic-actor.c | 27 +++++----- 3 files changed, 99 insertions(+), 26 deletions(-) diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index 4699340f3..e13530458 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -964,6 +964,7 @@ enum ALLOCATION_CHANGED, TRANSITIONS_COMPLETED, TOUCH_EVENT, + TRANSITION_STOPPED, LAST_SIGNAL }; @@ -4449,8 +4450,6 @@ clutter_actor_set_rotation_angle (ClutterActor *self, _clutter_actor_create_transition (self, pspec, *cur_angle_p, angle); else _clutter_actor_update_transition (self, pspec, angle); - - clutter_actor_queue_redraw (self); } /** @@ -8014,6 +8013,32 @@ clutter_actor_class_init (ClutterActorClass *klass) _clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); + /** + * ClutterActor::transition-stopped: + * @actor: a #ClutterActor + * @name: the name of the transition + * @is_finished: whether the transition was finished, or stopped + * + * The ::transition-stopped signal is emitted once a transition + * is stopped; a transition is stopped once it reached its total + * duration (including eventual repeats), it has been stopped + * using clutter_timeline_stop(), or it has been removed from the + * transitions applied on @actor, using clutter_actor_remove_transition(). + * + * Since: 1.12 + */ + actor_signals[TRANSITION_STOPPED] = + g_signal_new (I_("transition-stopped"), + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | + G_SIGNAL_NO_HOOKS | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + _clutter_marshal_VOID__STRING_BOOLEAN, + G_TYPE_NONE, 2, + G_TYPE_STRING, + G_TYPE_BOOLEAN); + /** * ClutterActor::touch-event: * @actor: a #ClutterActor @@ -18350,6 +18375,11 @@ on_transition_stopped (ClutterTransition *transition, { ClutterActor *actor = clos->actor; ClutterAnimationInfo *info; + GQuark t_quark; + gchar *t_name; + + if (clos->name == NULL) + return; /* reset the caches used by animations */ clutter_actor_store_content_box (actor, NULL); @@ -18359,6 +18389,9 @@ on_transition_stopped (ClutterTransition *transition, info = _clutter_actor_get_animation_info (actor); + t_quark = g_quark_from_string (clos->name); + t_name = g_strdup (clos->name); + /* 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; @@ -18368,6 +18401,16 @@ on_transition_stopped (ClutterTransition *transition, g_object_ref (transition); g_hash_table_remove (info->transitions, clos->name); + /* we emit the ::transition-stopped after removing the + * transition, so that we can chain up new transitions + * without interfering with the one that just finished + */ + g_signal_emit (actor, actor_signals[TRANSITION_STOPPED], t_quark, + t_name, + TRUE); + + g_free (t_name); + /* if it's the last transition then we clean up */ if (g_hash_table_size (info->transitions) == 0) { @@ -18481,6 +18524,9 @@ _clutter_actor_create_transition (ClutterActor *actor, TransitionClosure *clos; va_list var_args; + g_assert (pspec != NULL); + g_assert ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0); + info = _clutter_actor_get_animation_info (actor); /* XXX - this will go away in 2.0 @@ -18559,9 +18605,6 @@ _clutter_actor_create_transition (ClutterActor *actor, interval = clutter_interval_new_with_values (ptype, &initial, &final); - g_value_unset (&initial); - g_value_unset (&final); - res = clutter_property_transition_new (pspec->name); clutter_transition_set_interval (res, interval); @@ -18572,22 +18615,45 @@ _clutter_actor_create_transition (ClutterActor *actor, clutter_timeline_set_duration (timeline, info->cur_state->easing_duration); clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode); - CLUTTER_NOTE (ANIMATION, - "Created transition for %s:%s (len:%u, mode:%s, delay:%u)", - _clutter_actor_get_debug_name (actor), - pspec->name, - info->cur_state->easing_duration, - clutter_get_easing_name_for_mode (info->cur_state->easing_mode), - info->cur_state->easing_delay); +#ifdef CLUTTER_ENABLE_DEBUG + { + gchar *initial_v, *final_v; + + initial_v = g_strdup_value_contents (&initial); + final_v = g_strdup_value_contents (&final); + + CLUTTER_NOTE (ANIMATION, + "Created transition for %s:%s " + "(len:%u, mode:%s, delay:%u) " + "initial:%s, final:%s", + _clutter_actor_get_debug_name (actor), + pspec->name, + info->cur_state->easing_duration, + clutter_get_easing_name_for_mode (info->cur_state->easing_mode), + info->cur_state->easing_delay, + initial_v, final_v); + + g_free (initial_v); + g_free (final_v); + } +#endif /* CLUTTER_ENABLE_DEBUG */ /* this will start the transition as well */ clutter_actor_add_transition (actor, pspec->name, res); /* the actor now owns the transition */ g_object_unref (res); + + g_value_unset (&initial); + g_value_unset (&final); } else - res = clos->transition; + { + CLUTTER_NOTE (ANIMATION, "Existing transition for %s:%s", + _clutter_actor_get_debug_name (actor), + pspec->name); + res = clos->transition; + } out: if (call_restore) @@ -18698,6 +18764,11 @@ clutter_actor_remove_transition (ClutterActor *self, if (info->transitions == NULL) return; + g_signal_emit (self, actor_signals[TRANSITION_STOPPED], + g_quark_from_string (name), + name, + FALSE); + g_hash_table_remove (info->transitions, name); } diff --git a/clutter/clutter-marshal.list b/clutter/clutter-marshal.list index 557bf2aba..efe8fb509 100644 --- a/clutter/clutter-marshal.list +++ b/clutter/clutter-marshal.list @@ -24,6 +24,7 @@ VOID:OBJECT,PARAM VOID:OBJECT,POINTER VOID:OBJECT,UINT VOID:POINTER +VOID:STRING,BOOLEAN VOID:STRING,BOOLEAN,BOOLEAN VOID:STRING,INT VOID:UINT diff --git a/examples/basic-actor.c b/examples/basic-actor.c index 0ce396717..1bfb42750 100644 --- a/examples/basic-actor.c +++ b/examples/basic-actor.c @@ -49,36 +49,37 @@ on_crossing (ClutterActor *actor, } static void -on_transition_stopped (ClutterTransition *transition, - gboolean is_finished, - ClutterActor *actor) +on_transition_stopped (ClutterActor *actor, + const gchar *transition_name, + gboolean is_finished) { clutter_actor_save_easing_state (actor); - clutter_actor_set_easing_duration (actor, 250); - clutter_actor_set_rotation_angle (actor, CLUTTER_Y_AXIS, 0.0f); - clutter_actor_restore_easing_state (actor); + + /* disconnect so we don't get multiple notifications */ + g_signal_handlers_disconnect_by_func (actor, + on_transition_stopped, + NULL); } static gboolean animate_rotation (ClutterActor *actor, ClutterEvent *event) { - ClutterTransition *transition; - clutter_actor_save_easing_state (actor); clutter_actor_set_easing_duration (actor, 1000); clutter_actor_set_rotation_angle (actor, CLUTTER_Y_AXIS, 360.0); - transition = clutter_actor_get_transition (actor, "rotation-angle-y"); - g_signal_connect (transition, "stopped", - G_CALLBACK (on_transition_stopped), - actor); - clutter_actor_restore_easing_state (actor); + /* get a notification when the rotation-angle-y transition ends */ + g_signal_connect (actor, + "transition-stopped::rotation-angle-y", + G_CALLBACK (on_transition_stopped), + NULL); + return CLUTTER_EVENT_STOP; }