From f1b7af2ab0f2a3b7e115c9681e2e7cd98a4790b8 Mon Sep 17 00:00:00 2001 From: Sebastian Keller Date: Mon, 30 Oct 2023 11:18:25 +0100 Subject: [PATCH] popupMenu: Only connect to notify::key-focus when needed PopupMenuManager was connecting to notify::key-focus on the stage on construction, but only ever reacting to it when one of its menus was open. Given that every single app icon and text entry creates a PopupMenuManager this was causing a lot of these handlers to be created. Every single handler meant calling into JS code only for the vast majority of them to determine that they would not do anything. Additionally these handlers were leaked for the whole lifetime of the stage due to never getting disconnected. This now only connects the handler when a menu is open and disconnects again when it is closed, significantly reducing the number of active handlers at a time. Closes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/7143 Part-of: --- js/ui/popupMenu.js | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/js/ui/popupMenu.js b/js/ui/popupMenu.js index b2a3c4a48..f06bee65f 100644 --- a/js/ui/popupMenu.js +++ b/js/ui/popupMenu.js @@ -1276,16 +1276,6 @@ export class PopupMenuManager { constructor(owner, grabParams) { this._grabParams = Params.parse(grabParams, {actionMode: Shell.ActionMode.POPUP}); - global.stage.connect('notify::key-focus', () => { - if (!this.activeMenu) - return; - - let actor = global.stage.get_key_focus(); - let newMenu = this._findMenuForSource(actor); - - if (newMenu) - this._changeMenu(newMenu); - }); this._menus = []; } @@ -1309,6 +1299,11 @@ export class PopupMenuManager { if (menu === this.activeMenu) { Main.popModal(this._grab); this._grab = null; + + if (this._keyFocusId) { + global.stage.disconnect(this._keyFocusId); + delete this._keyFocusId; + } } const position = this._menus.indexOf(menu); @@ -1336,10 +1331,29 @@ export class PopupMenuManager { oldMenu?.close(BoxPointer.PopupAnimation.FADE); if (oldGrab) Main.popModal(oldGrab); + + if (!this._keyFocusId) { + this._keyFocusId = + global.stage.connect('notify::key-focus', () => { + if (!this.activeMenu) + return; + + let actor = global.stage.get_key_focus(); + let newMenu = this._findMenuForSource(actor); + + if (newMenu) + this._changeMenu(newMenu); + }); + } } else if (this.activeMenu === menu) { this.activeMenu = null; Main.popModal(this._grab); this._grab = null; + + if (this._keyFocusId) { + global.stage.disconnect(this._keyFocusId); + delete this._keyFocusId; + } } }