From 7419674bd39b0ac644b3fdb1cb5ba584f20526ee Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Thu, 25 Nov 2021 10:49:42 +0100 Subject: [PATCH] js: Change main.pushModal to return the Clutter.Grab handle All callers have been updated to keep this handle to identify their own grab. Also, optionally use the windowing state to determine whether the grab is suitable for the specific uses. This removes the need to trying to grab twice in the places where we settle for a keyboard grab. Part-of: --- js/gdm/loginDialog.js | 5 +++-- js/ui/dnd.js | 17 ++++++++++------- js/ui/grabHelper.js | 9 +++++++-- js/ui/lookingGlass.js | 9 +++++++-- js/ui/main.js | 24 +++++++++++------------- js/ui/modalDialog.js | 9 +++++++-- js/ui/overview.js | 8 ++++++-- js/ui/padOsd.js | 5 +++-- js/ui/popupMenu.js | 11 +++++++---- js/ui/screenShield.js | 18 ++++++++++-------- js/ui/switcherPopup.js | 15 +++++++++------ js/ui/unlockDialog.js | 9 +++++++-- 12 files changed, 87 insertions(+), 52 deletions(-) diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js index 6c5018006..3294d6556 100644 --- a/js/gdm/loginDialog.js +++ b/js/gdm/loginDialog.js @@ -1289,7 +1289,7 @@ var LoginDialog = GObject.registerClass({ this.opacity = 0; - Main.pushModal(global.stage, { actionMode: Shell.ActionMode.LOGIN_SCREEN }); + this._grab = Main.pushModal(global.stage, { actionMode: Shell.ActionMode.LOGIN_SCREEN }); this.ease({ opacity: 255, @@ -1301,7 +1301,8 @@ var LoginDialog = GObject.registerClass({ } close() { - Main.popModal(global.stage); + Main.popModal(this._grab); + this._grab = null; Main.ctrlAltTabManager.removeGroup(this); } diff --git a/js/ui/dnd.js b/js/ui/dnd.js index f6324f14e..d6a1f07c8 100644 --- a/js/ui/dnd.js +++ b/js/ui/dnd.js @@ -117,7 +117,6 @@ var _Draggable = class _Draggable { this._animationInProgress = false; // The drag is over and the item is in the process of animating to its original position (snapping back or reverting). this._dragCancellable = true; - this._eventsGrabbed = false; this._capturedEventId = 0; } @@ -208,18 +207,22 @@ var _Draggable = class _Draggable { } _grabEvents(device, touchSequence) { - if (!this._eventsGrabbed) { - this._eventsGrabbed = Main.pushModal(_getEventHandlerActor()); - if (this._eventsGrabbed) + if (!this._eventsGrab) { + let grab = Main.pushModal(_getEventHandlerActor()); + if ((grab.get_seat_state() & Clutter.GrabState.POINTER) !== 0) { this._grabDevice(_getEventHandlerActor(), device, touchSequence); + this._eventsGrab = grab; + } else { + Main.popModal(grab); + } } } _ungrabEvents() { - if (this._eventsGrabbed) { + if (this._eventsGrab) { this._ungrabDevice(); - Main.popModal(_getEventHandlerActor()); - this._eventsGrabbed = false; + Main.popModal(this._eventsGrab); + this._eventsGrab = null; } } diff --git a/js/ui/grabHelper.js b/js/ui/grabHelper.js index 89e1bee32..47a332a24 100644 --- a/js/ui/grabHelper.js +++ b/js/ui/grabHelper.js @@ -181,9 +181,13 @@ var GrabHelper = class GrabHelper { _takeModalGrab() { let firstGrab = this._modalCount == 0; if (firstGrab) { - if (!Main.pushModal(this._owner, this._modalParams)) + let grab = Main.pushModal(this._owner, this._modalParams); + if (grab.get_seat_state() === Clutter.GrabState.NONE) { + Main.popModal(grab); return false; + } + this._grab = grab; this._capturedEventId = this._owner.connect('captured-event', (actor, event) => { return this.onCapturedEvent(event); @@ -202,7 +206,8 @@ var GrabHelper = class GrabHelper { this._owner.disconnect(this._capturedEventId); this._ignoreUntilRelease = false; - Main.popModal(this._owner); + Main.popModal(this._grab); + this._grab = null; } // ignoreRelease: diff --git a/js/ui/lookingGlass.js b/js/ui/lookingGlass.js index 93d08f3fa..ed217a4db 100644 --- a/js/ui/lookingGlass.js +++ b/js/ui/lookingGlass.js @@ -1560,9 +1560,13 @@ class LookingGlass extends St.BoxLayout { if (this._open) return; - if (!Main.pushModal(this, { actionMode: Shell.ActionMode.LOOKING_GLASS })) + let grab = Main.pushModal(this, { actionMode: Shell.ActionMode.LOOKING_GLASS }); + if (grab.get_seat_state() === Clutter.GrabState.NONE) { + Main.popModal(grab); return; + } + this._grab = grab; this._notebook.selectIndex(0); this.show(); this._open = true; @@ -1602,7 +1606,8 @@ class LookingGlass extends St.BoxLayout { duration, mode: Clutter.AnimationMode.EASE_OUT_QUAD, onComplete: () => { - Main.popModal(this); + Main.popModal(this._grab); + this._grab = null; this.hide(); }, }); diff --git a/js/ui/main.js b/js/ui/main.js index 11ac073bb..14a541f0a 100644 --- a/js/ui/main.js +++ b/js/ui/main.js @@ -503,9 +503,9 @@ function notifyError(msg, details) { notify(msg, details); } -function _findModal(actor) { +function _findModal(grab) { for (let i = 0; i < modalActorFocusStack.length; i++) { - if (modalActorFocusStack[i].actor == actor) + if (modalActorFocusStack[i].grab === grab) return i; } return -1; @@ -537,7 +537,7 @@ function _findModal(actor) { * global keybindings; the default of NONE will filter * out all keybindings * - * @returns {bool}: true iff we successfully acquired a grab or already had one + * @returns {Clutter.Grab}: the grab handle created */ function pushModal(actor, params) { params = Params.parse(params, { timestamp: global.get_current_time(), @@ -551,9 +551,9 @@ function pushModal(actor, params) { modalCount += 1; let actorDestroyId = actor.connect('destroy', () => { - let index = _findModal(actor); + let index = _findModal(grab); if (index >= 0) - popModal(actor); + popModal(grab); }); let prevFocus = global.stage.get_key_focus(); @@ -577,14 +577,13 @@ function pushModal(actor, params) { actionMode = params.actionMode; global.stage.set_key_focus(actor); - return true; + return grab; } /** * popModal: - * @param {Clutter.Actor} actor: the actor passed to original invocation - * of pushModal() - * @param {number=} timestamp: optional timestamp + * @param {Clutter.Grab} grab - the grab given by pushModal() + * @param {number=} timestamp - optional timestamp * * Reverse the effect of pushModal(). If this invocation is undoing * the topmost invocation, then the focus will be restored to the @@ -594,11 +593,11 @@ function pushModal(actor, params) { * initiated event. If not provided then the value of * global.get_current_time() is assumed. */ -function popModal(actor, timestamp) { +function popModal(grab, timestamp) { if (timestamp == undefined) timestamp = global.get_current_time(); - let focusIndex = _findModal(actor); + let focusIndex = _findModal(grab); if (focusIndex < 0) { global.stage.set_key_focus(null); actionMode = Shell.ActionMode.NORMAL; @@ -611,8 +610,7 @@ function popModal(actor, timestamp) { let record = modalActorFocusStack[focusIndex]; record.actor.disconnect(record.destroyId); - let grab = record.grab; - grab.dismiss(); + record.grab.dismiss(); if (focusIndex == modalActorFocusStack.length - 1) { if (record.prevFocus) diff --git a/js/ui/modalDialog.js b/js/ui/modalDialog.js index 4b3078ae5..259a9c6bb 100644 --- a/js/ui/modalDialog.js +++ b/js/ui/modalDialog.js @@ -204,7 +204,8 @@ var ModalDialog = GObject.registerClass({ this._savedKeyFocus = focus; else this._savedKeyFocus = null; - Main.popModal(this, timestamp); + Main.popModal(this._grab, timestamp); + this._grab = null; this._hasModal = false; if (!this._shellReactive) @@ -218,9 +219,13 @@ var ModalDialog = GObject.registerClass({ let params = { actionMode: this._actionMode }; if (timestamp) params['timestamp'] = timestamp; - if (!Main.pushModal(this, params)) + let grab = Main.pushModal(this, params); + if (grab.get_seat_state() === Clutter.GrabState.NONE) { + Main.popModal(grab); return false; + } + this._grab = grab; Main.layoutManager.emit('system-modal-opened'); this._hasModal = true; diff --git a/js/ui/overview.js b/js/ui/overview.js index bcfdca344..2a603ba02 100644 --- a/js/ui/overview.js +++ b/js/ui/overview.js @@ -492,9 +492,12 @@ var Overview = class { let shouldBeModal = !this._inXdndDrag; if (shouldBeModal && !this._modal) { let actionMode = Shell.ActionMode.OVERVIEW; - if (Main.pushModal(global.stage, { actionMode })) { + let grab = Main.pushModal(global.stage, { actionMode }); + if (grab.get_seat_state() !== Clutter.GrabState.NONE) { + this._grab = grab; this._modal = true; } else { + Main.popModal(grab); this.hide(); return false; } @@ -502,7 +505,8 @@ var Overview = class { } else { // eslint-disable-next-line no-lonely-if if (this._modal) { - Main.popModal(global.stage); + Main.popModal(this._grab); + this._grab = false; this._modal = false; } } diff --git a/js/ui/padOsd.js b/js/ui/padOsd.js index 9de5b4927..8362b101d 100644 --- a/js/ui/padOsd.js +++ b/js/ui/padOsd.js @@ -723,7 +723,7 @@ var PadOsd = GObject.registerClass({ buttonBox.add_actor(this._editButton); this._syncEditionMode(); - Main.pushModal(this); + this._grab = Main.pushModal(this); } _updatePadChooser() { @@ -919,7 +919,8 @@ var PadOsd = GObject.registerClass({ } _onDestroy() { - Main.popModal(this); + Main.popModal(this._grab); + this._grab = null; this._actionEditor.close(); let seat = Clutter.get_default_backend().get_default_seat(); diff --git a/js/ui/popupMenu.js b/js/ui/popupMenu.js index 3a0e53c91..a0c00067d 100644 --- a/js/ui/popupMenu.js +++ b/js/ui/popupMenu.js @@ -1329,8 +1329,10 @@ var PopupMenuManager = class { } removeMenu(menu) { - if (menu == this.activeMenu) - Main.popModal(menu.actor); + if (menu === this.activeMenu) { + Main.popModal(this._grab); + this._grab = null; + } let position = this._findMenu(menu); if (position == -1) // not a menu we manage @@ -1353,12 +1355,13 @@ var PopupMenuManager = class { if (open) { if (this.activeMenu) this.activeMenu.close(BoxPointer.PopupAnimation.FADE); - Main.pushModal(menu.actor, this._grabParams); + this._grab = Main.pushModal(menu.actor, this._grabParams); this.activeMenu = menu; } else { if (this.activeMenu === menu) this.activeMenu = null; - Main.popModal(menu.actor); + Main.popModal(this._grab); + this._grab = null; } } diff --git a/js/ui/screenShield.js b/js/ui/screenShield.js index f18314b64..3d1a6eb1a 100644 --- a/js/ui/screenShield.js +++ b/js/ui/screenShield.js @@ -192,14 +192,15 @@ var ScreenShield = class { if (this._isModal) return true; - this._isModal = Main.pushModal(this.actor, { actionMode: Shell.ActionMode.LOCK_SCREEN }); - if (this._isModal) - return true; + let grab = Main.pushModal(this.actor, { actionMode: Shell.ActionMode.LOCK_SCREEN }); + + // We expect at least a keyboard grab here + this._isModal = (grab.get_seat_state() & Clutter.GrabState.KEYBOARD) !== 0; + if (this._isModal) + this._grab = grab; + else + Main.popModal(grab); - // We failed to get a pointer grab, it means that - // something else has it. Try with a keyboard grab only - this._isModal = Main.pushModal(this.actor, { options: Meta.ModalOptions.POINTER_ALREADY_GRABBED, - actionMode: Shell.ActionMode.LOCK_SCREEN }); return this._isModal; } @@ -550,7 +551,8 @@ var ScreenShield = class { this._dialog.popModal(); if (this._isModal) { - Main.popModal(this.actor); + Main.popModal(this._grab); + this._grab = null; this._isModal = false; } diff --git a/js/ui/switcherPopup.js b/js/ui/switcherPopup.js index ccc8b0fb0..17c3fcaa3 100644 --- a/js/ui/switcherPopup.js +++ b/js/ui/switcherPopup.js @@ -1,7 +1,7 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- /* exported SwitcherPopup, SwitcherList */ -const { Clutter, GLib, GObject, Meta, St } = imports.gi; +const { Clutter, GLib, GObject, St } = imports.gi; const Main = imports.ui.main; @@ -100,11 +100,13 @@ var SwitcherPopup = GObject.registerClass({ if (this._items.length == 0) return false; - if (!Main.pushModal(this)) { - // Probably someone else has a pointer grab, try again with keyboard only - if (!Main.pushModal(this, { options: Meta.ModalOptions.POINTER_ALREADY_GRABBED })) - return false; + let grab = Main.pushModal(this); + // We expect at least a keyboard grab here + if ((grab.get_seat_state() & Clutter.GrabState.KEYBOARD) === 0) { + Main.popModal(grab); + return false; } + this._grab = grab; this._haveModal = true; this._modifierMask = primaryModifier(mask); @@ -306,7 +308,8 @@ var SwitcherPopup = GObject.registerClass({ _popModal() { if (this._haveModal) { - Main.popModal(this); + Main.popModal(this._grab); + this._grab = null; this._haveModal = false; } } diff --git a/js/ui/unlockDialog.js b/js/ui/unlockDialog.js index b33da66a1..7fa307aa9 100644 --- a/js/ui/unlockDialog.js +++ b/js/ui/unlockDialog.js @@ -904,9 +904,13 @@ var UnlockDialog = GObject.registerClass({ timestamp, actionMode: Shell.ActionMode.UNLOCK_SCREEN, }; - if (!Main.pushModal(this, modalParams)) + let grab = Main.pushModal(this, modalParams); + if (grab.get_seat_state() !== Clutter.GrabState.ALL) { + Main.popModal(grab); return false; + } + this._grab = grab; this._isModal = true; return true; @@ -918,7 +922,8 @@ var UnlockDialog = GObject.registerClass({ popModal(timestamp) { if (this._isModal) { - Main.popModal(this, timestamp); + Main.popModal(this._grab, timestamp); + this._grab = null; this._isModal = false; } }