[gnome-shell] signalTracker: Add TransientSignalHolder class



commit cf29ec2f2231a897d25b67fac151e49da451eaeb
Author: Florian Müllner <fmuellner gnome org>
Date:   Fri Mar 4 23:32:24 2022 +0100

    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>

 js/misc/signalTracker.js    | 44 +++++++++++++++++++++++++++++++-------------
 tests/unit/signalTracker.js | 38 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 69 insertions(+), 13 deletions(-)
---
diff --git a/js/misc/signalTracker.js b/js/misc/signalTracker.js
index b7aff10dc8..3e83be7341 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 f13327ec14..40398c0b8a 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);


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