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