From 6ec5f8e70b35d84794d28f329c323bb3a27ed0e6 Mon Sep 17 00:00:00 2001 From: JaniSoto Date: Fri, 10 Apr 2026 09:36:41 +0200 Subject: [PATCH 1/3] fix: unstick wayland touch grab with virtual esc key --- grab.js | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/grab.js b/grab.js index 8d648bdd..26b62ca9 100644 --- a/grab.js +++ b/grab.js @@ -40,6 +40,16 @@ export function getVirtualPointer() { return virtualPointer; } +let virtualKeyboard; +export function getVirtualKeyboard() { + if (!virtualKeyboard) { + virtualKeyboard = Clutter.get_default_backend() + .get_default_seat() + .create_virtual_device(Clutter.InputDeviceType.KEYBOARD_DEVICE); + } + return virtualKeyboard; +} + export class MoveGrab { constructor(metaWindow, type, space) { this.window = metaWindow; @@ -567,16 +577,17 @@ export class MoveGrab { */ Utils.later_add(Meta.LaterType.IDLE, () => { if (!global.display.end_grab_op && this.wasTiled) { - // move to current cursor position + let time = Clutter.get_current_event_time(); + + // For Mouse users: Fakes a mouse click to break Mutter's pointer grab let [x, y] = global.get_pointer(); - getVirtualPointer().notify_absolute_motion( - Clutter.get_current_event_time(), - x, y); - - getVirtualPointer().notify_button(Clutter.get_current_event_time(), - Clutter.BUTTON_PRIMARY, Clutter.ButtonState.PRESSED); - getVirtualPointer().notify_button(Clutter.get_current_event_time(), - Clutter.BUTTON_PRIMARY, Clutter.ButtonState.RELEASED); + getVirtualPointer().notify_absolute_motion(time, x, y); + getVirtualPointer().notify_button(time, Clutter.BUTTON_PRIMARY, Clutter.ButtonState.PRESSED); + getVirtualPointer().notify_button(time, Clutter.BUTTON_PRIMARY, Clutter.ButtonState.RELEASED); + + // For Touch users: Fakes an 'Escape' keypress to break Mutter's Wayland touch grab + getVirtualKeyboard().notify_keyval(time, Clutter.KEY_Escape, Clutter.KeyState.PRESSED); + getVirtualKeyboard().notify_keyval(time, Clutter.KEY_Escape, Clutter.KeyState.RELEASED); } }); } From e11bc8ea35aae677cc3f708340d947fda653269e Mon Sep 17 00:00:00 2001 From: TheSola10 Date: Tue, 21 Apr 2026 14:08:54 +0900 Subject: [PATCH 2/3] styling: remove trailing spaces --- grab.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grab.js b/grab.js index 1796199d..a7fc65c1 100644 --- a/grab.js +++ b/grab.js @@ -586,7 +586,7 @@ export class MoveGrab { Utils.later_add(Meta.LaterType.IDLE, () => { if (!global.display.end_grab_op && this.wasTiled) { let time = Clutter.get_current_event_time(); - + // For Mouse users: Fakes a mouse click to break Mutter's pointer grab let [x, y] = global.get_pointer(); getVirtualPointer().notify_absolute_motion(time, x, y); From 49fee53aa614f4a2b8858dd442ab29f5e2639d8a Mon Sep 17 00:00:00 2001 From: JaniSoto Date: Tue, 21 Apr 2026 08:19:36 +0200 Subject: [PATCH 3/3] use only Escape to break Wayland grabs --- grab.js | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/grab.js b/grab.js index a7fc65c1..38f90a0e 100644 --- a/grab.js +++ b/grab.js @@ -38,22 +38,11 @@ export function disable() { } /** - * Returns a virtual pointer (i.e. mouse) device that can be used to - * "clickout" of a drag operation when `grab_end_op` is unavailable + * Returns a virtual keyboard that can be used to + * "escape" of a drag operation when `grab_end_op` is unavailable * (i.e. as of Gnome 44 where `grab_end_op` was removed). * @returns Clutter.VirtualInputDevice */ -let virtualPointer; -export function getVirtualPointer() { - if (!virtualPointer) { - virtualPointer = Clutter.get_default_backend() - .get_default_seat() - .create_virtual_device(Clutter.InputDeviceType.POINTER_DEVICE); - } - - return virtualPointer; -} - let virtualKeyboard; export function getVirtualKeyboard() { if (!virtualKeyboard) { @@ -586,14 +575,8 @@ export class MoveGrab { Utils.later_add(Meta.LaterType.IDLE, () => { if (!global.display.end_grab_op && this.wasTiled) { let time = Clutter.get_current_event_time(); - - // For Mouse users: Fakes a mouse click to break Mutter's pointer grab - let [x, y] = global.get_pointer(); - getVirtualPointer().notify_absolute_motion(time, x, y); - getVirtualPointer().notify_button(time, Clutter.BUTTON_PRIMARY, Clutter.ButtonState.PRESSED); - getVirtualPointer().notify_button(time, Clutter.BUTTON_PRIMARY, Clutter.ButtonState.RELEASED); - - // For Touch users: Fakes an 'Escape' keypress to break Mutter's Wayland touch grab + + // Fakes an 'Escape' keypress to break Mutter's Wayland grab (works for both Touch and Pointer) getVirtualKeyboard().notify_keyval(time, Clutter.KEY_Escape, Clutter.KeyState.PRESSED); getVirtualKeyboard().notify_keyval(time, Clutter.KEY_Escape, Clutter.KeyState.RELEASED); }