diff --git a/src/vs/platform/window/common/window.ts b/src/vs/platform/window/common/window.ts index 9bd50404bdf..38ad7ca52eb 100644 --- a/src/vs/platform/window/common/window.ts +++ b/src/vs/platform/window/common/window.ts @@ -204,6 +204,20 @@ export function useWindowControlsOverlay(configurationService: IConfigurationSer return true; } +export function useNativeFullScreen(configurationService: IConfigurationService): boolean { + const windowConfig = configurationService.getValue('window'); + if (!windowConfig || typeof windowConfig.nativeFullScreen !== 'boolean') { + return true; // default + } + + if (windowConfig.nativeTabs) { + return true; // https://github.com/electron/electron/issues/16142 + } + + return windowConfig.nativeFullScreen !== false; +} + + export interface IPath extends IPathData { /** diff --git a/src/vs/platform/windows/electron-main/windowImpl.ts b/src/vs/platform/windows/electron-main/windowImpl.ts index 5fec8f9520b..a2b3c09856e 100644 --- a/src/vs/platform/windows/electron-main/windowImpl.ts +++ b/src/vs/platform/windows/electron-main/windowImpl.ts @@ -31,7 +31,7 @@ import { IApplicationStorageMainService, IStorageMainService } from 'vs/platform import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ThemeIcon } from 'vs/base/common/themables'; import { IThemeMainService } from 'vs/platform/theme/electron-main/themeMainService'; -import { getMenuBarVisibility, getTitleBarStyle, IFolderToOpen, INativeWindowConfiguration, IWindowSettings, IWorkspaceToOpen, MenuBarVisibility, useWindowControlsOverlay } from 'vs/platform/window/common/window'; +import { getMenuBarVisibility, getTitleBarStyle, IFolderToOpen, INativeWindowConfiguration, IWindowSettings, IWorkspaceToOpen, MenuBarVisibility, useNativeFullScreen, useWindowControlsOverlay } from 'vs/platform/window/common/window'; import { defaultBrowserWindowOptions, IWindowsMainService, OpenContext } from 'vs/platform/windows/electron-main/windows'; import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, toWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace'; import { IWorkspacesManagementMainService } from 'vs/platform/workspaces/electron-main/workspacesManagementMainService'; @@ -163,7 +163,7 @@ export abstract class BaseWindow extends Disposable implements IBaseWindow { protected setFullScreen(fullscreen: boolean): void { // Set fullscreen state - if (this.useNativeFullScreen()) { + if (useNativeFullScreen(this.configurationService)) { this.setNativeFullScreen(fullscreen); } else { this.setSimpleFullScreen(fullscreen); @@ -223,19 +223,6 @@ export abstract class BaseWindow extends Disposable implements IBaseWindow { win?.webContents.focus(); // workaround issue where focus is not going into window } - protected useNativeFullScreen(): boolean { - const windowConfig = this.configurationService.getValue('window'); - if (!windowConfig || typeof windowConfig.nativeFullScreen !== 'boolean') { - return true; // default - } - - if (windowConfig.nativeTabs) { - return true; // https://github.com/electron/electron/issues/16142 - } - - return windowConfig.nativeFullScreen !== false; - } - //#endregion } @@ -356,8 +343,6 @@ export class CodeWindow extends BaseWindow implements ICodeWindow { // after the call to maximize/fullscreen (see below) const isFullscreenOrMaximized = (this.windowState.mode === WindowMode.Maximized || this.windowState.mode === WindowMode.Fullscreen); - const windowSettings = this.configurationService.getValue('window'); - const options = instantiationService.invokeFunction(defaultBrowserWindowOptions, this.windowState, { show: !isFullscreenOrMaximized, // reduce flicker by showing later webPreferences: { @@ -367,15 +352,6 @@ export class CodeWindow extends BaseWindow implements ICodeWindow { } }); - if (isMacintosh && !this.useNativeFullScreen()) { - options.fullscreenable = false; // enables simple fullscreen mode - } - - const useNativeTabs = isMacintosh && windowSettings?.nativeTabs === true; - if (useNativeTabs) { - options.tabbingIdentifier = this.productService.nameShort; // this opts in to sierra tabs - } - const useCustomTitleStyle = getTitleBarStyle(this.configurationService) === 'custom'; if (useCustomTitleStyle) { options.titleBarStyle = 'hidden'; @@ -421,51 +397,6 @@ export class CodeWindow extends BaseWindow implements ICodeWindow { } } - // Windows Custom System Context Menu - // See https://github.com/electron/electron/issues/24893 - // - // The purpose of this is to allow for the context menu in the Windows Title Bar - // - // Currently, all mouse events in the title bar are captured by the OS - // thus we need to capture them here with a window hook specific to Windows - // and then forward them to the correct window. - if (isWindows && useCustomTitleStyle) { - const WM_INITMENU = 0x0116; // https://docs.microsoft.com/en-us/windows/win32/menurc/wm-initmenu - - // This sets up a listener for the window hook. This is a Windows-only API provided by electron. - this._win.hookWindowMessage(WM_INITMENU, () => { - const [x, y] = this._win.getPosition(); - const cursorPos = screen.getCursorScreenPoint(); - const cx = cursorPos.x - x; - const cy = cursorPos.y - y; - - // In some cases, show the default system context menu - // 1) The mouse position is not within the title bar - // 2) The mouse position is within the title bar, but over the app icon - // We do not know the exact title bar height but we make an estimate based on window height - const shouldTriggerDefaultSystemContextMenu = () => { - // Use the custom context menu when over the title bar, but not over the app icon - // The app icon is estimated to be 30px wide - // The title bar is estimated to be the max of 35px and 15% of the window height - if (cx > 30 && cy >= 0 && cy <= Math.max(this._win.getBounds().height * 0.15, 35)) { - return false; - } - - return true; - }; - - if (!shouldTriggerDefaultSystemContextMenu()) { - // This is necessary to make sure the native system context menu does not show up. - this._win.setEnabled(false); - this._win.setEnabled(true); - - this._onDidTriggerSystemContextMenu.fire({ x: cx, y: cy }); - } - - return 0; - }); - } - // TODO@electron (Electron 4 regression): when running on multiple displays where the target display // to open the window has a larger resolution than the primary display, the window will not size // correctly unless we set the bounds again (https://github.com/microsoft/vscode/issues/74872) @@ -475,6 +406,8 @@ export class CodeWindow extends BaseWindow implements ICodeWindow { // However, when running with native tabs with multiple windows we cannot use this workaround // because there is a potential that the new window will be added as native tab instead of being // a window on its own. In that case calling setBounds() would cause https://github.com/microsoft/vscode/issues/75830 + const windowSettings = this.configurationService.getValue('window'); + const useNativeTabs = isMacintosh && windowSettings?.nativeTabs === true; if ((isMacintosh || isWindows) && hasMultipleDisplays && (!useNativeTabs || BrowserWindow.getAllWindows().length === 1)) { if ([this.windowState.width, this.windowState.height, this.windowState.x, this.windowState.y].every(value => typeof value === 'number')) { this._win.setBounds({ @@ -654,6 +587,52 @@ export class CodeWindow extends BaseWindow implements ICodeWindow { cb({ cancel: false, requestHeaders: Object.assign(details.requestHeaders, headers) }); }); + + // Windows Custom System Context Menu + // See https://github.com/electron/electron/issues/24893 + // + // The purpose of this is to allow for the context menu in the Windows Title Bar + // + // Currently, all mouse events in the title bar are captured by the OS + // thus we need to capture them here with a window hook specific to Windows + // and then forward them to the correct window. + const useCustomTitleStyle = getTitleBarStyle(this.configurationService) === 'custom'; + if (isWindows && useCustomTitleStyle) { + const WM_INITMENU = 0x0116; // https://docs.microsoft.com/en-us/windows/win32/menurc/wm-initmenu + + // This sets up a listener for the window hook. This is a Windows-only API provided by electron. + this._win.hookWindowMessage(WM_INITMENU, () => { + const [x, y] = this._win.getPosition(); + const cursorPos = screen.getCursorScreenPoint(); + const cx = cursorPos.x - x; + const cy = cursorPos.y - y; + + // In some cases, show the default system context menu + // 1) The mouse position is not within the title bar + // 2) The mouse position is within the title bar, but over the app icon + // We do not know the exact title bar height but we make an estimate based on window height + const shouldTriggerDefaultSystemContextMenu = () => { + // Use the custom context menu when over the title bar, but not over the app icon + // The app icon is estimated to be 30px wide + // The title bar is estimated to be the max of 35px and 15% of the window height + if (cx > 30 && cy >= 0 && cy <= Math.max(this._win.getBounds().height * 0.15, 35)) { + return false; + } + + return true; + }; + + if (!shouldTriggerDefaultSystemContextMenu()) { + // This is necessary to make sure the native system context menu does not show up. + this._win.setEnabled(false); + this._win.setEnabled(true); + + this._onDidTriggerSystemContextMenu.fire({ x: cx, y: cy }); + } + + return 0; + }); + } } private marketplaceHeadersPromise: Promise | undefined; diff --git a/src/vs/platform/windows/electron-main/windows.ts b/src/vs/platform/windows/electron-main/windows.ts index dd832b583fd..ff6a5ca8c7e 100644 --- a/src/vs/platform/windows/electron-main/windows.ts +++ b/src/vs/platform/windows/electron-main/windows.ts @@ -10,7 +10,7 @@ import { URI } from 'vs/base/common/uri'; import { NativeParsedArgs } from 'vs/platform/environment/common/argv'; import { ServicesAccessor, createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { ICodeWindow, IWindowState } from 'vs/platform/window/electron-main/window'; -import { IOpenEmptyWindowOptions, IWindowOpenable, IWindowSettings, WindowMinimumSize, zoomLevelToZoomFactor } from 'vs/platform/window/common/window'; +import { IOpenEmptyWindowOptions, IWindowOpenable, IWindowSettings, WindowMinimumSize, useNativeFullScreen, zoomLevelToZoomFactor } from 'vs/platform/window/common/window'; import { IThemeMainService } from 'vs/platform/theme/electron-main/themeMainService'; import { IProductService } from 'vs/platform/product/common/productService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -160,6 +160,15 @@ export function defaultBrowserWindowOptions(accessor: ServicesAccessor, windowSt } } + if (isMacintosh && !useNativeFullScreen(configurationService)) { + options.fullscreenable = false; // enables simple fullscreen mode + } + + const useNativeTabs = isMacintosh && windowSettings?.nativeTabs === true; + if (useNativeTabs) { + options.tabbingIdentifier = productService.nameShort; // this opts in to sierra tabs + } + return options; }