[gnome-shell] popupMenu: Port to GrabHelper



commit 9dfc3af9d7760634f390113e8867d903d6ee0a52
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Wed Feb 29 19:09:41 2012 -0500

    popupMenu: Port to GrabHelper
    
    https://bugzilla.gnome.org/show_bug.cgi?id=689109

 js/ui/appDisplay.js |    1 +
 js/ui/grabHelper.js |   13 +++-
 js/ui/popupMenu.js  |  226 ++++++++-------------------------------------------
 3 files changed, 46 insertions(+), 194 deletions(-)
---
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
index c7250e1..944b246 100644
--- a/js/ui/appDisplay.js
+++ b/js/ui/appDisplay.js
@@ -567,6 +567,7 @@ const AppWellIcon = new Lang.Class({
 
         this.actor.set_hover(true);
         this._menu.popup();
+        this._menuManager.ignoreRelease();
 
         return false;
     },
diff --git a/js/ui/grabHelper.js b/js/ui/grabHelper.js
index 27e1e58..6e1c54c 100644
--- a/js/ui/grabHelper.js
+++ b/js/ui/grabHelper.js
@@ -92,6 +92,14 @@ const GrabHelper = new Lang.Class({
         return this._grabStack[this._grabStack.length - 1] || {};
     },
 
+    get grabbed() {
+        return this._grabStack.length > 0;
+    },
+
+    get grabStack() {
+        return this._grabStack;
+    },
+
     _findStackIndex: function(actor) {
         if (!actor)
             return -1;
@@ -152,6 +160,7 @@ const GrabHelper = new Lang.Class({
         params = Params.parse(params, { actor: null,
                                         modal: false,
                                         grabFocus: false,
+                                        focus: null,
                                         onUngrab: null });
 
         let focus = global.stage.key_focus;
@@ -169,7 +178,9 @@ const GrabHelper = new Lang.Class({
         if (params.grabFocus && !this._takeFocusGrab(hadFocus))
             return false;
 
-        if (hadFocus || params.grabFocus)
+        if (params.focus)
+            params.focus.grab_key_focus();
+        else if (hadFocus || params.grabFocus)
             _navigateActor(newFocus);
 
         this._grabStack.push(params);
diff --git a/js/ui/popupMenu.js b/js/ui/popupMenu.js
index a469388..a50264e 100644
--- a/js/ui/popupMenu.js
+++ b/js/ui/popupMenu.js
@@ -12,6 +12,7 @@ const St = imports.gi.St;
 const Atk = imports.gi.Atk;
 
 const BoxPointer = imports.ui.boxpointer;
+const GrabHelper = imports.ui.grabHelper;
 const Main = imports.ui.main;
 const Params = imports.misc.params;
 const Tweener = imports.ui.tweener;
@@ -1204,7 +1205,6 @@ const PopupMenu = new Lang.Class({
         this.actor = this._boxPointer.actor;
         this.actor._delegate = this;
         this.actor.style_class = 'popup-menu-boxpointer';
-        this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
 
         this._boxWrapper = new Shell.GenericContainer();
         this._boxWrapper.connect('get-preferred-width', Lang.bind(this, this._boxGetPreferredWidth));
@@ -1234,15 +1234,6 @@ const PopupMenu = new Lang.Class({
         this.box.allocate(box, flags);
     },
 
-    _onKeyPressEvent: function(actor, event) {
-        if (event.get_key_symbol() == Clutter.Escape) {
-            this.close(BoxPointer.PopupAnimation.FULL);
-            return true;
-        }
-
-        return false;
-    },
-
     setArrowOrigin: function(origin) {
         this._boxPointer.setArrowOrigin(origin);
     },
@@ -1537,7 +1528,6 @@ const PopupComboMenu = new Lang.Class({
 
         this.actor = this.box;
         this.actor._delegate = this;
-        this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
         this.actor.connect('key-focus-in', Lang.bind(this, this._onKeyFocusIn));
         sourceActor.connect('style-changed',
                             Lang.bind(this, this._onSourceActorStyleChanged));
@@ -1545,15 +1535,6 @@ const PopupComboMenu = new Lang.Class({
         global.focus_manager.add_group(this.actor);
     },
 
-    _onKeyPressEvent: function(actor, event) {
-        if (event.get_key_symbol() == Clutter.Escape) {
-            this.close(BoxPointer.PopupAnimation.FULL);
-            return true;
-        }
-
-        return false;
-    },
-
     _onKeyFocusIn: function(actor) {
         let items = this._getMenuItems();
         let activeItem = items[this._activeItemPos];
@@ -2044,17 +2025,8 @@ const PopupMenuManager = new Lang.Class({
 
     _init: function(owner) {
         this._owner = owner;
-        this.grabbed = false;
-
-        this._eventCaptureId = 0;
-        this._enterEventId = 0;
-        this._leaveEventId = 0;
-        this._keyFocusNotifyId = 0;
-        this._activeMenu = null;
+        this._grabHelper = new GrabHelper.GrabHelper(owner.actor);
         this._menus = [];
-        this._menuStack = [];
-        this._preGrabInputMode = null;
-        this._grabbedFromKeynav = false;
     },
 
     addMenu: function(menu, position) {
@@ -2073,6 +2045,8 @@ const PopupMenuManager = new Lang.Class({
 
         let source = menu.sourceActor;
         if (source) {
+            if (!menu.blockSourceEvents)
+                this._grabHelper.addActor(source);
             menudata.enterId = source.connect('enter-event', Lang.bind(this, function() { this._onMenuSourceEnter(menu); }));
             menudata.focusInId = source.connect('key-focus-in', Lang.bind(this, function() { this._onMenuSourceEnter(menu); }));
         }
@@ -2085,7 +2059,7 @@ const PopupMenuManager = new Lang.Class({
 
     removeMenu: function(menu) {
         if (menu == this._activeMenu)
-            this._closeMenu();
+            this._closeMenu(menu);
 
         let position = this._findMenu(menu);
         if (position == -1) // not a menu we manage
@@ -2102,79 +2076,29 @@ const PopupMenuManager = new Lang.Class({
         if (menudata.focusInId)
             menu.sourceActor.disconnect(menudata.focusInId);
 
+        if (menu.sourceActor)
+            this._grabHelper.removeActor(menu.sourceActor);
         this._menus.splice(position, 1);
     },
 
-    _grab: function() {
-        Main.pushModal(this._owner.actor);
-
-        this._eventCaptureId = global.stage.connect('captured-event', Lang.bind(this, this._onEventCapture));
-        // captured-event doesn't see enter/leave events
-        this._enterEventId = global.stage.connect('enter-event', Lang.bind(this, this._onEventCapture));
-        this._leaveEventId = global.stage.connect('leave-event', Lang.bind(this, this._onEventCapture));
-        this._keyFocusNotifyId = global.stage.connect('notify::key-focus', Lang.bind(this, this._onKeyFocusChanged));
-
-        this.grabbed = true;
+    get activeMenu() {
+        let actor = this._grabHelper.currentGrab.actor;
+        if (actor)
+            return actor._delegate;
+        else
+            return null;
     },
 
-    _ungrab: function() {
-        global.stage.disconnect(this._eventCaptureId);
-        this._eventCaptureId = 0;
-        global.stage.disconnect(this._enterEventId);
-        this._enterEventId = 0;
-        global.stage.disconnect(this._leaveEventId);
-        this._leaveEventId = 0;
-        global.stage.disconnect(this._keyFocusNotifyId);
-        this._keyFocusNotifyId = 0;
-
-        this.grabbed = false;
-        Main.popModal(this._owner.actor);
+    ignoreRelease: function() {
+        return this._grabHelper.ignoreRelease();
     },
 
     _onMenuOpenState: function(menu, open) {
         if (open) {
-            if (this._activeMenu && this._activeMenu.isChildMenu(menu)) {
-                this._menuStack.push(this._activeMenu);
-                menu.actor.grab_key_focus();
-            }
-            this._activeMenu = menu;
+            this._grabHelper.grab({ actor: menu.actor, modal: true, focus: menu.sourceActor,
+                                    onUngrab: Lang.bind(this, this._closeMenu, menu) });
         } else {
-            if (this._menuStack.length > 0) {
-                this._activeMenu = this._menuStack.pop();
-                if (menu.sourceActor)
-                    menu.sourceActor.grab_key_focus();
-                this._didPop = true;
-            }
-        }
-
-        // Check what the focus was before calling pushModal/popModal
-        let focus = global.stage.key_focus;
-        let hadFocus = focus && this._activeMenuContains(focus);
-
-        if (open) {
-            if (!this.grabbed) {
-                this._preGrabInputMode = global.stage_input_mode;
-                this._grabbedFromKeynav = hadFocus;
-                this._grab();
-            }
-
-            if (hadFocus)
-                focus.grab_key_focus();
-            else
-                menu.actor.grab_key_focus();
-        } else if (menu == this._activeMenu) {
-            if (this.grabbed)
-                this._ungrab();
-            this._activeMenu = null;
-
-            if (this._grabbedFromKeynav) {
-                if (this._preGrabInputMode == Shell.StageInputMode.FOCUSED)
-                    global.stage_input_mode = Shell.StageInputMode.FOCUSED;
-                if (hadFocus && menu.sourceActor)
-                    menu.sourceActor.grab_key_focus();
-                else if (focus)
-                    focus.grab_key_focus();
-            }
+            this._grabHelper.ungrab({ actor: menu.actor });
         }
     },
 
@@ -2186,87 +2110,37 @@ const PopupMenuManager = new Lang.Class({
         this.removeMenu(childMenu);
     },
 
-    // change the currently-open menu without dropping grab
     _changeMenu: function(newMenu) {
-        if (this._activeMenu) {
-            // _onOpenMenuState will drop the grab if it sees
-            // this._activeMenu being closed; so clear _activeMenu
-            // before closing it to keep that from happening
-            let oldMenu = this._activeMenu;
-            this._activeMenu = null;
-            for (let i = this._menuStack.length - 1; i >= 0; i--)
-                this._menuStack[i].close(BoxPointer.PopupAnimation.FADE);
-            oldMenu.close(BoxPointer.PopupAnimation.FADE);
-            newMenu.open(BoxPointer.PopupAnimation.FADE);
-        } else
-            newMenu.open(BoxPointer.PopupAnimation.FULL);
+        if (this.activeMenu) {
+            this._closeMenu(this.activeMenu);
+            newMenu.open(false);
+        } else {
+            newMenu.open(true);
+        }
     },
 
     _onMenuSourceEnter: function(menu) {
-        if (!this.grabbed || menu == this._activeMenu)
+        if (!this._grabHelper.grabbed)
             return false;
 
-        if (this._activeMenu && this._activeMenu.isChildMenu(menu))
+        if (this._grabHelper.isActorGrabbed(menu.actor))
             return false;
 
-        if (this._menuStack.indexOf(menu) != -1)
-            return false;
-
-        if (this._menuStack.length > 0 && this._menuStack[0].isChildMenu(menu))
+        let isChildMenu = this._grabHelper.grabStack.some(function(grab) {
+            let existingMenu = grab.actor._delegate;
+            return existingMenu.isChildMenu(menu);
+        });
+        if (isChildMenu)
             return false;
 
         this._changeMenu(menu);
         return false;
     },
 
-    _onKeyFocusChanged: function() {
-        if (!this.grabbed || !this._activeMenu)
-            return;
-
-        let focus = global.stage.key_focus;
-        if (focus) {
-            if (this._activeMenuContains(focus))
-                return;
-            if (this._menuStack.length > 0)
-                return;
-            if (focus._delegate && focus._delegate.menu &&
-                this._findMenu(focus._delegate.menu) != -1)
-                return;
-        }
-
-        this._closeMenu();
-    },
-
     _onMenuDestroy: function(menu) {
         this.removeMenu(menu);
     },
 
-    _activeMenuContains: function(actor) {
-        return this._activeMenu != null
-                && (this._activeMenu.actor.contains(actor) ||
-                    (this._activeMenu.sourceActor && this._activeMenu.sourceActor.contains(actor)));
-    },
-
-    _eventIsOnActiveMenu: function(event) {
-        return this._activeMenuContains(event.get_source());
-    },
-
-    _shouldBlockEvent: function(event) {
-        let src = event.get_source();
-
-        if (this._activeMenu != null && this._activeMenu.actor.contains(src))
-            return false;
-
-        for (let i = 0; i < this._menus.length; i++) {
-            let menu = this._menus[i].menu;
-            if (menu.sourceActor && !menu.blockSourceEvents && menu.sourceActor.contains(src)) {
-                return false;
-            }
-        }
-
-        return true;
-    },
-
     _findMenu: function(item) {
         for (let i = 0; i < this._menus.length; i++) {
             let menudata = this._menus[i];
@@ -2276,41 +2150,7 @@ const PopupMenuManager = new Lang.Class({
         return -1;
     },
 
-    _onEventCapture: function(actor, event) {
-        if (!this.grabbed)
-            return false;
-
-        if (this._owner.menuEventFilter &&
-            this._owner.menuEventFilter(event))
-            return true;
-
-        if (this._didPop) {
-            this._didPop = false;
-            return true;
-        }
-
-        let activeMenuContains = this._eventIsOnActiveMenu(event);
-        let eventType = event.type();
-
-        if (eventType == Clutter.EventType.BUTTON_RELEASE) {
-            if (activeMenuContains) {
-                return false;
-            } else {
-                this._closeMenu();
-                return true;
-            }
-        } else if (eventType == Clutter.EventType.BUTTON_PRESS && !activeMenuContains) {
-            this._closeMenu();
-            return true;
-        } else if (!this._shouldBlockEvent(event)) {
-            return false;
-        }
-
-        return true;
-    },
-
-    _closeMenu: function() {
-        if (this._activeMenu != null)
-            this._activeMenu.close(BoxPointer.PopupAnimation.FULL);
+    _closeMenu: function(menu) {
+        menu.close(BoxPointer.PopupAnimation.FULL);
     }
 });



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