diff --git a/js/misc/signalTracker.js b/js/misc/signalTracker.js index b7aff10dc..3e83be734 100644 --- a/js/misc/signalTracker.js +++ b/js/misc/signalTracker.js @@ -1,6 +1,34 @@ -/* exported addObjectSignalMethods */ +/* exported TransientSignalHolder, addObjectSignalMethods */ const { GObject } = imports.gi; +/** + * @private + * @param {Object} obj - an object + * @returns {bool} - true if obj has a 'destroy' GObject signal + */ +function _hasDestroySignal(obj) { + return obj instanceof GObject.Object && + GObject.signal_lookup('destroy', obj); +} + +var TransientSignalHolder = GObject.registerClass( +class TransientSignalHolder extends GObject.Object { + static [GObject.signals] = { + 'destroy': {}, + }; + + constructor(owner) { + super(); + + if (_hasDestroySignal(owner)) + owner.connectObject('destroy', () => this.destroy(), this); + } + + destroy() { + this.emit('destroy'); + } +}); + class SignalManager { /** * @returns {SignalManager} - the SignalManager singleton @@ -31,23 +59,13 @@ class SignalTracker { * @param {Object=} owner - object that owns the tracker */ constructor(owner) { - if (this._hasDestroySignal(owner)) + if (_hasDestroySignal(owner)) this._ownerDestroyId = owner.connect_after('destroy', () => this.clear()); this._owner = owner; this._map = new Map(); } - /** - * @private - * @param {Object} obj - an object - * @returns {bool} - true if obj has a 'destroy' GObject signal - */ - _hasDestroySignal(obj) { - return obj instanceof GObject.Object && - GObject.signal_lookup('destroy', obj); - } - /** * @typedef SignalData * @property {number[]} ownerSignals - a list of handler IDs @@ -89,7 +107,7 @@ class SignalTracker { * @returns {void} */ track(obj, ...handlerIds) { - if (this._hasDestroySignal(obj)) + if (_hasDestroySignal(obj)) this._trackDestroy(obj); this._getSignalData(obj).ownerSignals.push(...handlerIds); diff --git a/tests/unit/signalTracker.js b/tests/unit/signalTracker.js index f13327ec1..40398c0b8 100644 --- a/tests/unit/signalTracker.js +++ b/tests/unit/signalTracker.js @@ -8,6 +8,8 @@ const JsUnit = imports.jsUnit; const Signals = imports.signals; const Environment = imports.ui.environment; +const { TransientSignalHolder } = imports.misc.signalTracker; + Environment.init(); const Destroyable = GObject.registerClass({ @@ -77,3 +79,39 @@ emitter1.emit('signal'); emitter2.emit('signal'); JsUnit.assertEquals(count, 10); + +emitter1.connectObject('signal', handler, tracked1); +emitter2.connectObject('signal', handler, tracked1); + +transientHolder = new TransientSignalHolder(tracked1); + +emitter1.connectObject('signal', handler, transientHolder); +emitter2.connectObject('signal', handler, transientHolder); + +emitter1.emit('signal'); +emitter2.emit('signal'); + +JsUnit.assertEquals(count, 14); + +transientHolder.destroy(); + +emitter1.emit('signal'); +emitter2.emit('signal'); + +JsUnit.assertEquals(count, 16); + +transientHolder = new TransientSignalHolder(tracked1); + +emitter1.connectObject('signal', handler, transientHolder); +emitter2.connectObject('signal', handler, transientHolder); + +emitter1.emit('signal'); +emitter2.emit('signal'); + +JsUnit.assertEquals(count, 20); + +tracked1.emit('destroy'); +emitter1.emit('signal'); +emitter2.emit('signal'); + +JsUnit.assertEquals(count, 20);