[gnome-shell] grabHelper: Introduce a stack of grab helpers



commit 8d9aa6388dec6ce2c9b7d87c30c594481ce30e53
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Fri Aug 16 20:11:36 2013 -0400

    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 files changed, 28 insertions(+), 5 deletions(-)
---
diff --git a/js/ui/grabHelper.js b/js/ui/grabHelper.js
index 296ce46..b022d1d 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 &&


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]