[gnome-shell] ScreenShield: try harder to become modal, and catch failures



commit 4dc954032551894a15cafd3ea72255dfca162122
Author: Giovanni Campagna <gcampagna src gnome org>
Date:   Mon Nov 26 20:18:57 2012 +0100

    ScreenShield: try harder to become modal, and catch failures
    
    The screenshield was not checking the return value of pushModal(), meaning
    that it believed it was fully locked when it was not. Later, calling
    popModal() would fail, causing an exception and blocking the unlock.
    Now when we fail we include an explanatory message, pointing the user
    to the actual cause of the issue.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=689106

 js/ui/screenShield.js |   46 ++++++++++++++++++++++++++++++++++++----------
 1 files changed, 36 insertions(+), 10 deletions(-)
---
diff --git a/js/ui/screenShield.js b/js/ui/screenShield.js
index 506b60d..d57a94e 100644
--- a/js/ui/screenShield.js
+++ b/js/ui/screenShield.js
@@ -568,6 +568,21 @@ const ScreenShield = new Lang.Class({
         }
     },
 
+    _becomeModal: function() {
+        if (this._isModal)
+            return true;
+
+        this._isModal = Main.pushModal(this.actor, { keybindingMode: Shell.KeyBindingMode.LOCK_SCREEN });
+        if (this._isModal)
+            return true;
+
+        // 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,
+                                                     keybindingMode: Shell.KeyBindingMode.LOCK_SCREEN });
+        return this._isModal;
+    },
+
     _onLockScreenKeyRelease: function(actor, event) {
         let symbol = event.get_key_symbol();
 
@@ -725,10 +740,18 @@ const ScreenShield = new Lang.Class({
             }
         }
 
-        if (!this._isModal) {
-            Main.pushModal(this.actor, { keybindingMode: Shell.KeyBindingMode.LOCK_SCREEN });
-            this._isModal = true;
-            }
+        if (!this._becomeModal()) {
+            // We could not become modal, so we can't activate the
+            // screenshield. The user is probably very upset at this
+            // point, but any application using global grabs is broken
+            // Just tell him to stop using this app
+            // 
+            // XXX: another option is to kick the user into the gdm login
+            // screen, where we're not affected by grabs
+            Main.notifyError(_("Unable to lock"),
+                             _("Lock was blocked by an application"));
+            return;
+        }
 
         if (this._lightbox.actor.visible ||
             this._isActive) {
@@ -805,9 +828,10 @@ const ScreenShield = new Lang.Class({
         // Ensure that the stage window is mapped, before taking a grab
         // otherwise X errors out
         Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
-            if (!this._isModal) {
-                Main.pushModal(this.actor);
-                this._isModal = true;
+            if (!this._becomeModal()) {
+                // In the login screen, this is a hard error. Fail-whale
+                log('Could not acquire modal grab for the login screen. Aborting login process.');
+                Meta.quit(Meta.ExitCode.ERROR);
             }
 
             return false;
@@ -1135,9 +1159,11 @@ const ScreenShield = new Lang.Class({
     },
 
     lock: function(animate) {
-        if (!this._isModal) {
-            Main.pushModal(this.actor, { keybindingMode: Shell.KeyBindingMode.LOCK_SCREEN });
-            this._isModal = true;
+        // Warn the user if we can't become modal
+        if (!this._becomeModal()) {
+            Main.notifyError(_("Unable to lock"),
+                             _("Lock was blocked by an application"));
+            return;
         }
 
         this._isLocked = true;


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