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: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2045>
This commit is contained in:
Carlos Garnacho 2021-11-25 10:49:42 +01:00
parent 2709f6c102
commit 7419674bd3
12 changed files with 87 additions and 52 deletions

View File

@ -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);
}

View File

@ -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;
}
}

View File

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

View File

@ -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();
},
});

View File

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

View File

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

View File

@ -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;
}
}

View File

@ -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();

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;
}
}