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 */
|
/* exported TransientSignalHolder, addObjectSignalMethods */
|
||||||
const { GObject } = imports.gi;
|
const { GObject } = imports.gi;
|
||||||
|
|
||||||
|
const destroyableTypes = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @param {Object} obj - an object
|
* @param {Object} obj - an object
|
||||||
* @returns {bool} - true if obj has a 'destroy' GObject signal
|
* @returns {bool} - true if obj has a 'destroy' GObject signal
|
||||||
*/
|
*/
|
||||||
function _hasDestroySignal(obj) {
|
function _hasDestroySignal(obj) {
|
||||||
return obj instanceof GObject.Object &&
|
return destroyableTypes.some(type => obj instanceof type);
|
||||||
GObject.signal_lookup('destroy', obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var TransientSignalHolder = GObject.registerClass(
|
var TransientSignalHolder = GObject.registerClass(
|
||||||
@ -28,6 +29,7 @@ class TransientSignalHolder extends GObject.Object {
|
|||||||
this.emit('destroy');
|
this.emit('destroy');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
registerDestroyableType(TransientSignalHolder);
|
||||||
|
|
||||||
class SignalManager {
|
class SignalManager {
|
||||||
/**
|
/**
|
||||||
@ -230,3 +232,19 @@ function addObjectSignalMethods(proto) {
|
|||||||
};
|
};
|
||||||
proto['disconnect_object'] = proto['disconnectObject'];
|
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.addObjectSignalMethods(prototype);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SignalTracker.registerDestroyableType(Clutter.Actor);
|
||||||
|
|
||||||
// Miscellaneous monkeypatching
|
// Miscellaneous monkeypatching
|
||||||
_patchContainerClass(St.BoxLayout);
|
_patchContainerClass(St.BoxLayout);
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ const GnomeSession = imports.misc.gnomeSession;
|
|||||||
const Layout = imports.ui.layout;
|
const Layout = imports.ui.layout;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
|
const SignalTracker = imports.misc.signalTracker;
|
||||||
|
|
||||||
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
|
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
|
||||||
|
|
||||||
@ -493,6 +494,7 @@ var Notification = GObject.registerClass({
|
|||||||
this.run_dispose();
|
this.run_dispose();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
SignalTracker.registerDestroyableType(Notification);
|
||||||
|
|
||||||
var NotificationBanner = GObject.registerClass({
|
var NotificationBanner = GObject.registerClass({
|
||||||
Signals: {
|
Signals: {
|
||||||
@ -795,6 +797,7 @@ var Source = GObject.registerClass({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
SignalTracker.registerDestroyableType(Source);
|
||||||
|
|
||||||
var MessageTray = GObject.registerClass({
|
var MessageTray = GObject.registerClass({
|
||||||
Signals: {
|
Signals: {
|
||||||
|
@ -8,13 +8,14 @@ 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;
|
const { TransientSignalHolder, registerDestroyableType } = imports.misc.signalTracker;
|
||||||
|
|
||||||
Environment.init();
|
Environment.init();
|
||||||
|
|
||||||
const Destroyable = GObject.registerClass({
|
const Destroyable = GObject.registerClass({
|
||||||
Signals: { 'destroy': {} },
|
Signals: { 'destroy': {} },
|
||||||
}, class Destroyable extends GObject.Object {});
|
}, class Destroyable extends GObject.Object {});
|
||||||
|
registerDestroyableType(Destroyable);
|
||||||
|
|
||||||
class PlainEmitter {}
|
class PlainEmitter {}
|
||||||
Signals.addSignalMethods(PlainEmitter.prototype);
|
Signals.addSignalMethods(PlainEmitter.prototype);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user