[gnome-shell] messageTray: Don't use focus grabs



commit eef593a34ea04db70064525549a45963e14ac968
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Thu May 23 17:11:40 2013 -0400

    messageTray: Don't use focus grabs
    
    We can easily implement much of the same behavior ourselves by
    keeping track of Clutter's focus events. Reintroduce heavily
    modified FocusGrabber to do the work for us.
    
    This will temporarily break when the user selects a window until
    we can make gnome-shell automatically set the stage focus.
    
    This also removes our only use of focus grabs, so remove those
    as well.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=700735

 js/ui/grabHelper.js  |   91 ++------------------------------------------------
 js/ui/messageTray.js |   78 ++++++++++++++++++++++++++++++++++---------
 2 files changed, 65 insertions(+), 104 deletions(-)
---
diff --git a/js/ui/grabHelper.js b/js/ui/grabHelper.js
index 690ba6e..d69a534 100644
--- a/js/ui/grabHelper.js
+++ b/js/ui/grabHelper.js
@@ -32,13 +32,9 @@ const GrabHelper = new Lang.Class({
 
         this._actors = [];
         this._capturedEventId = 0;
-        this._keyFocusNotifyId = 0;
-        this._focusWindowChangedId = 0;
         this._ignoreRelease = false;
-        this._isUngrabbingCount = 0;
 
         this._modalCount = 0;
-        this._grabFocusCount = 0;
     },
 
     // addActor:
@@ -149,7 +145,6 @@ const GrabHelper = new Lang.Class({
     grab: function(params) {
         params = Params.parse(params, { actor: null,
                                         modal: false,
-                                        grabFocus: false,
                                         focus: null,
                                         onUngrab: null });
 
@@ -165,19 +160,16 @@ const GrabHelper = new Lang.Class({
         if (params.modal && !this._takeModalGrab())
             return false;
 
-        if (params.grabFocus && !this._takeFocusGrab(hadFocus))
-            return false;
-
         this._grabStack.push(params);
 
         if (params.focus) {
             params.focus.grab_key_focus();
-        } else if (newFocus && (hadFocus || params.grabFocus)) {
+        } else if (newFocus && hadFocus) {
             if (!newFocus.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false))
                 newFocus.grab_key_focus();
         }
 
-        if ((params.grabFocus || params.modal) && !this._capturedEventId)
+        if (params.modal && !this._capturedEventId)
             this._capturedEventId = global.stage.connect('captured-event', Lang.bind(this, 
this._onCapturedEvent));
 
         return true;
@@ -203,52 +195,6 @@ const GrabHelper = new Lang.Class({
         global.sync_pointer();
     },
 
-    _takeFocusGrab: function(hadFocus) {
-        let firstGrab = (this._grabFocusCount == 0);
-        if (firstGrab) {
-            let metaDisplay = global.screen.get_display();
-
-            this._grabbedFromKeynav = hadFocus;
-            this._preGrabInputMode = global.stage_input_mode;
-
-            if (this._preGrabInputMode == Shell.StageInputMode.NORMAL)
-                global.set_stage_input_mode(Shell.StageInputMode.FOCUSED);
-
-            this._keyFocusNotifyId = global.stage.connect('notify::key-focus', Lang.bind(this, 
this._onKeyFocusChanged));
-            this._focusWindowChangedId = metaDisplay.connect('notify::focus-window', Lang.bind(this, 
this._focusWindowChanged));
-        }
-
-        this._grabFocusCount++;
-        return true;
-    },
-
-    _releaseFocusGrab: function() {
-        this._grabFocusCount--;
-        if (this._grabFocusCount > 0)
-            return;
-
-        if (this._keyFocusNotifyId > 0) {
-            global.stage.disconnect(this._keyFocusNotifyId);
-            this._keyFocusNotifyId = 0;
-        }
-
-        if (this._focusWindowChangedId > 0) {
-            let metaDisplay = global.screen.get_display();
-            metaDisplay.disconnect(this._focusWindowChangedId);
-            this._focusWindowChangedId = 0;
-        }
-
-        let prePopInputMode = global.stage_input_mode;
-
-        if (this._grabbedFromKeynav) {
-            if (this._preGrabInputMode == Shell.StageInputMode.FOCUSED &&
-                prePopInputMode != Shell.StageInputMode.FULLSCREEN)
-                global.set_stage_input_mode(Shell.StageInputMode.FOCUSED);
-        }
-
-        global.screen.focus_default_window(global.display.get_current_time_roundtrip());
-    },
-
     // ignoreRelease:
     //
     // Make sure that the next button release event evaluated by the
@@ -278,14 +224,6 @@ const GrabHelper = new Lang.Class({
         if (grabStackIndex < 0)
             return;
 
-        // We may get key focus changes when calling onUngrab, which
-        // would cause an extra ungrab() on the next actor in the
-        // stack, which is wrong. Ignore key focus changes during the
-        // ungrab, and restore the saved key focus ourselves afterwards.
-        // We use a count as ungrab() may be re-entrant, as onUngrab()
-        // may ungrab additional actors.
-        this._isUngrabbingCount++;
-
         let focus = global.stage.key_focus;
         let hadFocus = focus && this._isWithinGrabbedActor(focus);
 
@@ -302,9 +240,6 @@ const GrabHelper = new Lang.Class({
 
             if (poppedGrab.modal)
                 this._releaseModalGrab();
-
-            if (poppedGrab.grabFocus)
-                this._releaseFocusGrab();
         }
 
         if (!this.grabbed && this._capturedEventId > 0) {
@@ -319,8 +254,6 @@ const GrabHelper = new Lang.Class({
             if (poppedGrab.savedFocus)
                 poppedGrab.savedFocus.grab_key_focus();
         }
-
-        this._isUngrabbingCount--;
     },
 
     _onCapturedEvent: function(actor, event) {
@@ -341,9 +274,6 @@ const GrabHelper = new Lang.Class({
             return true;
         }
 
-        if (!button && this._modalCount == 0)
-            return false;
-
         if (this._isWithinGrabbedActor(event.get_source()))
             return false;
 
@@ -360,21 +290,6 @@ const GrabHelper = new Lang.Class({
             return true;
         }
 
-        return this._modalCount > 0;
-    },
-
-    _onKeyFocusChanged: function() {
-        if (this._isUngrabbingCount > 0)
-            return;
-
-        let focus = global.stage.key_focus;
-        if (!focus || !this._isWithinGrabbedActor(focus))
-            this.ungrab({ isUser: true });
+        return true;
     },
-
-    _focusWindowChanged: function() {
-        let metaDisplay = global.screen.get_display();
-        if (metaDisplay.focus_window != null)
-            this.ungrab({ isUser: true });
-    }
 });
diff --git a/js/ui/messageTray.js b/js/ui/messageTray.js
index afbcf26..3bd15c3 100644
--- a/js/ui/messageTray.js
+++ b/js/ui/messageTray.js
@@ -97,6 +97,65 @@ function _fixMarkup(text, allowMarkup) {
     return GLib.markup_escape_text(text, -1);
 }
 
+const FocusGrabber = new Lang.Class({
+    Name: 'FocusGrabber',
+
+    _init: function(actor) {
+        this._actor = actor;
+        this._prevKeyFocusActor = null;
+        this._focusActorChangedId = 0;
+        this._focused = false;
+    },
+
+    grabFocus: function() {
+        if (this._focused)
+            return;
+
+        this._prevFocusedWindow = global.display.focus_window;
+        this._prevKeyFocusActor = global.stage.get_key_focus();
+
+        this._focusActorChangedId = global.stage.connect('notify::key-focus', Lang.bind(this, 
this._focusActorChanged));
+
+        if (!this._actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false))
+            this._actor.grab_key_focus();
+
+        this._focused = true;
+    },
+
+    _focusUngrabbed: function() {
+        if (!this._focused)
+            return false;
+
+        if (this._focusActorChangedId > 0) {
+            global.stage.disconnect(this._focusActorChangedId);
+            this._focusActorChangedId = 0;
+        }
+
+        this._focused = false;
+        return true;
+    },
+
+    _focusActorChanged: function() {
+        let focusedActor = global.stage.get_key_focus();
+        if (!focusedActor || !this._actor.contains(focusedActor))
+            this._focusUngrabbed();
+    },
+
+    ungrabFocus: function() {
+        if (!this._focusUngrabbed())
+            return;
+
+        if (this._prevKeyFocusActor) {
+            global.stage.set_key_focus(this._prevKeyFocusActor);
+            this._prevKeyFocusActor = null;
+        } else {
+            let focusedActor = global.stage.get_key_focus();
+            if (focusedActor && this._actor.contains(focusedActor))
+                global.stage.set_key_focus(null);
+        }
+    }
+});
+
 const URLHighlighter = new Lang.Class({
     Name: 'URLHighlighter',
 
@@ -1574,6 +1633,7 @@ const MessageTray = new Lang.Class({
         this._notificationBin.set_y_align(Clutter.ActorAlign.START);
         this._notificationWidget.add_actor(this._notificationBin);
         this._notificationWidget.hide();
+        this._notificationFocusGrabber = new FocusGrabber(this._notificationWidget);
         this._notificationQueue = [];
         this._notification = null;
         this._notificationClickedId = 0;
@@ -1623,7 +1683,6 @@ const MessageTray = new Lang.Class({
                                                      { keybindingMode: Shell.KeyBindingMode.MESSAGE_TRAY });
         this._grabHelper.addActor(this._summaryBoxPointer.actor);
         this._grabHelper.addActor(this.actor);
-        this._grabHelper.addActor(this._notificationWidget);
 
         Main.layoutManager.connect('keyboard-visible-changed', Lang.bind(this, 
this._onKeyboardVisibleChanged));
 
@@ -2520,19 +2579,7 @@ const MessageTray = new Lang.Class({
     },
 
     _hideNotification: function() {
-        // HACK!
-        // There seems to be a reentrancy issue in calling .ungrab() here,
-        // which causes _updateState to be called before _notificationState
-        // becomes HIDING. That hides the notification again, nullifying the
-        // object but not setting _notificationState (and that's the weird part)
-        // As then _notificationState is stuck into SHOWN but _notification
-        // is null, every new _updateState fails and the message tray is
-        // lost forever.
-        //
-        // See more at https://bugzilla.gnome.org/show_bug.cgi?id=683986
-        this._notificationState = State.HIDING;
-
-        this._grabHelper.ungrab({ actor: this._notification.actor });
+        this._notificationFocusGrabber.ungrabFocus();
 
         if (this._notificationExpandedId) {
             this._notification.disconnect(this._notificationExpandedId);
@@ -2630,8 +2677,7 @@ const MessageTray = new Lang.Class({
     },
 
     _ensureNotificationFocused: function() {
-        this._grabHelper.grab({ actor: this._notification.actor,
-                                grabFocus: true });
+        this._notificationFocusGrabber.grabFocus();
     },
 
     _onSourceDoneDisplayingContent: function(source, closeTray) {


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