Codebase list gnome-shell-extension-appindicator / 42c1a68
dbusMenu: Populate menus in chunked idles Creating menu items and populating them can be quite expensive in GNOME shell, since we may create many of them during the extension initialization we could end up blocking the UI. To avoid this, we can create multiple idles for each menu addition, one with each priority that depends on the number of elements already queued for addition, in this way the items are added in different main loop idle cycles avoiding to fill our job queue with too many things to do each frame. Helps with: #295 Marco Trevisan (TreviƱo) authored 1 year, 2 months ago Marco Trevisan committed 1 year, 2 months ago
1 changed file(s) with 29 addition(s) and 7 deletion(s). Raw diff Collapse all Expand all
843843 attachToMenu(menu) {
844844 this._rootMenu = menu;
845845 this._rootItem = this._client.getRoot();
846 this._itemsBeingAdded = new Set();
846847
847848 // cleanup: remove existing children (just in case)
848849 this._rootMenu.removeAll();
862863 this._rootItem.sendAboutToShow();
863864
864865 // fill the menu for the first time
865 this._rootItem.getChildren().forEach(child =>
866 this._rootMenu.addMenuItem(MenuItemFactory.createItem(this, child)));
866 const children = this._rootItem.getChildren();
867 children.forEach(child =>
868 this._onRootChildAdded(this._rootItem, child));
867869 }
868870
869871 _setOpenedSubmenu(submenu) {
883885 }
884886
885887 _onRootChildAdded(dbusItem, child, position) {
886 this._rootMenu.addMenuItem(MenuItemFactory.createItem(this, child), position);
888 // Menu additions can be expensive, so let's do it in different chunks
889 const basePriority = this.isOpen ? GLib.PRIORITY_DEFAULT : GLib.PRIORITY_LOW;
890 const idlePromise = new PromiseUtils.IdlePromise(
891 basePriority + this._itemsBeingAdded.size, this.cancellable);
892 this._itemsBeingAdded.add(child);
893
894 idlePromise.then(() => {
895 if (!this._itemsBeingAdded.has(child))
896 return;
897
898 this._rootMenu.addMenuItem(
899 MenuItemFactory.createItem(this, child), position);
900 }).catch(e => {
901 if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
902 logError(e);
903 }).finally(() => this._itemsBeingAdded.delete(child));
887904 }
888905
889906 _onRootChildRemoved(dbusItem, child) {
890907 // children like to play hide and seek
891908 // but we know how to find it for sure!
892 this._rootMenu._getMenuItems().forEach(item => {
893 if (item._dbusItem === child)
894 item.destroy();
895 });
909 const item = this._rootMenu._getMenuItems().find(it =>
910 it._dbusItem === child);
911
912 if (item)
913 item.destroy();
914 else
915 this._itemsBeingAdded.delete(child);
916
896917 }
897918
898919 _onRootChildMoved(dbusItem, child, oldpos, newpos) {
926947 this._rootItem = null;
927948 this._rootMenu = null;
928949 this.indicator = null;
950 this._itemsBeingAdded = null;
929951 }
930952 };
931953 Signals.addSignalMethods(Client.prototype);