grabHelper: Introduce a stack of grab helpers
GrabHelpers use a 'captured-event' to steal events and emulate modality or grab-like semantics. There can be issues when you try to use multiple GrabHelpers stacked on each other. As Clutter follows the DOM-like semantics of "first come, first serve", when a second GrabHelper connects to 'captured-event', its callback will only be processed *after* the first GrabHelper's callback is called. This breaks the expectation of narrowing modality where new modals take priority over the old ones. Solving this globally in a cleaner manner would require a rewrite of pushModal/GrabHelper. As a stopgap fix for now, use one shared 'captured-event' handler between all GrabHelper instances, and delegate to the individual GrabHelpers. https://bugzilla.gnome.org/show_bug.cgi?id=699272
This commit is contained in:
parent
6d317d300c
commit
8d9aa6388d
@ -10,6 +10,31 @@ const St = imports.gi.St;
|
|||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
|
|
||||||
|
let _capturedEventId = 0;
|
||||||
|
let _grabHelperStack = [];
|
||||||
|
function _onCapturedEvent(actor, event) {
|
||||||
|
let grabHelper = _grabHelperStack[_grabHelperStack.length - 1];
|
||||||
|
return grabHelper.onCapturedEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _pushGrabHelper(grabHelper) {
|
||||||
|
_grabHelperStack.push(grabHelper);
|
||||||
|
|
||||||
|
if (_capturedEventId == 0)
|
||||||
|
_capturedEventId = global.stage.connect('captured-event', _onCapturedEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _popGrabHelper(grabHelper) {
|
||||||
|
let poppedHelper = _grabHelperStack.pop();
|
||||||
|
if (poppedHelper != grabHelper)
|
||||||
|
throw new Error("incorrect grab helper pop");
|
||||||
|
|
||||||
|
if (_grabHelperStack.length == 0) {
|
||||||
|
global.stage.disconnect(_capturedEventId);
|
||||||
|
_capturedEventId = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GrabHelper:
|
// GrabHelper:
|
||||||
// @owner: the actor that owns the GrabHelper
|
// @owner: the actor that owns the GrabHelper
|
||||||
// @params: optional parameters to pass to Main.pushModal()
|
// @params: optional parameters to pass to Main.pushModal()
|
||||||
@ -31,7 +56,6 @@ const GrabHelper = new Lang.Class({
|
|||||||
this._grabStack = [];
|
this._grabStack = [];
|
||||||
|
|
||||||
this._actors = [];
|
this._actors = [];
|
||||||
this._capturedEventId = 0;
|
|
||||||
this._ignoreRelease = false;
|
this._ignoreRelease = false;
|
||||||
|
|
||||||
this._modalCount = 0;
|
this._modalCount = 0;
|
||||||
@ -177,7 +201,7 @@ const GrabHelper = new Lang.Class({
|
|||||||
if (!Main.pushModal(this._owner, this._modalParams))
|
if (!Main.pushModal(this._owner, this._modalParams))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
this._capturedEventId = global.stage.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
|
_pushGrabHelper(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._modalCount++;
|
this._modalCount++;
|
||||||
@ -189,8 +213,7 @@ const GrabHelper = new Lang.Class({
|
|||||||
if (this._modalCount > 0)
|
if (this._modalCount > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
global.stage.disconnect(this._capturedEventId);
|
_popGrabHelper(this);
|
||||||
this._capturedEventId = 0;
|
|
||||||
|
|
||||||
this._ignoreRelease = false;
|
this._ignoreRelease = false;
|
||||||
|
|
||||||
@ -251,7 +274,7 @@ const GrabHelper = new Lang.Class({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_onCapturedEvent: function(actor, event) {
|
onCapturedEvent: function(event) {
|
||||||
let type = event.type();
|
let type = event.type();
|
||||||
|
|
||||||
if (type == Clutter.EventType.KEY_PRESS &&
|
if (type == Clutter.EventType.KEY_PRESS &&
|
||||||
|
Loading…
Reference in New Issue
Block a user