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:
parent
ba23279f1f
commit
fc4f9f61fa
@ -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);
|
||||
}
|
||||
|
@ -345,6 +345,8 @@ function init() {
|
||||
SignalTracker.addObjectSignalMethods(prototype);
|
||||
};
|
||||
|
||||
SignalTracker.registerDestroyableType(Clutter.Actor);
|
||||
|
||||
// Miscellaneous monkeypatching
|
||||
_patchContainerClass(St.BoxLayout);
|
||||
|
||||
|
@ -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: {
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user