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




commit 6683e3901f42c82c91458f1b63e68f59a1eabe42
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, 157 insertions(+)
---
diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c
index 5b89080605..d7e4b5ac1b 100644
--- a/clutter/clutter/clutter-stage.c
+++ b/clutter/clutter/clutter-stage.c
@@ -3460,6 +3460,27 @@ clutter_stage_set_device_coords (ClutterStage         *stage,
     entry->coords = coords;
 }
 
+static ClutterActor *
+find_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);
+        }
+
+      g_warn_if_reached ();
+    }
+
+  return CLUTTER_ACTOR (stage);
+}
+
 static ClutterEvent *
 create_crossing_event (ClutterStage         *stage,
                        ClutterInputDevice   *device,
@@ -3641,6 +3662,140 @@ clutter_stage_pick_and_update_device (ClutterStage             *stage,
   return new_actor;
 }
 
+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;
+
+  if (!entry->current_actor)
+    return;
+
+  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 = clutter_actor_get_parent (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 = clutter_actor_get_parent (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 = find_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,
+                                     event_type == CLUTTER_LEAVE ?
+                                     grab_actor : old_grab_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_stage_grab (ClutterStage *stage,
                     ClutterActor *actor)
@@ -3661,6 +3816,7 @@ clutter_stage_grab (ClutterStage *stage,
     priv->topmost_grab->prev = grab;
 
   priv->topmost_grab = grab;
+  clutter_stage_notify_grab (stage, grab, grab->next);
 
   return grab;
 }
@@ -3687,6 +3843,7 @@ clutter_grab_dismiss (ClutterGrab *grab)
       /* This is the active grab */
       g_assert (prev == NULL);
       priv->topmost_grab = 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]