gnome-shell/tests/unit/signalTracker.js
Florian Müllner fc4f9f61fa signalTracker: Explicitly register destroyable types
We currently assume that any '::destroy' signal on a GObject type
has the semantics of the ClutterActor/GtkWidget signal, and should
therefore result in all signals being disconnected.

But we already have a case where the assumption doesn't hold: ShellWM
uses '::destroy' for the closing animation of windows, and the ShellWM
object itself remains very valid after the emission.

So rather than making assumptions about '::destroy', check objects
against a list of destroyable types that are explicitly registered
as such.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2226>
2022-03-06 00:10:03 +00:00

119 lines
2.7 KiB
JavaScript

// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
// Test cases for version comparison
const { GObject } = imports.gi;
const JsUnit = imports.jsUnit;
const Signals = imports.signals;
const Environment = imports.ui.environment;
const { TransientSignalHolder, registerDestroyableType } = imports.misc.signalTracker;
Environment.init();
const Destroyable = GObject.registerClass({
Signals: { 'destroy': {} },
}, class Destroyable extends GObject.Object {});
registerDestroyableType(Destroyable);
class PlainEmitter {}
Signals.addSignalMethods(PlainEmitter.prototype);
const GObjectEmitter = GObject.registerClass({
Signals: { 'signal': {} },
}, class GObjectEmitter extends Destroyable {});
const emitter1 = new PlainEmitter();
const emitter2 = new GObjectEmitter();
const tracked1 = new Destroyable();
const tracked2 = {};
let count = 0;
const handler = () => count++;
emitter1.connectObject('signal', handler, tracked1);
emitter2.connectObject('signal', handler, tracked1);
emitter1.connectObject('signal', handler, tracked2);
emitter2.connectObject('signal', handler, tracked2);
JsUnit.assertEquals(count, 0);
emitter1.emit('signal');
emitter2.emit('signal');
JsUnit.assertEquals(count, 4);
tracked1.emit('destroy');
emitter1.emit('signal');
emitter2.emit('signal');
JsUnit.assertEquals(count, 6);
emitter1.disconnectObject(tracked2);
emitter2.emit('destroy');
emitter1.emit('signal');
emitter2.emit('signal');
JsUnit.assertEquals(count, 6);
emitter1.connectObject(
'signal', handler,
'signal', handler, GObject.ConnectFlags.AFTER,
tracked1);
emitter2.connectObject(
'signal', handler,
'signal', handler, GObject.ConnectFlags.AFTER,
tracked1);
emitter1.emit('signal');
emitter2.emit('signal');
JsUnit.assertEquals(count, 10);
tracked1.emit('destroy');
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);