fix: don't wrap Panel._addToPanelBox twice

If `enable()` throws after `Panel._addToPanelBox` is overwritten, the
extension ends up in the error state and GNOME Shell never calls
`disable()`. Extensions are disabled and enabled on every screen lock,
so the next `enable()` saved the overwrite itself as
`_originalAddToPanelBox`. From then on the method called itself until
the stack overflowed, and the top bar came up empty after unlocking.

Only save the original method when it isn't saved yet, and make
`disable()` safe to call when `enable()` didn't finish.
This commit is contained in:
Michał T 2026-11-09 09:52:24 +01:00
commit 6802c2f0f3

View file

@ -54,18 +54,21 @@ export default class TopBarOrganizerExtension extends Extension {
}
disable(): void {
// Revert the overwrite of `Panel._addToPanelBox`.
// Revert the overwrite of `Panel._addToPanelBox`, if there is one.
// @ts-ignore
Panel.Panel.prototype._addToPanelBox = Panel.Panel.prototype._originalAddToPanelBox;
// Set `Panel._originalAddToPanelBox` to `undefined`.
// @ts-ignore
Panel.Panel.prototype._originalAddToPanelBox = undefined;
// Disconnect signals.
for (const handlerId of this._settingsHandlerIds) {
this._settings.disconnect(handlerId);
if (Panel.Panel.prototype._originalAddToPanelBox) {
// @ts-ignore
Panel.Panel.prototype._addToPanelBox = Panel.Panel.prototype._originalAddToPanelBox;
// Set `Panel._originalAddToPanelBox` to `undefined`.
// @ts-ignore
Panel.Panel.prototype._originalAddToPanelBox = undefined;
}
this._boxOrderManager.disconnectSignals();
// Disconnect signals. `enable()` may not have got this far.
for (const handlerId of this._settingsHandlerIds ?? []) {
this._settings?.disconnect(handlerId);
}
this._boxOrderManager?.disconnectSignals();
// @ts-ignore
this._settings = null;
@ -83,9 +86,16 @@ export default class TopBarOrganizerExtension extends Extension {
*/
#overwritePanelAddToPanelBox(): void {
// Add the original `Panel._addToPanelBox` method as
// `Panel._originalAddToPanelBox`.
// `Panel._originalAddToPanelBox`, unless it's already saved. That is
// the case when an earlier `enable()` failed, so `disable()` never
// ran: `Panel._addToPanelBox` is then still our overwrite, and saving
// that as the original would make it call itself endlessly, which
// leaves the top bar empty.
// @ts-ignore
Panel.Panel.prototype._originalAddToPanelBox = Panel.Panel.prototype._addToPanelBox;
if (!Panel.Panel.prototype._originalAddToPanelBox) {
// @ts-ignore
Panel.Panel.prototype._originalAddToPanelBox = Panel.Panel.prototype._addToPanelBox;
}
const handleNewItemsAndOrderTopBar = () => {
this.#handleNewItemsAndOrderTopBar();