[gnome-shell] st: Add transition API to StAdjustment



commit 9097c5e9c016d0d247e93b1fffd27fe844538607
Author: Florian Müllner <fmuellner gnome org>
Date:   Fri Aug 2 16:58:39 2019 +0200

    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__ */


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