diff options
Diffstat (limited to 'src/vs/platform/menubar/electron-main/menubar.ts')
-rw-r--r-- | src/vs/platform/menubar/electron-main/menubar.ts | 44 |
1 files changed, 40 insertions, 4 deletions
diff --git a/src/vs/platform/menubar/electron-main/menubar.ts b/src/vs/platform/menubar/electron-main/menubar.ts index c4f612d801f..9fd8cca89ea 100644 --- a/src/vs/platform/menubar/electron-main/menubar.ts +++ b/src/vs/platform/menubar/electron-main/menubar.ts @@ -3,11 +3,11 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { app, BrowserWindow, KeyboardEvent, Menu, MenuItem, MenuItemConstructorOptions, WebContents } from 'electron'; +import { app, BrowserWindow, KeyboardEvent, Menu, MenuItem, MenuItemConstructorOptions, MessageBoxOptions, WebContents } from 'electron'; import { WorkbenchActionExecutedClassification, WorkbenchActionExecutedEvent } from 'vs/base/common/actions'; import { RunOnceScheduler } from 'vs/base/common/async'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { mnemonicMenuLabel } from 'vs/base/common/labels'; +import { mnemonicButtonLabel, mnemonicMenuLabel } from 'vs/base/common/labels'; import { isMacintosh, language } from 'vs/base/common/platform'; import { URI } from 'vs/base/common/uri'; import * as nls from 'vs/nls'; @@ -118,6 +118,7 @@ export class Menubar { this.fallbackMenuHandlers['workbench.action.files.newUntitledFile'] = (menuItem, win, event) => this.windowsMainService.openEmptyWindow({ context: OpenContext.MENU, contextWindowId: win?.id }); this.fallbackMenuHandlers['workbench.action.newWindow'] = (menuItem, win, event) => this.windowsMainService.openEmptyWindow({ context: OpenContext.MENU, contextWindowId: win?.id }); this.fallbackMenuHandlers['workbench.action.files.openFileFolder'] = (menuItem, win, event) => this.nativeHostMainService.pickFileFolderAndOpen(undefined, { forceNewWindow: this.isOptionClick(event), telemetryExtraData: { from: telemetryFrom } }); + this.fallbackMenuHandlers['workbench.action.files.openFolder'] = (menuItem, win, event) => this.nativeHostMainService.pickFolderAndOpen(undefined, { forceNewWindow: this.isOptionClick(event), telemetryExtraData: { from: telemetryFrom } }); this.fallbackMenuHandlers['workbench.action.openWorkspace'] = (menuItem, win, event) => this.nativeHostMainService.pickWorkspaceAndOpen(undefined, { forceNewWindow: this.isOptionClick(event), telemetryExtraData: { from: telemetryFrom } }); // Recent Menu Items @@ -160,6 +161,7 @@ export class Menubar { } private registerListeners(): void { + // Keep flag when app quits this.lifecycleMainService.onWillShutdown(() => this.willShutdown = true); @@ -382,14 +384,17 @@ export class Menubar { const hideOthers = new MenuItem({ label: nls.localize('mHideOthers', "Hide Others"), role: 'hideOthers', accelerator: 'Command+Alt+H' }); const showAll = new MenuItem({ label: nls.localize('mShowAll', "Show All"), role: 'unhide' }); const quit = new MenuItem(this.likeAction('workbench.action.quit', { - label: nls.localize('miQuit', "Quit {0}", this.productService.nameLong), click: () => { + label: nls.localize('miQuit', "Quit {0}", this.productService.nameLong), click: async (item, window, event) => { const lastActiveWindow = this.windowsMainService.getLastActiveWindow(); if ( this.windowsMainService.getWindowCount() === 0 || // allow to quit when no more windows are open !!BrowserWindow.getFocusedWindow() || // allow to quit when window has focus (fix for https://github.com/microsoft/vscode/issues/39191) lastActiveWindow?.isMinimized() // allow to quit when window has no focus but is minimized (https://github.com/microsoft/vscode/issues/63000) ) { - this.nativeHostMainService.quit(undefined); + const confirmed = await this.confirmBeforeQuit(event); + if (confirmed) { + this.nativeHostMainService.quit(undefined); + } } } })); @@ -418,6 +423,33 @@ export class Menubar { actions.forEach(i => macApplicationMenu.append(i)); } + private async confirmBeforeQuit(event: KeyboardEvent): Promise<boolean> { + if (this.windowsMainService.getWindowCount() === 0) { + return true; // never confirm when no windows are opened + } + + const confirmBeforeClose = this.configurationService.getValue<'always' | 'never' | 'keyboardOnly'>('window.confirmBeforeClose'); + if (confirmBeforeClose === 'always' || (confirmBeforeClose === 'keyboardOnly' && this.isKeyboardEvent(event))) { + const options: MessageBoxOptions = { + title: this.productService.nameLong, + type: 'question', + buttons: [ + mnemonicButtonLabel(nls.localize({ key: 'quit', comment: ['&& denotes a mnemonic'] }, "&&Quit")), + mnemonicButtonLabel(nls.localize({ key: 'cancel', comment: ['&& denotes a mnemonic'] }, "&&Cancel")) + ], + message: nls.localize('quitMessage', "Are you sure you want to quit?"), + noLink: true, + defaultId: 0, + cancelId: 1 + }; + + const { response } = await this.nativeHostMainService.showMessageBox(this.windowsMainService.getFocusedWindow()?.id, options); + return response === 0; + } + + return true; + } + private shouldDrawMenu(menuId: string): boolean { // We need to draw an empty menu to override the electron default if (!isMacintosh && getTitleBarStyle(this.configurationService) === 'custom') { @@ -522,6 +554,10 @@ export class Menubar { return !!(event && ((!isMacintosh && (event.ctrlKey || event.shiftKey)) || (isMacintosh && (event.metaKey || event.altKey)))); } + private isKeyboardEvent(event: KeyboardEvent): boolean { + return !!(event.triggeredByAccelerator || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey); + } + private createRoleMenuItem(label: string, commandId: string, role: any): MenuItem { const options: MenuItemConstructorOptions = { label: this.mnemonicLabel(label), |