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>
This commit is contained in:
Florian Müllner 2022-03-06 00:30:16 +01:00 committed by Marge Bot
parent ba23279f1f
commit fc4f9f61fa
4 changed files with 27 additions and 3 deletions

View File

@ -1,14 +1,15 @@
/* exported TransientSignalHolder, addObjectSignalMethods */
const { GObject } = imports.gi;
const destroyableTypes = [];
/**
* @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);
return destroyableTypes.some(type => obj instanceof type);
}
var TransientSignalHolder = GObject.registerClass(
@ -28,6 +29,7 @@ class TransientSignalHolder extends GObject.Object {
this.emit('destroy');
}
});
registerDestroyableType(TransientSignalHolder);
class SignalManager {
/**
@ -230,3 +232,19 @@ function addObjectSignalMethods(proto) {
};
proto['disconnect_object'] = proto['disconnectObject'];
}
/**
* Register a GObject type as having a 'destroy' signal
* that should disconnect all handlers
*
* @param {GObject.Type} gtype - a GObject type
*/
function registerDestroyableType(gtype) {
if (!GObject.type_is_a(gtype, GObject.Object))
throw new Error(`${gtype} is not a GObject subclass`);
if (!GObject.signal_lookup('destroy', gtype))
throw new Error(`${gtype} does not have a destroy signal`);
destroyableTypes.push(gtype);
}

View File

@ -345,6 +345,8 @@ function init() {
SignalTracker.addObjectSignalMethods(prototype);
};
SignalTracker.registerDestroyableType(Clutter.Actor);
// Miscellaneous monkeypatching
_patchContainerClass(St.BoxLayout);

View File

@ -10,6 +10,7 @@ const GnomeSession = imports.misc.gnomeSession;
const Layout = imports.ui.layout;
const Main = imports.ui.main;
const Params = imports.misc.params;
const SignalTracker = imports.misc.signalTracker;
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
@ -493,6 +494,7 @@ var Notification = GObject.registerClass({
this.run_dispose();
}
});
SignalTracker.registerDestroyableType(Notification);
var NotificationBanner = GObject.registerClass({
Signals: {
@ -795,6 +797,7 @@ var Source = GObject.registerClass({
}
}
});
SignalTracker.registerDestroyableType(Source);
var MessageTray = GObject.registerClass({
Signals: {

View File

@ -8,13 +8,14 @@ const JsUnit = imports.jsUnit;
const Signals = imports.signals;
const Environment = imports.ui.environment;
const { TransientSignalHolder } = imports.misc.signalTracker;
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);