From 8d9aa6388dec6ce2c9b7d87c30c594481ce30e53 Mon Sep 17 00:00:00 2001 From: "Jasper St. Pierre" Date: Fri, 16 Aug 2013 20:11:36 -0400 Subject: [PATCH] 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 --- js/ui/grabHelper.js | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/js/ui/grabHelper.js b/js/ui/grabHelper.js index 296ce46f7..b022d1d6b 100644 --- a/js/ui/grabHelper.js +++ b/js/ui/grabHelper.js @@ -10,6 +10,31 @@ const St = imports.gi.St; const Main = imports.ui.main; 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: // @owner: the actor that owns the GrabHelper // @params: optional parameters to pass to Main.pushModal() @@ -31,7 +56,6 @@ const GrabHelper = new Lang.Class({ this._grabStack = []; this._actors = []; - this._capturedEventId = 0; this._ignoreRelease = false; this._modalCount = 0; @@ -177,7 +201,7 @@ const GrabHelper = new Lang.Class({ if (!Main.pushModal(this._owner, this._modalParams)) return false; - this._capturedEventId = global.stage.connect('captured-event', Lang.bind(this, this._onCapturedEvent)); + _pushGrabHelper(this); } this._modalCount++; @@ -189,8 +213,7 @@ const GrabHelper = new Lang.Class({ if (this._modalCount > 0) return; - global.stage.disconnect(this._capturedEventId); - this._capturedEventId = 0; + _popGrabHelper(this); this._ignoreRelease = false; @@ -251,7 +274,7 @@ const GrabHelper = new Lang.Class({ } }, - _onCapturedEvent: function(actor, event) { + onCapturedEvent: function(event) { let type = event.type(); if (type == Clutter.EventType.KEY_PRESS &&