Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

don't create and dispose submenus #165206

Merged
merged 1 commit into from
Nov 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 28 additions & 40 deletions src/vs/workbench/browser/parts/titlebar/menubarControl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import { ICommandService } from 'vs/platform/commands/common/commands';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { OpenRecentAction } from 'vs/workbench/browser/actions/windowActions';
import { isICommandActionToggleInfo } from 'vs/platform/action/common/action';
import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';

export type IOpenRecentAction = IAction & { uri: URI; remoteAuthority?: string };

Expand Down Expand Up @@ -646,6 +647,12 @@ export class CustomMenubarControl extends MenubarControl {
this._onVisibilityChange.fire(visible);
}

private toActionsArray(menu: IMenu): IAction[] {
const result: IAction[] = [];
createAndFillInContextMenuActions(menu, { shouldForwardArgs: true }, result);
return result;
}

private reinstallDisposables = this._register(new DisposableStore());
private setupCustomMenubar(firstTime: boolean): void {
// If there is no container, we cannot setup the menubar
Expand Down Expand Up @@ -704,67 +711,48 @@ export class CustomMenubarControl extends MenubarControl {
}

// Update the menu actions
const updateActions = (menu: IMenu, target: IAction[], topLevelTitle: string) => {
const updateActions = (menuActions: readonly IAction[], target: IAction[], topLevelTitle: string) => {
target.splice(0);
const groups = menu.getActions();

for (const group of groups) {
const [, actions] = group;

for (const action of actions) {
this.insertActionsBefore(action, target);
for (const menuItem of menuActions) {
this.insertActionsBefore(menuItem, target);

if (menuItem instanceof Separator) {
target.push(menuItem);
} else if (menuItem instanceof SubmenuItemAction || menuItem instanceof MenuItemAction) {
// use mnemonicTitle whenever possible
let title = typeof action.item.title === 'string'
? action.item.title
: action.item.title.mnemonicTitle ?? action.item.title.value;

if (action instanceof SubmenuItemAction) {
let submenu = this.menus[action.item.submenu.id];
if (!submenu) {
submenu = this.mainMenuDisposables.add(this.menus[action.item.submenu.id] = this.menuService.createMenu(action.item.submenu, this.contextKeyService));
this.mainMenuDisposables.add(submenu.onDidChange(() => {
if (!this.focusInsideMenubar) {
const actions: IAction[] = [];
updateActions(menu, actions, topLevelTitle);
if (this.menubar && this.topLevelTitles[topLevelTitle]) {
this.menubar.updateMenu({ actions: actions, label: mnemonicMenuLabel(this.topLevelTitles[topLevelTitle]) });
}
}
}, this));
}
let title = typeof menuItem.item.title === 'string'
? menuItem.item.title
: menuItem.item.title.mnemonicTitle ?? menuItem.item.title.value;

if (menuItem instanceof SubmenuItemAction) {
const submenuActions: SubmenuAction[] = [];
updateActions(submenu, submenuActions, topLevelTitle);
updateActions(menuItem.actions, submenuActions, topLevelTitle);

if (submenuActions.length > 0) {
target.push(new SubmenuAction(action.id, mnemonicMenuLabel(title), submenuActions));
target.push(new SubmenuAction(menuItem.id, mnemonicMenuLabel(title), submenuActions));
}
} else {
if (isICommandActionToggleInfo(action.item.toggled)) {
title = action.item.toggled.mnemonicTitle ?? action.item.toggled.title ?? title;
if (isICommandActionToggleInfo(menuItem.item.toggled)) {
title = menuItem.item.toggled.mnemonicTitle ?? menuItem.item.toggled.title ?? title;
}

const newAction = new Action(action.id, mnemonicMenuLabel(title), action.class, action.enabled, () => this.commandService.executeCommand(action.id));
newAction.tooltip = action.tooltip;
newAction.checked = action.checked;
const newAction = new Action(menuItem.id, mnemonicMenuLabel(title), menuItem.class, menuItem.enabled, () => this.commandService.executeCommand(menuItem.id));
newAction.tooltip = menuItem.tooltip;
newAction.checked = menuItem.checked;
target.push(newAction);
}
}

target.push(new Separator());
}

// Append web navigation menu items to the file menu when not compact
if (menu === this.menus.File && this.currentCompactMenuMode === undefined) {
if (topLevelTitle === 'File' && this.currentCompactMenuMode === undefined) {
const webActions = this.getWebNavigationActions();
if (webActions.length) {
target.push(...webActions);
target.push(new Separator()); // to account for pop below
}
}

target.pop();
};

for (const title of Object.keys(this.topLevelTitles)) {
Expand All @@ -773,7 +761,7 @@ export class CustomMenubarControl extends MenubarControl {
this.reinstallDisposables.add(menu.onDidChange(() => {
if (!this.focusInsideMenubar) {
const actions: IAction[] = [];
updateActions(menu, actions, title);
updateActions(this.toActionsArray(menu), actions, title);
this.menubar?.updateMenu({ actions: actions, label: mnemonicMenuLabel(this.topLevelTitles[title]) });
}
}));
Expand All @@ -783,7 +771,7 @@ export class CustomMenubarControl extends MenubarControl {
this.reinstallDisposables.add(this.webNavigationMenu.onDidChange(() => {
if (!this.focusInsideMenubar) {
const actions: IAction[] = [];
updateActions(menu, actions, title);
updateActions(this.toActionsArray(menu), actions, title);
this.menubar?.updateMenu({ actions: actions, label: mnemonicMenuLabel(this.topLevelTitles[title]) });
}
}));
Expand All @@ -792,7 +780,7 @@ export class CustomMenubarControl extends MenubarControl {

const actions: IAction[] = [];
if (menu) {
updateActions(menu, actions, title);
updateActions(this.toActionsArray(menu), actions, title);
}

if (this.menubar) {
Expand Down
34 changes: 13 additions & 21 deletions src/vs/workbench/electron-sandbox/parts/titlebar/menubarControl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { Separator } from 'vs/base/common/actions';
import { IMenuService, IMenu, SubmenuItemAction } from 'vs/platform/actions/common/actions';
import { IAction, Separator } from 'vs/base/common/actions';
import { IMenuService, SubmenuItemAction, MenuItemAction } from 'vs/platform/actions/common/actions';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces';
import { isMacintosh } from 'vs/base/common/platform';
Expand All @@ -26,6 +26,7 @@ import { IPreferencesService } from 'vs/workbench/services/preferences/common/pr
import { ICommandService } from 'vs/platform/commands/common/commands';
import { OpenRecentAction } from 'vs/workbench/browser/actions/windowActions';
import { isICommandActionToggleInfo } from 'vs/platform/action/common/action';
import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';

export class NativeMenubarControl extends MenubarControl {

Expand Down Expand Up @@ -93,7 +94,9 @@ export class NativeMenubarControl extends MenubarControl {
const menu = this.menus[topLevelMenuName];
if (menu) {
const menubarMenu: IMenubarMenu = { items: [] };
this.populateMenuItems(menu, menubarMenu, menubarData.keybindings);
const menuActions: IAction[] = [];
createAndFillInContextMenuActions(menu, { shouldForwardArgs: true }, menuActions);
this.populateMenuItems(menuActions, menubarMenu, menubarData.keybindings);
if (menubarMenu.items.length === 0) {
return false; // Menus are incomplete
}
Expand All @@ -104,13 +107,11 @@ export class NativeMenubarControl extends MenubarControl {
return true;
}

private populateMenuItems(menu: IMenu, menuToPopulate: IMenubarMenu, keybindings: { [id: string]: IMenubarKeybinding | undefined }) {
const groups = menu.getActions();

for (const group of groups) {
const [, actions] = group;

actions.forEach(menuItem => {
private populateMenuItems(menuActions: readonly IAction[], menuToPopulate: IMenubarMenu, keybindings: { [id: string]: IMenubarKeybinding | undefined }) {
for (const menuItem of menuActions) {
if (menuItem instanceof Separator) {
menuToPopulate.items.push({ id: 'vscode.menubar.separator' });
} else if (menuItem instanceof MenuItemAction || menuItem instanceof SubmenuItemAction) {

// use mnemonicTitle whenever possible
const title = typeof menuItem.item.title === 'string'
Expand All @@ -120,8 +121,7 @@ export class NativeMenubarControl extends MenubarControl {
if (menuItem instanceof SubmenuItemAction) {
const submenu = { items: [] };

const menuToDispose = this.menuService.createMenu(menuItem.item.submenu, this.contextKeyService);
this.populateMenuItems(menuToDispose, submenu, keybindings);
this.populateMenuItems(menuItem.actions, submenu, keybindings);

if (submenu.items.length > 0) {
const menubarSubmenuItem: IMenubarMenuItemSubmenu = {
Expand All @@ -132,8 +132,6 @@ export class NativeMenubarControl extends MenubarControl {

menuToPopulate.items.push(menubarSubmenuItem);
}

menuToDispose.dispose();
} else {
if (menuItem.id === OpenRecentAction.ID) {
const actions = this.getOpenRecentActions().map(this.transformOpenRecentAction);
Expand All @@ -160,13 +158,7 @@ export class NativeMenubarControl extends MenubarControl {
keybindings[menuItem.id] = this.getMenubarKeybinding(menuItem.id);
menuToPopulate.items.push(menubarMenuItem);
}
});

menuToPopulate.items.push({ id: 'vscode.menubar.separator' });
}

if (menuToPopulate.items.length > 0) {
menuToPopulate.items.pop();
}
}
}

Expand Down