Path: blob/main/src/vs/workbench/services/auxiliaryWindow/electron-browser/auxiliaryWindowService.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { localize } from '../../../../nls.js';6import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';7import { IWorkbenchLayoutService } from '../../layout/browser/layoutService.js';8import { AuxiliaryWindow, AuxiliaryWindowMode, BrowserAuxiliaryWindowService, IAuxiliaryWindowOpenOptions, IAuxiliaryWindowService } from '../browser/auxiliaryWindowService.js';9import { ISandboxGlobals } from '../../../../base/parts/sandbox/electron-browser/globals.js';10import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';11import { DisposableStore } from '../../../../base/common/lifecycle.js';12import { INativeHostService } from '../../../../platform/native/common/native.js';13import { IDialogService } from '../../../../platform/dialogs/common/dialogs.js';14import { CodeWindow } from '../../../../base/browser/window.js';15import { mark } from '../../../../base/common/performance.js';16import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';17import { ShutdownReason } from '../../lifecycle/common/lifecycle.js';18import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js';19import { Barrier } from '../../../../base/common/async.js';20import { IHostService } from '../../host/browser/host.js';21import { applyZoom } from '../../../../platform/window/electron-browser/window.js';22import { getZoomLevel, isFullscreen, setFullscreen } from '../../../../base/browser/browser.js';23import { getActiveWindow } from '../../../../base/browser/dom.js';24import { IWorkbenchEnvironmentService } from '../../environment/common/environmentService.js';25import { isMacintosh } from '../../../../base/common/platform.js';2627type NativeCodeWindow = CodeWindow & {28readonly vscode: ISandboxGlobals;29};3031export class NativeAuxiliaryWindow extends AuxiliaryWindow {3233private skipUnloadConfirmation = false;3435private maximized = false;36private alwaysOnTop = false;3738constructor(39window: CodeWindow,40container: HTMLElement,41stylesHaveLoaded: Barrier,42@IConfigurationService configurationService: IConfigurationService,43@INativeHostService private readonly nativeHostService: INativeHostService,44@IInstantiationService private readonly instantiationService: IInstantiationService,45@IHostService hostService: IHostService,46@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,47@IDialogService private readonly dialogService: IDialogService48) {49super(window, container, stylesHaveLoaded, configurationService, hostService, environmentService);5051if (!isMacintosh) {52// For now, limit this to platforms that have clear maximised53// transitions (Windows, Linux) via window buttons.54this.handleMaximizedState();55}5657this.handleFullScreenState();58this.handleAlwaysOnTopState();59}6061private handleMaximizedState(): void {62(async () => {63this.maximized = await this.nativeHostService.isMaximized({ targetWindowId: this.window.vscodeWindowId });64})();6566this._register(this.nativeHostService.onDidMaximizeWindow(windowId => {67if (windowId === this.window.vscodeWindowId) {68this.maximized = true;69}70}));7172this._register(this.nativeHostService.onDidUnmaximizeWindow(windowId => {73if (windowId === this.window.vscodeWindowId) {74this.maximized = false;75}76}));77}7879private handleAlwaysOnTopState(): void {80(async () => {81this.alwaysOnTop = await this.nativeHostService.isWindowAlwaysOnTop({ targetWindowId: this.window.vscodeWindowId });82})();8384this._register(this.nativeHostService.onDidChangeWindowAlwaysOnTop(({ windowId, alwaysOnTop }) => {85if (windowId === this.window.vscodeWindowId) {86this.alwaysOnTop = alwaysOnTop;87}88}));89}9091private async handleFullScreenState(): Promise<void> {92const fullscreen = await this.nativeHostService.isFullScreen({ targetWindowId: this.window.vscodeWindowId });93if (fullscreen) {94setFullscreen(true, this.window);95}96}9798protected override async handleVetoBeforeClose(e: BeforeUnloadEvent, veto: string): Promise<void> {99this.preventUnload(e);100101await this.dialogService.error(veto, localize('backupErrorDetails', "Try saving or reverting the editors with unsaved changes first and then try again."));102}103104protected override async confirmBeforeClose(e: BeforeUnloadEvent): Promise<void> {105if (this.skipUnloadConfirmation) {106return;107}108109this.preventUnload(e);110111const confirmed = await this.instantiationService.invokeFunction(accessor => NativeAuxiliaryWindow.confirmOnShutdown(accessor, ShutdownReason.CLOSE));112if (confirmed) {113this.skipUnloadConfirmation = true;114this.nativeHostService.closeWindow({ targetWindowId: this.window.vscodeWindowId });115}116}117118protected override preventUnload(e: BeforeUnloadEvent): void {119e.preventDefault();120e.returnValue = true;121}122123override createState(): IAuxiliaryWindowOpenOptions {124const state = super.createState();125const fullscreen = isFullscreen(this.window);126return {127...state,128bounds: state.bounds,129mode: this.maximized ? AuxiliaryWindowMode.Maximized : fullscreen ? AuxiliaryWindowMode.Fullscreen : AuxiliaryWindowMode.Normal,130alwaysOnTop: this.alwaysOnTop131};132}133}134135export class NativeAuxiliaryWindowService extends BrowserAuxiliaryWindowService {136137constructor(138@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,139@IConfigurationService configurationService: IConfigurationService,140@INativeHostService private readonly nativeHostService: INativeHostService,141@IDialogService dialogService: IDialogService,142@IInstantiationService private readonly instantiationService: IInstantiationService,143@ITelemetryService telemetryService: ITelemetryService,144@IHostService hostService: IHostService,145@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService146) {147super(layoutService, dialogService, configurationService, telemetryService, hostService, environmentService);148}149150protected override async resolveWindowId(auxiliaryWindow: NativeCodeWindow): Promise<number> {151mark('code/auxiliaryWindow/willResolveWindowId');152const windowId = await auxiliaryWindow.vscode.ipcRenderer.invoke('vscode:registerAuxiliaryWindow', this.nativeHostService.windowId);153mark('code/auxiliaryWindow/didResolveWindowId');154155return windowId;156}157158protected override createContainer(auxiliaryWindow: NativeCodeWindow, disposables: DisposableStore, options?: IAuxiliaryWindowOpenOptions) {159160// Zoom level (either explicitly provided or inherited from main window)161let windowZoomLevel: number;162if (typeof options?.zoomLevel === 'number') {163windowZoomLevel = options.zoomLevel;164} else {165windowZoomLevel = getZoomLevel(getActiveWindow());166}167168applyZoom(windowZoomLevel, auxiliaryWindow);169170return super.createContainer(auxiliaryWindow, disposables);171}172173protected override createAuxiliaryWindow(targetWindow: CodeWindow, container: HTMLElement, stylesHaveLoaded: Barrier): AuxiliaryWindow {174return new NativeAuxiliaryWindow(targetWindow, container, stylesHaveLoaded, this.configurationService, this.nativeHostService, this.instantiationService, this.hostService, this.environmentService, this.dialogService);175}176}177178registerSingleton(IAuxiliaryWindowService, NativeAuxiliaryWindowService, InstantiationType.Delayed);179180181