[gnome-shell/wip/carlosg/grabs-pt2] js: Change main.pushModal to return the Clutter.Grab handle




commit e267c3513b84ef50d36145fe202860222f451e33
Author: Carlos Garnacho <carlosg gnome org>
Date:   Thu Nov 25 10:49:42 2021 +0100

    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.

 js/gdm/loginDialog.js  |  5 +++--
 js/ui/dnd.js           | 17 ++++++++++-------
 js/ui/grabHelper.js    |  9 +++++++--
 js/ui/lookingGlass.js  |  9 +++++++--
 js/ui/main.js          | 20 +++++++++-----------
 js/ui/modalDialog.js   |  9 +++++++--
 js/ui/overview.js      |  8 ++++++--
 js/ui/padOsd.js        |  5 +++--
 js/ui/popupMenu.js     | 11 +++++++----
 js/ui/screenShield.js  | 16 +++++++++-------
 js/ui/switcherPopup.js | 13 ++++++++-----
 js/ui/unlockDialog.js  |  9 +++++++--
 12 files changed, 83 insertions(+), 48 deletions(-)
---
diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js
index d2a82b43d1..4e01dc3ed0 100644
--- a/js/gdm/loginDialog.js
+++ b/js/gdm/loginDialog.js
@@ -1283,7 +1283,7 @@ var LoginDialog = GObject.registerClass({
 
         this.opacity = 0;
 
-        Main.pushModal(this, { actionMode: Shell.ActionMode.LOGIN_SCREEN });
+        this._grab = Main.pushModal(this, { actionMode: Shell.ActionMode.LOGIN_SCREEN });
 
         this.ease({
             opacity: 255,
@@ -1295,7 +1295,8 @@ var LoginDialog = GObject.registerClass({
     }
 
     close() {
-        Main.popModal(this);
+        Main.popModal(this._grab);
+        this._grab = null;
         Main.ctrlAltTabManager.removeGroup(this);
     }
 
diff --git a/js/ui/dnd.js b/js/ui/dnd.js
index f6324f14e0..0f3d4b8566 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_windowing_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 89e1bee321..98cbaa595e 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 (this._grab.get_windowing_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 2af9c7ef7e..f32c7fff7a 100644
--- a/js/ui/lookingGlass.js
+++ b/js/ui/lookingGlass.js
@@ -1335,9 +1335,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_windowing_state() == Clutter.GrabState.NONE) {
+            Main.popModal(grab);
             return;
+        }
 
+        this._grab = grab;
         this._notebook.selectIndex(0);
         this.show();
         this._open = true;
@@ -1377,7 +1381,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 b496be782c..fd04d78a8f 100644
--- a/js/ui/main.js
+++ b/js/ui/main.js
@@ -482,9 +482,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;
@@ -530,9 +530,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();
@@ -556,13 +556,12 @@ 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 {Clutter.Grab} grab: the grab given by pushModal()
  * @param {number=} timestamp: optional timestamp
  *
  * Reverse the effect of pushModal(). If this invocation is undoing
@@ -573,11 +572,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;
@@ -590,8 +589,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 4b3078ae5e..0941dae66e 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_windowing_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 2312bb10d0..86ddfa86c6 100644
--- a/js/ui/overview.js
+++ b/js/ui/overview.js
@@ -488,9 +488,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_windowing_state () !== Clutter.GrabState.NONE) {
+                    this._grab = grab;
                     this._modal = true;
                 } else {
+                    Main.popModal(grab);
                     this.hide();
                     return false;
                 }
@@ -498,7 +501,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 9de5b49276..8362b101d5 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 2e6e56de2d..f37a0dcbdd 100644
--- a/js/ui/popupMenu.js
+++ b/js/ui/popupMenu.js
@@ -1313,8 +1313,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
@@ -1337,12 +1339,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 87b79b353d..f25ad8607b 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 });
+        let grab = Main.pushModal(this.actor, { actionMode: Shell.ActionMode.LOCK_SCREEN });
+
+        // We expect at least a keyboard grab here
+        this._isModal = (grab.get_windowing_state() & Clutter.GrabState.KEYBOARD) !== 0;
         if (this._isModal)
-            return true;
+            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 b1e2730068..e4e5223917 100644
--- a/js/ui/switcherPopup.js
+++ b/js/ui/switcherPopup.js
@@ -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_windowing_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 3ef6aa90f0..5ac73f6cb3 100644
--- a/js/ui/unlockDialog.js
+++ b/js/ui/unlockDialog.js
@@ -888,9 +888,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_windowing_state() !== Clutter.GrabState.ALL) {
+            Main.popModal(grab);
             return false;
+        }
 
+        this._grab = grab;
         this._isModal = true;
 
         return true;
@@ -902,7 +906,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;
         }
     }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]