Blame SOURCES/0001-events-Sync-pending-pointer-events-without-a-window.patch

ad2d02
From 3582d1780c9bf3fc93604963a11b9b60d9895178 Mon Sep 17 00:00:00 2001
ad2d02
From: Olivier Fourdan <ofourdan@redhat.com>
ad2d02
Date: Wed, 2 Oct 2019 16:49:28 +0200
ad2d02
Subject: [PATCH] events: Sync pending pointer events without a window
ad2d02
ad2d02
Mutter issues a synchronous grab on the pointer for unfocused client
ad2d02
windows to be able to catch the button events first and raise/focus
ad2d02
client windows accordingly.
ad2d02
ad2d02
When there is a synchronous grab in effect, all events are queued until
ad2d02
the grabbing client releases the event queue as it processes the events.
ad2d02
ad2d02
Mutter does release the events in its event handler function but does so
ad2d02
only if it is able to find the window matching the event. If the window
ad2d02
is a shell widget, that matching may fail and therefore Mutter will not
ad2d02
release the events, hence causing a freeze in pointer events delivery.
ad2d02
ad2d02
To avoid the issue, make sure we sync the pointer events in case we
ad2d02
can't find a matching window.
ad2d02
ad2d02
https://gitlab.gnome.org/GNOME/mutter/merge_requests/821
ad2d02
---
ad2d02
 src/core/events.c | 62 ++++++++++++++++++++++++++++++++++++++---------
ad2d02
 1 file changed, 51 insertions(+), 11 deletions(-)
ad2d02
ad2d02
diff --git a/src/core/events.c b/src/core/events.c
ad2d02
index 92503a168..9b19065fb 100644
ad2d02
--- a/src/core/events.c
ad2d02
+++ b/src/core/events.c
ad2d02
@@ -51,6 +51,12 @@
ad2d02
 #define IS_KEY_EVENT(e) ((e)->type == CLUTTER_KEY_PRESS || \
ad2d02
                          (e)->type == CLUTTER_KEY_RELEASE)
ad2d02
 
ad2d02
+typedef enum
ad2d02
+{
ad2d02
+  EVENTS_UNFREEZE_SYNC,
ad2d02
+  EVENTS_UNFREEZE_REPLAY,
ad2d02
+} EventsUnfreezeMethod;
ad2d02
+
ad2d02
 static gboolean
ad2d02
 stage_has_key_focus (void)
ad2d02
 {
ad2d02
@@ -167,6 +173,43 @@ sequence_is_pointer_emulated (MetaDisplay        *display,
ad2d02
   return FALSE;
ad2d02
 }
ad2d02
 
ad2d02
+static void
ad2d02
+maybe_unfreeze_pointer_events (MetaBackend          *backend,
ad2d02
+                               const ClutterEvent   *event,
ad2d02
+                               EventsUnfreezeMethod  unfreeze_method)
ad2d02
+{
ad2d02
+  Display *xdisplay;
ad2d02
+  int event_mode;
ad2d02
+  int device_id;
ad2d02
+
ad2d02
+  if (event->type != CLUTTER_BUTTON_PRESS)
ad2d02
+    return;
ad2d02
+
ad2d02
+  if (!META_IS_BACKEND_X11 (backend))
ad2d02
+    return;
ad2d02
+
ad2d02
+  device_id = clutter_event_get_device_id (event);
ad2d02
+  switch (unfreeze_method)
ad2d02
+    {
ad2d02
+    case EVENTS_UNFREEZE_SYNC:
ad2d02
+      event_mode = XISyncDevice;
ad2d02
+      meta_verbose ("Syncing events time %u device %i\n",
ad2d02
+                    (unsigned int) event->button.time, device_id);
ad2d02
+      break;
ad2d02
+    case EVENTS_UNFREEZE_REPLAY:
ad2d02
+      event_mode = XIReplayDevice;
ad2d02
+      meta_verbose ("Replaying events time %u device %i\n",
ad2d02
+                    (unsigned int) event->button.time, device_id);
ad2d02
+      break;
ad2d02
+    default:
ad2d02
+      g_assert_not_reached ();
ad2d02
+      return;
ad2d02
+    }
ad2d02
+
ad2d02
+  xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
ad2d02
+  XIAllowEvents (xdisplay, device_id, event_mode, event->button.time);
ad2d02
+}
ad2d02
+
ad2d02
 static gboolean
ad2d02
 meta_display_handle_event (MetaDisplay        *display,
ad2d02
                            const ClutterEvent *event)
ad2d02
@@ -366,17 +409,7 @@ meta_display_handle_event (MetaDisplay        *display,
ad2d02
         {
ad2d02
           /* Only replay button press events, since that's where we
ad2d02
            * have the synchronous grab. */
ad2d02
-          if (event->type == CLUTTER_BUTTON_PRESS)
ad2d02
-            {
ad2d02
-              if (META_IS_BACKEND_X11 (backend))
ad2d02
-                {
ad2d02
-                  Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
ad2d02
-                  meta_verbose ("Allowing events time %u\n",
ad2d02
-                                (unsigned int)event->button.time);
ad2d02
-                  XIAllowEvents (xdisplay, clutter_event_get_device_id (event),
ad2d02
-                                 XIReplayDevice, event->button.time);
ad2d02
-                }
ad2d02
-            }
ad2d02
+          maybe_unfreeze_pointer_events (backend, event, EVENTS_UNFREEZE_REPLAY);
ad2d02
 
ad2d02
           /* If the focus window has an active close dialog let clutter
ad2d02
            * events go through, so fancy clutter dialogs can get to handle
ad2d02
@@ -392,6 +425,13 @@ meta_display_handle_event (MetaDisplay        *display,
ad2d02
 
ad2d02
       goto out;
ad2d02
     }
ad2d02
+  else
ad2d02
+    {
ad2d02
+      /* We could not match the event with a window, make sure we sync
ad2d02
+       * the pointer to discard the sequence and don't keep events frozen.
ad2d02
+       */
ad2d02
+       maybe_unfreeze_pointer_events (backend, event, EVENTS_UNFREEZE_SYNC);
ad2d02
+    }
ad2d02
 
ad2d02
  out:
ad2d02
   /* If the compositor has a grab, don't pass that through to Wayland */
ad2d02
-- 
ad2d02
2.23.0
ad2d02