[gnome-shell/wip/rstrode/login-screen-extensions: 107/134] tweener: Save handlers on target and remove them on destroy




commit 11e70e6fcd0aa95fbfae8860d5b3d9e2147ec56c
Author: Marco Trevisan (TreviƱo) <mail 3v1n0 net>
Date:   Tue Dec 5 02:41:50 2017 +0100

    tweener: Save handlers on target and remove them on destroy
    
    Saving handlers we had using the wrapper as a property of the object and delete
    them when resetting the object state.
    Without doing this an handler could be called on a destroyed target when this
    happens on the onComplete callback.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=791233

 js/ui/tweener.js | 63 ++++++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 50 insertions(+), 13 deletions(-)
---
diff --git a/js/ui/tweener.js b/js/ui/tweener.js
index bb9ea557ca..c04cede25f 100644
--- a/js/ui/tweener.js
+++ b/js/ui/tweener.js
@@ -63,30 +63,67 @@ function _getTweenState(target) {
     return target.__ShellTweenerState;
 }
 
+function _ensureHandlers(target) {
+    if (!target.__ShellTweenerHandlers)
+        target.__ShellTweenerHandlers = {};
+    return target.__ShellTweenerHandlers;
+}
+
 function _resetTweenState(target) {
     let state = target.__ShellTweenerState;
 
     if (state) {
-        if (state.destroyedId)
+        if (state.destroyedId) {
             state.actor.disconnect(state.destroyedId);
+            delete state.destroyedId;
+        }
     }
 
+    _removeHandler(target, 'onComplete', _tweenCompleted);
     target.__ShellTweenerState = {};
 }
 
 function _addHandler(target, params, name, handler) {
-    if (params[name]) {
-        let oldHandler = params[name];
-        let oldScope = params[name + 'Scope'];
-        let oldParams = params[name + 'Params'];
-        let eventScope = oldScope ? oldScope : target;
-
-        params[name] = () => {
-            oldHandler.apply(eventScope, oldParams);
-            handler(target);
-        };
-    } else
-        params[name] = () => { handler(target); };
+    let wrapperNeeded = false;
+    let tweenerHandlers = _ensureHandlers(target);
+
+    if (!(name in tweenerHandlers)) {
+        tweenerHandlers[name] = [];
+        wrapperNeeded = true;
+    }
+
+    let handlers = tweenerHandlers[name];
+    handlers.push(handler);
+
+    if (wrapperNeeded) {
+        if (params[name]) {
+            let oldHandler = params[name];
+            let oldScope = params[name + 'Scope'];
+            let oldParams = params[name + 'Params'];
+            let eventScope = oldScope ? oldScope : target;
+
+            params[name] = () => {
+                oldHandler.apply(eventScope, oldParams);
+                handlers.forEach((h) => h(target));
+            };
+        } else {
+            params[name] = () => { handlers.forEach((h) => h(target)); };
+        }
+    }
+}
+
+function _removeHandler(target, name, handler) {
+    let tweenerHandlers = _ensureHandlers(target);
+
+    if (name in tweenerHandlers) {
+        let handlers = tweenerHandlers[name];
+        let handlerIndex = handlers.indexOf(handler);
+
+        while (handlerIndex > -1) {
+            handlers.splice(handlerIndex, 1);
+            handlerIndex = handlers.indexOf(handler);
+        }
+    }
 }
 
 function _actorDestroyed(target) {


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