[mutter] clutter/timeline: Wait for stage if no frame clock is available



commit 5b0a7b3a33b13765c3834103084f1f0c025e26a9
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Wed Jul 1 13:09:27 2020 -0300

    clutter/timeline: Wait for stage if no frame clock is available
    
    When picking which frame clock to use, we traverse up in the actor
    hierarchy until a suitable frame clock is found. ClutterTimeline
    also listens to the 'stage-views-changed' to make sure it's always
    attached to the correct frame clock.
    
    However, there is one special situation where neither of them would
    work: when the stage doesn't have a frame clock yet, and the actor
    of the timeline is outside any stage view. When that happens, the
    returned frame clock is NULL, and 'stage-views-changed' is never
    emitted by the actor.
    
    Monitor the stage for stage view changes when the frame clock is
    NULL.
    
    https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1285

 clutter/clutter/clutter-timeline.c | 53 ++++++++++++++++++++++++++++++++++----
 1 file changed, 48 insertions(+), 5 deletions(-)
---
diff --git a/clutter/clutter/clutter-timeline.c b/clutter/clutter/clutter-timeline.c
index 25d9aad95c..bc29f8e24c 100644
--- a/clutter/clutter/clutter-timeline.c
+++ b/clutter/clutter/clutter-timeline.c
@@ -117,6 +117,8 @@ struct _ClutterTimelinePrivate
   ClutterActor *actor;
   gulong actor_destroy_handler_id;
   gulong actor_stage_views_handler_id;
+  gulong stage_stage_views_handler_id;
+  ClutterActor *stage;
 
   guint delay_id;
 
@@ -207,6 +209,8 @@ enum
 
 static guint timeline_signals[LAST_SIGNAL] = { 0, };
 
+static void update_frame_clock (ClutterTimeline *timeline);
+
 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
 
 G_DEFINE_TYPE_WITH_CODE (ClutterTimeline, clutter_timeline, G_TYPE_OBJECT,
@@ -366,17 +370,53 @@ set_frame_clock_internal (ClutterTimeline   *timeline,
     maybe_add_timeline (timeline);
 }
 
+static void
+on_stage_stage_views_changed (ClutterActor    *stage,
+                              ClutterTimeline *timeline)
+{
+  ClutterTimelinePrivate *priv = timeline->priv;
+
+  g_clear_signal_handler (&priv->stage_stage_views_handler_id, priv->stage);
+  priv->stage = NULL;
+
+  update_frame_clock (timeline);
+}
+
 static void
 update_frame_clock (ClutterTimeline *timeline)
 {
   ClutterTimelinePrivate *priv = timeline->priv;
-  ClutterFrameClock *frame_clock;
+  ClutterFrameClock *frame_clock = NULL;
+  ClutterActor *stage;
 
-  if (priv->actor)
-    frame_clock = clutter_actor_pick_frame_clock (priv->actor);
-  else
-    frame_clock = NULL;
+  if (!priv->actor)
+    goto out;
+
+  frame_clock = clutter_actor_pick_frame_clock (priv->actor);
+  if (frame_clock)
+    {
+      g_clear_signal_handler (&priv->stage_stage_views_handler_id, priv->stage);
+      goto out;
+    }
+
+  stage = clutter_actor_get_stage (priv->actor);
+  if (!stage)
+    {
+      if (priv->is_playing)
+        g_warning ("Timelines with detached actors are not supported");
+      goto out;
+    }
+
+  if (priv->stage_stage_views_handler_id > 0)
+    goto out;
+
+  priv->stage_stage_views_handler_id =
+    g_signal_connect (stage, "stage-views-changed",
+                      G_CALLBACK (on_stage_stage_views_changed),
+                      timeline);
+  priv->stage = stage;
 
+out:
   set_frame_clock_internal (timeline, frame_clock);
 }
 
@@ -406,6 +446,8 @@ clutter_timeline_set_actor (ClutterTimeline *timeline,
     {
       g_clear_signal_handler (&priv->actor_destroy_handler_id, priv->actor);
       g_clear_signal_handler (&priv->actor_stage_views_handler_id, priv->actor);
+      g_clear_signal_handler (&priv->stage_stage_views_handler_id, priv->stage);
+      priv->stage = NULL;
       priv->actor = NULL;
 
       if (priv->is_playing)
@@ -690,6 +732,7 @@ clutter_timeline_dispose (GObject *object)
     {
       g_clear_signal_handler (&priv->actor_destroy_handler_id, priv->actor);
       g_clear_signal_handler (&priv->actor_stage_views_handler_id, priv->actor);
+      g_clear_signal_handler (&priv->stage_stage_views_handler_id, priv->stage);
       priv->actor = NULL;
     }
 


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