From d8df46d4a1e00ff463fa4842605f80875c7f9b37 Mon Sep 17 00:00:00 2001 From: Giovanni Campagna Date: Fri, 25 Jun 2010 14:55:03 +0200 Subject: [PATCH] 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 file changed, 46 insertions(+), 8 deletions(-) diff --git a/js/ui/popupMenu.js b/js/ui/popupMenu.js index 2826edd0f..ac569f7e0 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();