diff --git a/lib/extension/indicator.js b/lib/extension/indicator.js index 309dcf20..06a0d448 100644 --- a/lib/extension/indicator.js +++ b/lib/extension/indicator.js @@ -118,12 +118,20 @@ export class FeatureIndicator extends SystemIndicator { this._indicator.visible = tilingModeEnabled && quickSettingsEnabled; - this.extension.settings.connect("changed", (_, name) => { + this._settings = this.extension.settings; + this._settingsChangedId = this._settings.connect("changed", (_, name) => { switch (name) { case "tiling-mode-enabled": case "quick-settings-enabled": - this._indicator.visible = this.extension.settings.get_boolean(name); + this._indicator.visible = this._settings.get_boolean(name); } }); } + + destroy() { + // the handler would outlive the indicator, and the extension's settings (#469's log) + if (this._settingsChangedId) this._settings.disconnect(this._settingsChangedId); + this._settingsChangedId = 0; + super.destroy(); + } } diff --git a/lib/extension/window.js b/lib/extension/window.js index 61820e1e..750b9f4c 100644 --- a/lib/extension/window.js +++ b/lib/extension/window.js @@ -289,7 +289,10 @@ export class WindowManager extends GObject.Object { let settings = this.ext.settings; - settings.connect("changed", (_, settingName) => { + // (kept to disconnect in _removeSignals: the extension drops its settings on disable, and + // a handler left connected failed on every later change) + this._settings = settings; + this._settingsChangedId = settings.connect("changed", (_, settingName) => { switch (settingName) { case "window-overrides-reload-trigger": // Reload window overrides when triggered by preferences @@ -1042,6 +1045,12 @@ export class WindowManager extends GObject.Object { _removeSignals() { if (!this._signalsBound) return; + if (this._settingsChangedId) { + this._settings.disconnect(this._settingsChangedId); + this._settingsChangedId = 0; + this._settings = null; + } + if (this._displaySignals) { for (const displaySignal of this._displaySignals) { global.display.disconnect(displaySignal); @@ -1082,6 +1091,10 @@ export class WindowManager extends GObject.Object { } let allWindows = this.windowsAllWorkspaces; + // A window that is closing has left the window list, but its actor keeps its handlers and + // borders until the close animation ends: release those too + const windowActors = new Set(this._windowActors); + this._windowActors?.clear(); if (allWindows) { for (let metaWindow of allWindows) { @@ -1094,29 +1107,33 @@ export class WindowManager extends GObject.Object { } let windowActor = metaWindow.get_compositor_private(); - if (windowActor && windowActor.actorSignals) { - for (const actorSignal of windowActor.actorSignals) { - windowActor.disconnect(actorSignal); - } - windowActor.actorSignals.length = 0; - windowActor.actorSignals = undefined; + if (windowActor) windowActors.add(windowActor); + } + } + + for (const windowActor of windowActors) { + if (windowActor.actorSignals) { + for (const actorSignal of windowActor.actorSignals) { + windowActor.disconnect(actorSignal); } + windowActor.actorSignals.length = 0; + windowActor.actorSignals = undefined; + } - if (windowActor && windowActor.border) { - windowActor.border.hide(); - if (global.window_group) { - global.window_group.remove_child(windowActor.border); - } - windowActor.border = undefined; + if (windowActor.border) { + windowActor.border.hide(); + if (global.window_group) { + global.window_group.remove_child(windowActor.border); } + windowActor.border = undefined; + } - if (windowActor && windowActor.splitBorder) { - windowActor.splitBorder.hide(); - if (global.window_group) { - global.window_group.remove_child(windowActor.splitBorder); - } - windowActor.splitBorder = undefined; + if (windowActor.splitBorder) { + windowActor.splitBorder.hide(); + if (global.window_group) { + global.window_group.remove_child(windowActor.splitBorder); } + windowActor.splitBorder = undefined; } } @@ -1525,6 +1542,7 @@ export class WindowManager extends GObject.Object { if (!windowActor.actorSignals) { let actorSignals = [windowActor.connect("destroy", this.windowDestroy.bind(this))]; windowActor.actorSignals = actorSignals; + (this._windowActors ??= new Set()).add(windowActor); } if (!windowActor.border) { @@ -1671,6 +1689,7 @@ export class WindowManager extends GObject.Object { } windowDestroy(actor) { + this._windowActors?.delete(actor); // Release any resources on the window let border = actor.border; if (border) {