[mutter] clutter/actor: Emit a signal when the stage-views an actor is on change



commit 18c792d6f8a15bfd36edfb9751c63556190eeded
Author: Jonas Dreßler <verdre v0yd nl>
Date:   Fri Apr 10 00:59:05 2020 +0200

    clutter/actor: Emit a signal when the stage-views an actor is on change
    
    Add a new signal that's emitted when the stage views an actor being
    painted on have changed, "stage-views-changed". For example this signal
    can be helpful when tracking whether an actor is painted on multiple
    stage views or only one.
    
    Since we must clear the stage-views list when an actor leaves the stage
    (actors that aren't attached to a stage don't get notified about the
    stage views being changed/replaced), we also emit the new signal when an
    actor gets detached from the stage (otherwise there would be an edge
    case where no signal is emitted but it really should: An actor is
    visible on a stage view, then detached from the stage, and then attached
    again and immeditely moved outside the view).
    
    Also skip the comparison of the old stage-views list and the new one if
    nobody is listening to the signal to save some resources.
    
    https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1196

 clutter/clutter/clutter-actor.c | 69 ++++++++++++++++++++++++++++++++++++++---
 1 file changed, 64 insertions(+), 5 deletions(-)
---
diff --git a/clutter/clutter/clutter-actor.c b/clutter/clutter/clutter-actor.c
index 1d3f98d415..dd7b1ba740 100644
--- a/clutter/clutter/clutter-actor.c
+++ b/clutter/clutter/clutter-actor.c
@@ -1020,6 +1020,7 @@ enum
   TRANSITIONS_COMPLETED,
   TOUCH_EVENT,
   TRANSITION_STOPPED,
+  STAGE_VIEWS_CHANGED,
 
   LAST_SIGNAL
 };
@@ -4421,7 +4422,7 @@ clutter_actor_remove_child_internal (ClutterActor                 *self,
    * to the stage views, so make sure all the stage-views lists are
    * cleared as the child and its children leave the actor tree.
    */
-  if (clear_stage_views)
+  if (clear_stage_views && !CLUTTER_ACTOR_IN_DESTRUCTION (child))
     clutter_actor_clear_stage_views_recursive (child);
 
   if (emit_parent_set && !CLUTTER_ACTOR_IN_DESTRUCTION (child))
@@ -8634,6 +8635,27 @@ clutter_actor_class_init (ClutterActorClass *klass)
   g_signal_set_va_marshaller (actor_signals[TOUCH_EVENT],
                               G_TYPE_FROM_CLASS (object_class),
                               _clutter_marshal_BOOLEAN__BOXEDv);
+
+  /**
+   * ClutterActor::stage-views-changed:
+   * @actor: a #ClutterActor
+   *
+   * The ::stage-views-changed signal is emitted when the position or
+   * size an actor is being painted at have changed so that it's visible
+   * on different stage views.
+   *
+   * This signal is also emitted when the actor gets detached from the stage
+   * or when the views of the stage have been invalidated and will be
+   * replaced; it's not emitted when the actor gets hidden.
+   */
+  actor_signals[STAGE_VIEWS_CHANGED] =
+    g_signal_new (I_("stage-views-changed"),
+                  G_TYPE_FROM_CLASS (object_class),
+                  G_SIGNAL_RUN_LAST,
+                  0,
+                  NULL, NULL, NULL,
+                  G_TYPE_NONE, 0);
+
 }
 
 static void
@@ -17540,10 +17562,15 @@ clear_stage_views_cb (ClutterActor *actor,
                       int           depth,
                       gpointer      user_data)
 {
+  g_autoptr (GList) old_stage_views = NULL;
+
   actor->priv->needs_update_stage_views = TRUE;
   actor->priv->needs_compute_resource_scale = TRUE;
 
-  g_clear_pointer (&actor->priv->stage_views, g_list_free);
+  old_stage_views = g_steal_pointer (&actor->priv->stage_views);
+
+  if (old_stage_views)
+    g_signal_emit (actor, actor_signals[STAGE_VIEWS_CHANGED], 0);
 
   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
 }
@@ -17645,20 +17672,44 @@ clutter_actor_get_resource_scale (ClutterActor *self,
   return FALSE;
 }
 
+static gboolean
+sorted_lists_equal (GList *list_a,
+                    GList *list_b)
+{
+  GList *a, *b;
+
+  if (!list_a && !list_b)
+    return TRUE;
+
+  for (a = list_a, b = list_b;
+       a && b;
+       a = a->next, b = b->next)
+    {
+      if (a->data != b->data)
+        break;
+
+      if (!a->next && !b->next)
+        return TRUE;
+    }
+
+  return FALSE;
+}
+
 static void
 update_stage_views (ClutterActor *self)
 {
   ClutterActorPrivate *priv = self->priv;
+  g_autoptr (GList) old_stage_views = NULL;
   ClutterStage *stage;
   graphene_rect_t bounding_rect;
 
-  g_clear_pointer (&priv->stage_views, g_list_free);
+  old_stage_views = g_steal_pointer (&priv->stage_views);
 
   if (priv->needs_allocation)
     {
       g_warning ("Can't update stage views actor %s is on because it needs an "
                  "allocation.", _clutter_actor_get_debug_name (self));
-      return;
+      goto out;
     }
 
   stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
@@ -17673,10 +17724,18 @@ update_stage_views (ClutterActor *self)
 
   if (bounding_rect.size.width == 0.0 ||
       bounding_rect.size.height == 0.0)
-    return;
+    goto out;
 
   priv->stage_views = clutter_stage_get_views_for_rect (stage,
                                                         &bounding_rect);
+
+out:
+  if (g_signal_has_handler_pending (self, actor_signals[STAGE_VIEWS_CHANGED],
+                                    0, TRUE))
+    {
+      if (!sorted_lists_equal (old_stage_views, priv->stage_views))
+        g_signal_emit (self, actor_signals[STAGE_VIEWS_CHANGED], 0);
+    }
 }
 
 void


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