[gnome-shell] popup-menu: Add support for child menus
- From: Florian MÃllner <fmuellner src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] popup-menu: Add support for child menus
- Date: Mon, 29 Aug 2011 20:11:59 +0000 (UTC)
commit 5d2b7e2c9e2de78455c815d2caafc0738250e292
Author: Florian MÃllner <fmuellner gnome org>
Date: Tue Jul 12 21:47:37 2011 +0200
popup-menu: Add support for child menus
Allow opening a popup menu from another menu. While the child menu
is open, events on the parent menu are blocked. The parent menu
is kept open when the child menu is closed; the child menu on the
other hand is closed with the parent, e.g. when the focus moves
to another toplevel menu.
This feature will be used to implement combo box menu items.
https://bugzilla.gnome.org/show_bug.cgi?id=652837
js/ui/popupMenu.js | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 67 insertions(+), 1 deletions(-)
---
diff --git a/js/ui/popupMenu.js b/js/ui/popupMenu.js
index 7b28108..ecc5ec1 100644
--- a/js/ui/popupMenu.js
+++ b/js/ui/popupMenu.js
@@ -800,6 +800,7 @@ PopupMenuBase.prototype = {
this.passEvents = false;
this._activeMenuItem = null;
+ this._childMenus = [];
},
addAction: function(title, callback) {
@@ -831,6 +832,28 @@ PopupMenuBase.prototype = {
return menuItem;
},
+ isChildMenu: function(menu) {
+ return this._childMenus.indexOf(menu) != -1;
+ },
+
+ addChildMenu: function(menu) {
+ if (this.isChildMenu(menu))
+ return;
+
+ this._childMenus.push(menu);
+ this.emit('child-menu-added', menu);
+ },
+
+ removeChildMenu: function(menu) {
+ let index = this._childMenus.indexOf(menu);
+
+ if (index == -1)
+ return;
+
+ this._childMenus.splice(index, 1);
+ this.emit('child-menu-removed', menu);
+ },
+
/**
* _connectSubMenuSignals:
* @object: a menu item, or a menu section
@@ -1400,6 +1423,7 @@ PopupMenuManager.prototype = {
this._keyFocusNotifyId = 0;
this._activeMenu = null;
this._menus = [];
+ this._menuStack = [];
this._preGrabInputMode = null;
this._grabbedFromKeynav = false;
},
@@ -1408,6 +1432,8 @@ PopupMenuManager.prototype = {
let menudata = {
menu: menu,
openStateChangeId: menu.connect('open-state-changed', Lang.bind(this, this._onMenuOpenState)),
+ childMenuAddedId: menu.connect('child-menu-added', Lang.bind(this, this._onChildMenuAdded)),
+ childMenuRemovedId: menu.connect('child-menu-removed', Lang.bind(this, this._onChildMenuRemoved)),
destroyId: menu.connect('destroy', Lang.bind(this, this._onMenuDestroy)),
enterId: 0,
focusInId: 0
@@ -1435,6 +1461,8 @@ PopupMenuManager.prototype = {
let menudata = this._menus[position];
menu.disconnect(menudata.openStateChangeId);
+ menu.disconnect(menudata.childMenuAddedId);
+ menu.disconnect(menudata.childMenuRemovedId);
menu.disconnect(menudata.destroyId);
if (menudata.enterId)
@@ -1472,8 +1500,20 @@ PopupMenuManager.prototype = {
},
_onMenuOpenState: function(menu, open) {
- if (open)
+ if (open) {
+ if (this._activeMenu && this._activeMenu.isChildMenu(menu)) {
+ this._menuStack.push(this._activeMenu);
+ menu.actor.grab_key_focus();
+ }
this._activeMenu = 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;
@@ -1506,6 +1546,14 @@ PopupMenuManager.prototype = {
}
},
+ _onChildMenuAdded: function(menu, childMenu) {
+ this.addMenu(childMenu);
+ },
+
+ _onChildMenuRemoved: function(menu, childMenu) {
+ this.removeMenu(childMenu);
+ },
+
// change the currently-open menu without dropping grab
_changeMenu: function(newMenu) {
if (this._activeMenu) {
@@ -1514,6 +1562,8 @@ PopupMenuManager.prototype = {
// 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(false);
oldMenu.close(false);
newMenu.open(false);
} else
@@ -1524,6 +1574,15 @@ PopupMenuManager.prototype = {
if (!this.grabbed || menu == this._activeMenu)
return false;
+ if (this._activeMenu && this._activeMenu.isChildMenu(menu))
+ return false;
+
+ if (this._menuStack.indexOf(menu) != -1)
+ return false;
+
+ if (this._menuStack.length > 0 && this._menuStack[0].isChildMenu(menu))
+ return false;
+
this._changeMenu(menu);
return false;
},
@@ -1536,6 +1595,8 @@ PopupMenuManager.prototype = {
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;
@@ -1594,6 +1655,11 @@ PopupMenuManager.prototype = {
if (this._activeMenu != null && this._activeMenu.passEvents)
return false;
+ if (this._didPop) {
+ this._didPop = false;
+ return true;
+ }
+
let activeMenuContains = this._eventIsOnActiveMenu(event);
let eventType = event.type();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]