|
|
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 |
|