From 9097c5e9c016d0d247e93b1fffd27fe844538607 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Fri, 2 Aug 2019 16:58:39 +0200 Subject: [PATCH] st: Add transition API to StAdjustment StAdjustment implements the ClutterAnimatable interface, so we can already animate its properties with ClutterPropertyTransitions. But as it is currently not possible to associate a transition with an adjustment, it must be owned (and kept alive in case of GC) by the calling code. Change that by implementing the same (add|remove|get)_transition() API as ClutterActor, so we can use a familiar API and even duck typing in case of javascript. https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/669 --- src/st/st-adjustment.c | 164 +++++++++++++++++++++++++++++++++++++++++ src/st/st-adjustment.h | 8 ++ 2 files changed, 172 insertions(+) diff --git a/src/st/st-adjustment.c b/src/st/st-adjustment.c index b705e6e6c..890c69903 100644 --- a/src/st/st-adjustment.c +++ b/src/st/st-adjustment.c @@ -45,6 +45,8 @@ struct _StAdjustmentPrivate * not all properties may be set yet. */ guint is_constructing : 1; + GHashTable *transitions; + gdouble lower; gdouble upper; gdouble value; @@ -85,6 +87,14 @@ enum static guint signals[LAST_SIGNAL] = { 0, }; +typedef struct _TransitionClosure +{ + StAdjustment *adjustment; + ClutterTransition *transition; + char *name; + gulong completed_id; +} TransitionClosure; + static gboolean st_adjustment_set_lower (StAdjustment *adjustment, gdouble lower); static gboolean st_adjustment_set_upper (StAdjustment *adjustment, @@ -201,6 +211,17 @@ st_adjustment_set_property (GObject *gobject, } } +static void +st_adjustment_dispose (GObject *object) +{ + StAdjustmentPrivate *priv; + + priv = st_adjustment_get_instance_private (ST_ADJUSTMENT (object)); + g_clear_pointer (&priv->transitions, g_hash_table_unref); + + G_OBJECT_CLASS (st_adjustment_parent_class)->dispose (object); +} + static void st_adjustment_class_init (StAdjustmentClass *klass) { @@ -209,6 +230,7 @@ st_adjustment_class_init (StAdjustmentClass *klass) object_class->constructed = st_adjustment_constructed; object_class->get_property = st_adjustment_get_property; object_class->set_property = st_adjustment_set_property; + object_class->dispose = st_adjustment_dispose; props[PROP_LOWER] = g_param_spec_double ("lower", "Lower", "Lower bound", @@ -588,3 +610,145 @@ st_adjustment_adjust_for_scroll_event (StAdjustment *adjustment, new_value = priv->value + delta * scroll_unit; st_adjustment_set_value (adjustment, new_value); } + +static void +transition_closure_free (gpointer data) +{ + TransitionClosure *clos; + ClutterTimeline *timeline; + + if (G_UNLIKELY (data == NULL)) + return; + + clos = data; + timeline = CLUTTER_TIMELINE (clos->transition); + + g_signal_handler_disconnect (clos->transition, clos->completed_id); + + if (clutter_timeline_is_playing (timeline)) + clutter_timeline_stop (timeline); + + g_object_unref (clos->transition); + g_free (clos->name); + g_free (clos); +} + +static void +remove_transition (StAdjustment *adjustment, + const char *name) +{ + StAdjustmentPrivate *priv = st_adjustment_get_instance_private (adjustment); + + g_hash_table_remove (priv->transitions, name); + + if (g_hash_table_size (priv->transitions) == 0) + g_clear_pointer (&priv->transitions, g_hash_table_unref); +} + +static void +on_transition_stopped (ClutterTransition *transition, + gboolean is_finished, + TransitionClosure *clos) +{ + StAdjustment *adjustment = clos->adjustment; + + if (!clutter_transition_get_remove_on_complete (transition)) + return; + + /* Take a reference, because removing the closure will + * release the reference on the transition, and we want + * it to survive the signal emission; ClutterTransition's + * own ::stopped signal closure will release it after all + * other handlers have run. + */ + g_object_ref (transition); + + remove_transition (adjustment, clos->name); +} + +/** + * st_adjustment_get_transition: + * Returns: (transfer none) (nullable): + */ +ClutterTransition * +st_adjustment_get_transition (StAdjustment *adjustment, + const char *name) +{ + StAdjustmentPrivate *priv; + TransitionClosure *clos; + + g_return_val_if_fail (ST_IS_ADJUSTMENT (adjustment), NULL); + + priv = st_adjustment_get_instance_private (adjustment); + + if (priv->transitions == NULL) + return NULL; + + clos = g_hash_table_lookup (priv->transitions, name); + if (clos == NULL) + return NULL; + + return clos->transition; +} + +void +st_adjustment_add_transition (StAdjustment *adjustment, + const char *name, + ClutterTransition *transition) +{ + StAdjustmentPrivate *priv; + TransitionClosure *clos; + + g_return_if_fail (ST_IS_ADJUSTMENT (adjustment)); + g_return_if_fail (name != NULL); + g_return_if_fail (CLUTTER_IS_TRANSITION (transition)); + + priv = st_adjustment_get_instance_private (adjustment); + + if (priv->transitions == NULL) + priv->transitions = g_hash_table_new_full (g_str_hash, g_str_equal, + NULL, + transition_closure_free); + + if (g_hash_table_lookup (priv->transitions, name) != NULL) + { + g_warning ("A transition with name '%s' already exists for " + "adjustment '%p'", name, adjustment); + return; + } + + clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (adjustment)); + + clos = g_new (TransitionClosure, 1); + clos->adjustment = adjustment; + clos->transition = g_object_ref (transition); + clos->name = g_strdup (name); + clos->completed_id = g_signal_connect (transition, "stopped", + G_CALLBACK (on_transition_stopped), + clos); + + g_hash_table_insert (priv->transitions, clos->name, clos); + clutter_timeline_start (CLUTTER_TIMELINE (transition)); +} + +void +st_adjustment_remove_transition (StAdjustment *adjustment, + const char *name) +{ + StAdjustmentPrivate *priv; + TransitionClosure *clos; + + g_return_if_fail (ST_IS_ADJUSTMENT (adjustment)); + g_return_if_fail (name != NULL); + + priv = st_adjustment_get_instance_private (adjustment); + + if (priv->transitions == NULL) + return; + + clos = g_hash_table_lookup (priv->transitions, name); + if (clos == NULL) + return; + + remove_transition (adjustment, name); +} diff --git a/src/st/st-adjustment.h b/src/st/st-adjustment.h index 529d8628e..302755a09 100644 --- a/src/st/st-adjustment.h +++ b/src/st/st-adjustment.h @@ -78,6 +78,14 @@ void st_adjustment_get_values (StAdjustment *adjustment, void st_adjustment_adjust_for_scroll_event (StAdjustment *adjustment, gdouble delta); +ClutterTransition * st_adjustment_get_transition (StAdjustment *adjustment, + const char *name); +void st_adjustment_add_transition (StAdjustment *adjustment, + const char *name, + ClutterTransition *transition); +void st_adjustment_remove_transition (StAdjustment *adjustment, + const char *name); + G_END_DECLS #endif /* __ST_ADJUSTMENT_H__ */