[mutter/wip/carlosg/grabs-pt1: 20/30] clutter: Emit crossing events along with ClutterGrabs becoming active




commit c6bcc03d9125d3806be6049adbb98645178d7496
Author: Carlos Garnacho <carlosg gnome org>
Date:   Tue Oct 26 18:57:35 2021 +0200

    clutter: Emit crossing events along with ClutterGrabs becoming active
    
    Emit crossing events whenever a grab coming or going would cause a
    pointer/touchpoint to become inactive on their position. Depending
    on whether the pointer lies inside the old or new grab widgets,
    enter or leave events would be generated.

 clutter/clutter/clutter-stage.c | 157 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 156 insertions(+), 1 deletion(-)
---
diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c
index 3d3c4f1fee..d6ab02b787 100644
--- a/clutter/clutter/clutter-stage.c
+++ b/clutter/clutter/clutter-stage.c
@@ -3425,6 +3425,25 @@ clutter_stage_get_device_actor (ClutterStage         *stage,
   return NULL;
 }
 
+static ClutterActor *
+common_root_actor (ClutterStage *stage,
+                   ClutterActor *a,
+                   ClutterActor *b)
+{
+  if (a && b)
+    {
+      while (a)
+        {
+          if (a == b || clutter_actor_contains (a, b))
+            return a;
+
+          a = clutter_actor_get_parent (a);
+        }
+    }
+
+  return CLUTTER_ACTOR (stage);
+}
+
 static ClutterEvent *
 create_crossing_event (ClutterStage         *stage,
                        ClutterInputDevice   *device,
@@ -3535,6 +3554,136 @@ clutter_stage_get_device_coords (ClutterStage         *stage,
     *coords = entry->coords;
 }
 
+static void
+clutter_stage_notify_grab_on_entry (ClutterStage       *stage,
+                                    PointerDeviceEntry *entry,
+                                    ClutterActor       *grab_actor,
+                                    ClutterActor       *old_grab_actor)
+{
+  gboolean pointer_in_grab, pointer_in_old_grab;
+  ClutterEventType event_type = CLUTTER_NOTHING;
+  ClutterActor *topmost, *deepmost;
+
+  pointer_in_grab =
+    !grab_actor ||
+    grab_actor == entry->current_actor ||
+    clutter_actor_contains (grab_actor, entry->current_actor);
+  pointer_in_old_grab =
+    !old_grab_actor ||
+    old_grab_actor == entry->current_actor ||
+    clutter_actor_contains (old_grab_actor, entry->current_actor);
+
+  /* Equate NULL actors to the stage here, to ease calculations further down. */
+  if (!grab_actor)
+    grab_actor = CLUTTER_ACTOR (stage);
+  if (!old_grab_actor)
+    old_grab_actor = CLUTTER_ACTOR (stage);
+
+  if (grab_actor == old_grab_actor)
+    return;
+
+  if (pointer_in_grab && pointer_in_old_grab)
+    {
+      /* Both grabs happen to contain the pointer actor, we have to figure out
+       * which is topmost, and emit ENTER/LEAVE events accordingly on the actors
+       * between old/new grabs.
+       */
+      if (clutter_actor_contains (grab_actor, old_grab_actor))
+        {
+          /* grab_actor is above old_grab_actor, emit ENTER events in the
+           * line between those two actors.
+           */
+          event_type = CLUTTER_ENTER;
+          deepmost = old_grab_actor;
+          topmost = grab_actor;
+        }
+      else if (clutter_actor_contains (old_grab_actor, grab_actor))
+        {
+          /* old_grab_actor is above grab_actor, emit LEAVE events in the
+           * line between those two actors.
+           */
+          event_type = CLUTTER_LEAVE;
+          deepmost = grab_actor;
+          topmost = old_grab_actor;
+        }
+    }
+  else if (pointer_in_grab)
+    {
+      /* Pointer is somewhere inside the grab_actor hierarchy. Emit ENTER events
+       * from the current grab actor to the pointer actor.
+       */
+      event_type = CLUTTER_ENTER;
+      deepmost = entry->current_actor;
+      topmost = grab_actor;
+    }
+  else if (pointer_in_old_grab)
+    {
+      /* Pointer is somewhere inside the old_grab_actor hierarchy. Emit LEAVE
+       * events from the common root of old/cur grab actors to the pointer
+       * actor.
+       */
+      event_type = CLUTTER_LEAVE;
+      deepmost = entry->current_actor;
+      topmost = common_root_actor (stage, grab_actor, old_grab_actor);
+    }
+
+  if (event_type != CLUTTER_NOTHING)
+    {
+      ClutterEvent *event;
+
+      event = create_crossing_event (stage,
+                                     entry->device,
+                                     entry->sequence,
+                                     event_type,
+                                     entry->current_actor,
+                                     entry->current_actor,
+                                     entry->coords,
+                                     CLUTTER_CURRENT_TIME);
+      _clutter_actor_handle_event (deepmost, topmost, event);
+      clutter_event_free (event);
+    }
+}
+
+static void
+clutter_stage_notify_grab (ClutterStage *stage,
+                           ClutterGrab  *cur,
+                           ClutterGrab  *old)
+{
+  ClutterStagePrivate *priv = stage->priv;
+  ClutterActor *cur_actor = NULL, *old_actor = NULL;
+  PointerDeviceEntry *entry;
+  GHashTableIter iter;
+
+  if (cur)
+    cur_actor = cur->actor;
+  if (old)
+    old_actor = old->actor;
+
+  /* Nothing to notify */
+  if (cur_actor == old_actor)
+    return;
+
+  g_hash_table_iter_init (&iter, priv->pointer_devices);
+  while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &entry))
+    {
+      /* Update pointers */
+      clutter_stage_notify_grab_on_entry (stage,
+                                          entry,
+                                          cur_actor,
+                                          old_actor);
+    }
+
+  g_hash_table_iter_init (&iter, priv->touch_sequences);
+  while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &entry))
+    {
+      /* Update touch sequences */
+      clutter_stage_notify_grab_on_entry (stage,
+                                          entry,
+                                          cur_actor,
+                                          old_actor);
+    }
+}
+
 ClutterGrab *
 clutter_grab (ClutterStage *stage,
               ClutterActor *actor)
@@ -3547,6 +3696,7 @@ clutter_grab (ClutterStage *stage,
   grab->next = priv->grabs;
 
   priv->grabs = grab;
+  clutter_stage_notify_grab (stage, grab, grab->next);
 
   return grab;
 }
@@ -3567,7 +3717,12 @@ clutter_ungrab (ClutterStage *stage,
     next->prev = prev;
 
   if (!prev)
-    priv->grabs = next;
+    {
+      /* This is the active grab */
+      g_assert (priv->grabs == grab);
+      priv->grabs = next;
+      clutter_stage_notify_grab (stage, next, grab);
+    }
 
   g_free (grab);
 }


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