signalTracker: Add TransientSignalHolder class
There are cases where we want to connect to a number of signals for the lifetime of an object, but also other signals for a limited period (say: between show and hide). It is currently not possible to use disconnectObject() for the latter, because it will disconnect all signals. To address this use case, add a small class that can be used as a transient signal holder, while still benefiting from autocleanup by proxying the real owner. Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2221>
This commit is contained in:
parent
7b0a94b246
commit
cf29ec2f22
@ -1,6 +1,34 @@
|
|||||||
/* exported addObjectSignalMethods */
|
/* exported TransientSignalHolder, addObjectSignalMethods */
|
||||||
const { GObject } = imports.gi;
|
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 {
|
class SignalManager {
|
||||||
/**
|
/**
|
||||||
* @returns {SignalManager} - the SignalManager singleton
|
* @returns {SignalManager} - the SignalManager singleton
|
||||||
@ -31,23 +59,13 @@ class SignalTracker {
|
|||||||
* @param {Object=} owner - object that owns the tracker
|
* @param {Object=} owner - object that owns the tracker
|
||||||
*/
|
*/
|
||||||
constructor(owner) {
|
constructor(owner) {
|
||||||
if (this._hasDestroySignal(owner))
|
if (_hasDestroySignal(owner))
|
||||||
this._ownerDestroyId = owner.connect_after('destroy', () => this.clear());
|
this._ownerDestroyId = owner.connect_after('destroy', () => this.clear());
|
||||||
|
|
||||||
this._owner = owner;
|
this._owner = owner;
|
||||||
this._map = new Map();
|
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
|
* @typedef SignalData
|
||||||
* @property {number[]} ownerSignals - a list of handler IDs
|
* @property {number[]} ownerSignals - a list of handler IDs
|
||||||
@ -89,7 +107,7 @@ class SignalTracker {
|
|||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
track(obj, ...handlerIds) {
|
track(obj, ...handlerIds) {
|
||||||
if (this._hasDestroySignal(obj))
|
if (_hasDestroySignal(obj))
|
||||||
this._trackDestroy(obj);
|
this._trackDestroy(obj);
|
||||||
|
|
||||||
this._getSignalData(obj).ownerSignals.push(...handlerIds);
|
this._getSignalData(obj).ownerSignals.push(...handlerIds);
|
||||||
|
@ -8,6 +8,8 @@ const JsUnit = imports.jsUnit;
|
|||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
|
|
||||||
const Environment = imports.ui.environment;
|
const Environment = imports.ui.environment;
|
||||||
|
const { TransientSignalHolder } = imports.misc.signalTracker;
|
||||||
|
|
||||||
Environment.init();
|
Environment.init();
|
||||||
|
|
||||||
const Destroyable = GObject.registerClass({
|
const Destroyable = GObject.registerClass({
|
||||||
@ -77,3 +79,39 @@ emitter1.emit('signal');
|
|||||||
emitter2.emit('signal');
|
emitter2.emit('signal');
|
||||||
|
|
||||||
JsUnit.assertEquals(count, 10);
|
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);
|
||||||
|
Loading…
Reference in New Issue
Block a user