From c227be4325b1594ffd5ed718c5146718d726e238 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Tue, 5 Dec 2017 02:41:50 +0100 Subject: [PATCH] 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 | 61 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 12 deletions(-) diff --git a/js/ui/tweener.js b/js/ui/tweener.js index 1a85e2fb1..22818ba4b 100644 --- a/js/ui/tweener.js +++ b/js/ui/tweener.js @@ -69,30 +69,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; + let wrapperNeeded = false; + let tweenerHandlers = _ensureHandlers(target); - params[name] = () => { - oldHandler.apply(eventScope, oldParams); - handler(target); - }; - } else - params[name] = () => { handler(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) {