[mutter/wip/halfline/gesture-osk-fix] clutter-gester-action: Cancel gesture when a device gets grabbed




commit a587d3f3deadf53e3e08ff24c98e3fc466248f7e
Author: Ray Strode <rstrode redhat com>
Date:   Wed Oct 6 22:03:46 2021 -0400

    clutter-gester-action: Cancel gesture when a device gets grabbed
    
    If an actor takes a grab on an input device, that's a good indicator
    that the user expects input to be handled solely by the actor and
    any gestures that are taking place aren't meant for the stage.
    
    At the moment, the gesture code has no insight into when a grab
    gets taken, though. If a grab does get taken it missed out on the
    motion and button release events that have now been redirected to
    the actor.
    
    Those missed events can confuse the event processing code into thinking
    the user is doing a multi-press gesture, when the user is actually just
    e.g., doing a series of clicks.
    
    This commit addresses the problem by installing an event filter that
    can see the events before they're delivered to the grabbed actor.
    
    The filter checkes if a device a grabbed, and if so cancels any
    in-flight gestures that are currently getting processed.

 clutter/clutter/clutter-gesture-action.c | 55 +++++++++++++++++++++-----------
 1 file changed, 36 insertions(+), 19 deletions(-)
---
diff --git a/clutter/clutter/clutter-gesture-action.c b/clutter/clutter/clutter-gesture-action.c
index f938a549aa..d9f0c2700e 100644
--- a/clutter/clutter/clutter-gesture-action.c
+++ b/clutter/clutter/clutter-gesture-action.c
@@ -120,6 +120,7 @@ struct _ClutterGestureActionPrivate
 
   gulong actor_capture_id;
   gulong stage_capture_id;
+  guint  event_filter_id;
 
   ClutterGestureTriggerEdge edge;
   float distance_x, distance_y;
@@ -312,6 +313,7 @@ cancel_gesture (ClutterGestureAction *action)
 
   priv->in_gesture = FALSE;
 
+  g_clear_handle_id (&priv->event_filter_id, clutter_event_remove_filter);
   g_clear_signal_handler (&priv->stage_capture_id, priv->stage);
 
   actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (action));
@@ -353,6 +355,27 @@ begin_gesture (ClutterGestureAction *action,
   return TRUE;
 }
 
+static gboolean
+event_filter_cb (ClutterActor         *stage,
+                 ClutterEvent         *event,
+                 ClutterGestureAction *action)
+{
+  ClutterInputDevice *device = NULL;
+  ClutterActor *grabbed_actor;
+
+  device = clutter_event_get_device (event);
+
+  if (device == NULL)
+    return CLUTTER_EVENT_PROPAGATE;
+
+  grabbed_actor = clutter_input_device_get_grabbed_actor (device);
+
+  if (grabbed_actor != NULL)
+    cancel_gesture (action);
+
+  return CLUTTER_EVENT_PROPAGATE;
+}
+
 static gboolean
 stage_captured_event_cb (ClutterActor         *stage,
                          ClutterEvent         *event,
@@ -383,21 +406,7 @@ stage_captured_event_cb (ClutterActor         *stage,
   switch (clutter_event_type (event))
     {
     case CLUTTER_MOTION:
-      {
-        ClutterModifierType mods = clutter_event_get_state (event);
-
-        /* we might miss a button-release event in case of grabs,
-         * so we need to check whether the button is still down
-         * during a motion event
-         */
-        if (!(mods & CLUTTER_BUTTON1_MASK))
-          {
-            cancel_gesture (action);
-            return CLUTTER_EVENT_PROPAGATE;
-          }
-      }
       /* Follow same code path as a touch event update */
-
     case CLUTTER_TOUCH_UPDATE:
       if (!priv->in_gesture)
         {
@@ -482,7 +491,10 @@ stage_captured_event_cb (ClutterActor         *stage,
     }
 
   if (priv->points->len == 0)
-    g_clear_signal_handler (&priv->stage_capture_id, priv->stage);
+    {
+      g_clear_handle_id (&priv->event_filter_id, clutter_event_remove_filter);
+      g_clear_signal_handler (&priv->stage_capture_id, priv->stage);
+    }
 
   return CLUTTER_EVENT_PROPAGATE;
 }
@@ -508,6 +520,12 @@ actor_captured_event_cb (ClutterActor *actor,
   if (priv->stage == NULL)
     priv->stage = clutter_actor_get_stage (actor);
 
+  if (priv->event_filter_id == 0)
+    priv->event_filter_id = clutter_event_add_filter (priv->stage,
+                                                      (ClutterEventFilterFunc) event_filter_cb,
+                                                      NULL,
+                                                      action);
+
   if (priv->stage_capture_id == 0)
     priv->stage_capture_id =
       g_signal_connect_after (priv->stage, "captured-event",
@@ -542,12 +560,11 @@ clutter_gesture_action_set_actor (ClutterActorMeta *meta,
       priv->actor_capture_id = 0;
     }
 
-  if (priv->stage_capture_id != 0)
+  if (priv->stage != NULL)
     {
-      if (priv->stage != NULL)
-        g_clear_signal_handler (&priv->stage_capture_id, priv->stage);
+      g_clear_handle_id (&priv->event_filter_id, clutter_event_remove_filter);
+      g_clear_signal_handler (&priv->stage_capture_id, priv->stage);
 
-      priv->stage_capture_id = 0;
       priv->stage = NULL;
     }
 


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