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

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