[gnome-shell] Enable insertion and removal of menus



commit d8df46d4a1e00ff463fa4842605f80875c7f9b37
Author: Giovanni Campagna <scampa giovanni gmail com>
Date:   Fri Jun 25 14:55:03 2010 +0200

    Enable insertion and removal of menus
    
    This patch adds the method "removeMenu" to PopupMenuManager, to allow
    for removal of menus after they're inserted. In order to do this, it
    needs to store along with the menu all the relevant signal connections,
    that are disconnected when the menu is removed.
    Also adds a parameter "position" to "addMenu", so that menus can added
    in arbitrary order (in particular to reintroduce those which were removed).
    This patch is intended towards dynamic menu users, like extensions for
    application lists, docks, sidebars showing recent documents or favourites,
    as well as advanced system tray implementations.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=622730

 js/ui/popupMenu.js |   54 ++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 46 insertions(+), 8 deletions(-)
---
diff --git a/js/ui/popupMenu.js b/js/ui/popupMenu.js
index 2826edd..ac569f7 100644
--- a/js/ui/popupMenu.js
+++ b/js/ui/popupMenu.js
@@ -429,17 +429,45 @@ PopupMenuManager.prototype = {
         this._delayedMenus = [];
     },
 
-    addMenu: function(menu, noGrab) {
-        this._menus.push(menu);
-        menu.connect('open-state-changed', Lang.bind(this, this._onMenuOpenState));
-        menu.connect('activate', Lang.bind(this, this._onMenuActivated));
+    addMenu: function(menu, noGrab, position) {
+        let menudata = {
+            menu:              menu,
+            openStateChangeId: menu.connect('open-state-changed', Lang.bind(this, this._onMenuOpenState)),
+            activateId:        menu.connect('activate', Lang.bind(this, this._onMenuActivated)),
+            enterId:           0,
+            buttonPressId:     0
+        };
 
         let source = menu.sourceActor;
         if (source) {
-            source.connect('enter-event', Lang.bind(this, this._onMenuSourceEnter, menu));
+            menudata.enterId = source.connect('enter-event', Lang.bind(this, this._onMenuSourceEnter, menu));
             if (!noGrab)
-                source.connect('button-press-event', Lang.bind(this, this._onMenuSourcePress, menu));
+                menudata.buttonPressId = source.connect('button-press-event', Lang.bind(this, this._onMenuSourcePress, menu));
         }
+
+        if (position == undefined)
+            this._menus.push(menudata);
+        else
+            this._menus.splice(position, 0, menudata);
+    },
+
+    removeMenu: function(menu) {
+        if (menu == this._activeMenu)
+            this._closeMenu();
+        let position = this._findMenu(menu);
+        if (position == -1) // not a menu we manage
+            return;
+
+        let menudata = this._menus[position];
+        menu.disconnect(menudata.openStateChangeId);
+        menu.disconnect(menudata.activateId);
+
+        if (menudata.enterId)
+            menu.sourceActor.disconnect(menudata.enterId);
+        if (menudata.buttonPressId)
+            menu.sourceActor.disconnect(menudata.buttonPressId);
+
+        this._menus.splice(position, 1);
     },
 
     grab: function() {
@@ -505,13 +533,22 @@ PopupMenuManager.prototype = {
     _eventIsOnAnyMenuSource: function(event) {
         let src = event.get_source();
         for (let i = 0; i < this._menus.length; i++) {
-            let menu = this._menus[i];
+            let menu = this._menus[i].menu;
             if (menu.sourceActor && menu.sourceActor.contains(src))
                 return true;
         }
         return false;
     },
 
+    _findMenu: function(item) {
+        for (let i = 0; i < this._menus.length; i++) {
+            let menudata = this._menus[i];
+            if (item == menudata.menu)
+                return i;
+        }
+        return -1;
+    },
+
     _onEventCapture: function(actor, event) {
         if (!this.grabbed)
             return false;
@@ -542,7 +579,8 @@ PopupMenuManager.prototype = {
                    && (event.get_key_symbol() == Clutter.Left
                        || event.get_key_symbol() == Clutter.Right)) {
             let direction = event.get_key_symbol() == Clutter.Right ? 1 : -1;
-            let next = findNextInCycle(this._menus, this._activeMenu, direction);
+            let pos = this._findMenu(this._activeMenu);
+            let next = this._menus[mod(pos + direction, this._menus.length)].menu;
             if (next != this._activeMenu) {
                 this._activeMenu.close();
                 next.open();



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