popupMenu: Port to GrabHelper
https://bugzilla.gnome.org/show_bug.cgi?id=689109
This commit is contained in:
parent
8dc63932fc
commit
9dfc3af9d7
@ -567,6 +567,7 @@ const AppWellIcon = new Lang.Class({
|
|||||||
|
|
||||||
this.actor.set_hover(true);
|
this.actor.set_hover(true);
|
||||||
this._menu.popup();
|
this._menu.popup();
|
||||||
|
this._menuManager.ignoreRelease();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
@ -92,6 +92,14 @@ const GrabHelper = new Lang.Class({
|
|||||||
return this._grabStack[this._grabStack.length - 1] || {};
|
return this._grabStack[this._grabStack.length - 1] || {};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
get grabbed() {
|
||||||
|
return this._grabStack.length > 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
get grabStack() {
|
||||||
|
return this._grabStack;
|
||||||
|
},
|
||||||
|
|
||||||
_findStackIndex: function(actor) {
|
_findStackIndex: function(actor) {
|
||||||
if (!actor)
|
if (!actor)
|
||||||
return -1;
|
return -1;
|
||||||
@ -152,6 +160,7 @@ const GrabHelper = new Lang.Class({
|
|||||||
params = Params.parse(params, { actor: null,
|
params = Params.parse(params, { actor: null,
|
||||||
modal: false,
|
modal: false,
|
||||||
grabFocus: false,
|
grabFocus: false,
|
||||||
|
focus: null,
|
||||||
onUngrab: null });
|
onUngrab: null });
|
||||||
|
|
||||||
let focus = global.stage.key_focus;
|
let focus = global.stage.key_focus;
|
||||||
@ -169,7 +178,9 @@ const GrabHelper = new Lang.Class({
|
|||||||
if (params.grabFocus && !this._takeFocusGrab(hadFocus))
|
if (params.grabFocus && !this._takeFocusGrab(hadFocus))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (hadFocus || params.grabFocus)
|
if (params.focus)
|
||||||
|
params.focus.grab_key_focus();
|
||||||
|
else if (hadFocus || params.grabFocus)
|
||||||
_navigateActor(newFocus);
|
_navigateActor(newFocus);
|
||||||
|
|
||||||
this._grabStack.push(params);
|
this._grabStack.push(params);
|
||||||
|
@ -12,6 +12,7 @@ const St = imports.gi.St;
|
|||||||
const Atk = imports.gi.Atk;
|
const Atk = imports.gi.Atk;
|
||||||
|
|
||||||
const BoxPointer = imports.ui.boxpointer;
|
const BoxPointer = imports.ui.boxpointer;
|
||||||
|
const GrabHelper = imports.ui.grabHelper;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
@ -1204,7 +1205,6 @@ const PopupMenu = new Lang.Class({
|
|||||||
this.actor = this._boxPointer.actor;
|
this.actor = this._boxPointer.actor;
|
||||||
this.actor._delegate = this;
|
this.actor._delegate = this;
|
||||||
this.actor.style_class = 'popup-menu-boxpointer';
|
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 = new Shell.GenericContainer();
|
||||||
this._boxWrapper.connect('get-preferred-width', Lang.bind(this, this._boxGetPreferredWidth));
|
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);
|
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) {
|
setArrowOrigin: function(origin) {
|
||||||
this._boxPointer.setArrowOrigin(origin);
|
this._boxPointer.setArrowOrigin(origin);
|
||||||
},
|
},
|
||||||
@ -1537,7 +1528,6 @@ const PopupComboMenu = new Lang.Class({
|
|||||||
|
|
||||||
this.actor = this.box;
|
this.actor = this.box;
|
||||||
this.actor._delegate = this;
|
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));
|
this.actor.connect('key-focus-in', Lang.bind(this, this._onKeyFocusIn));
|
||||||
sourceActor.connect('style-changed',
|
sourceActor.connect('style-changed',
|
||||||
Lang.bind(this, this._onSourceActorStyleChanged));
|
Lang.bind(this, this._onSourceActorStyleChanged));
|
||||||
@ -1545,15 +1535,6 @@ const PopupComboMenu = new Lang.Class({
|
|||||||
global.focus_manager.add_group(this.actor);
|
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) {
|
_onKeyFocusIn: function(actor) {
|
||||||
let items = this._getMenuItems();
|
let items = this._getMenuItems();
|
||||||
let activeItem = items[this._activeItemPos];
|
let activeItem = items[this._activeItemPos];
|
||||||
@ -2044,17 +2025,8 @@ const PopupMenuManager = new Lang.Class({
|
|||||||
|
|
||||||
_init: function(owner) {
|
_init: function(owner) {
|
||||||
this._owner = owner;
|
this._owner = owner;
|
||||||
this.grabbed = false;
|
this._grabHelper = new GrabHelper.GrabHelper(owner.actor);
|
||||||
|
|
||||||
this._eventCaptureId = 0;
|
|
||||||
this._enterEventId = 0;
|
|
||||||
this._leaveEventId = 0;
|
|
||||||
this._keyFocusNotifyId = 0;
|
|
||||||
this._activeMenu = null;
|
|
||||||
this._menus = [];
|
this._menus = [];
|
||||||
this._menuStack = [];
|
|
||||||
this._preGrabInputMode = null;
|
|
||||||
this._grabbedFromKeynav = false;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
addMenu: function(menu, position) {
|
addMenu: function(menu, position) {
|
||||||
@ -2073,6 +2045,8 @@ const PopupMenuManager = new Lang.Class({
|
|||||||
|
|
||||||
let source = menu.sourceActor;
|
let source = menu.sourceActor;
|
||||||
if (source) {
|
if (source) {
|
||||||
|
if (!menu.blockSourceEvents)
|
||||||
|
this._grabHelper.addActor(source);
|
||||||
menudata.enterId = source.connect('enter-event', Lang.bind(this, function() { this._onMenuSourceEnter(menu); }));
|
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); }));
|
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) {
|
removeMenu: function(menu) {
|
||||||
if (menu == this._activeMenu)
|
if (menu == this._activeMenu)
|
||||||
this._closeMenu();
|
this._closeMenu(menu);
|
||||||
|
|
||||||
let position = this._findMenu(menu);
|
let position = this._findMenu(menu);
|
||||||
if (position == -1) // not a menu we manage
|
if (position == -1) // not a menu we manage
|
||||||
@ -2102,79 +2076,29 @@ const PopupMenuManager = new Lang.Class({
|
|||||||
if (menudata.focusInId)
|
if (menudata.focusInId)
|
||||||
menu.sourceActor.disconnect(menudata.focusInId);
|
menu.sourceActor.disconnect(menudata.focusInId);
|
||||||
|
|
||||||
|
if (menu.sourceActor)
|
||||||
|
this._grabHelper.removeActor(menu.sourceActor);
|
||||||
this._menus.splice(position, 1);
|
this._menus.splice(position, 1);
|
||||||
},
|
},
|
||||||
|
|
||||||
_grab: function() {
|
get activeMenu() {
|
||||||
Main.pushModal(this._owner.actor);
|
let actor = this._grabHelper.currentGrab.actor;
|
||||||
|
if (actor)
|
||||||
this._eventCaptureId = global.stage.connect('captured-event', Lang.bind(this, this._onEventCapture));
|
return actor._delegate;
|
||||||
// captured-event doesn't see enter/leave events
|
else
|
||||||
this._enterEventId = global.stage.connect('enter-event', Lang.bind(this, this._onEventCapture));
|
return null;
|
||||||
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;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_ungrab: function() {
|
ignoreRelease: function() {
|
||||||
global.stage.disconnect(this._eventCaptureId);
|
return this._grabHelper.ignoreRelease();
|
||||||
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);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onMenuOpenState: function(menu, open) {
|
_onMenuOpenState: function(menu, open) {
|
||||||
if (open) {
|
if (open) {
|
||||||
if (this._activeMenu && this._activeMenu.isChildMenu(menu)) {
|
this._grabHelper.grab({ actor: menu.actor, modal: true, focus: menu.sourceActor,
|
||||||
this._menuStack.push(this._activeMenu);
|
onUngrab: Lang.bind(this, this._closeMenu, menu) });
|
||||||
menu.actor.grab_key_focus();
|
|
||||||
}
|
|
||||||
this._activeMenu = menu;
|
|
||||||
} else {
|
} else {
|
||||||
if (this._menuStack.length > 0) {
|
this._grabHelper.ungrab({ actor: menu.actor });
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -2186,87 +2110,37 @@ const PopupMenuManager = new Lang.Class({
|
|||||||
this.removeMenu(childMenu);
|
this.removeMenu(childMenu);
|
||||||
},
|
},
|
||||||
|
|
||||||
// change the currently-open menu without dropping grab
|
|
||||||
_changeMenu: function(newMenu) {
|
_changeMenu: function(newMenu) {
|
||||||
if (this._activeMenu) {
|
if (this.activeMenu) {
|
||||||
// _onOpenMenuState will drop the grab if it sees
|
this._closeMenu(this.activeMenu);
|
||||||
// this._activeMenu being closed; so clear _activeMenu
|
newMenu.open(false);
|
||||||
// before closing it to keep that from happening
|
} else {
|
||||||
let oldMenu = this._activeMenu;
|
newMenu.open(true);
|
||||||
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);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onMenuSourceEnter: function(menu) {
|
_onMenuSourceEnter: function(menu) {
|
||||||
if (!this.grabbed || menu == this._activeMenu)
|
if (!this._grabHelper.grabbed)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (this._activeMenu && this._activeMenu.isChildMenu(menu))
|
if (this._grabHelper.isActorGrabbed(menu.actor))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (this._menuStack.indexOf(menu) != -1)
|
let isChildMenu = this._grabHelper.grabStack.some(function(grab) {
|
||||||
return false;
|
let existingMenu = grab.actor._delegate;
|
||||||
|
return existingMenu.isChildMenu(menu);
|
||||||
if (this._menuStack.length > 0 && this._menuStack[0].isChildMenu(menu))
|
});
|
||||||
|
if (isChildMenu)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
this._changeMenu(menu);
|
this._changeMenu(menu);
|
||||||
return false;
|
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) {
|
_onMenuDestroy: function(menu) {
|
||||||
this.removeMenu(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) {
|
_findMenu: function(item) {
|
||||||
for (let i = 0; i < this._menus.length; i++) {
|
for (let i = 0; i < this._menus.length; i++) {
|
||||||
let menudata = this._menus[i];
|
let menudata = this._menus[i];
|
||||||
@ -2276,41 +2150,7 @@ const PopupMenuManager = new Lang.Class({
|
|||||||
return -1;
|
return -1;
|
||||||
},
|
},
|
||||||
|
|
||||||
_onEventCapture: function(actor, event) {
|
_closeMenu: function(menu) {
|
||||||
if (!this.grabbed)
|
menu.close(BoxPointer.PopupAnimation.FULL);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user