Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/services/auxiliaryWindow/electron-browser/auxiliaryWindowService.ts
5262 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { localize } from '../../../../nls.js';
7
import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';
8
import { IWorkbenchLayoutService } from '../../layout/browser/layoutService.js';
9
import { AuxiliaryWindow, AuxiliaryWindowMode, BrowserAuxiliaryWindowService, IAuxiliaryWindowOpenOptions, IAuxiliaryWindowService } from '../browser/auxiliaryWindowService.js';
10
import { ISandboxGlobals } from '../../../../base/parts/sandbox/electron-browser/globals.js';
11
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
12
import { DisposableStore } from '../../../../base/common/lifecycle.js';
13
import { INativeHostService } from '../../../../platform/native/common/native.js';
14
import { IDialogService } from '../../../../platform/dialogs/common/dialogs.js';
15
import { CodeWindow } from '../../../../base/browser/window.js';
16
import { mark } from '../../../../base/common/performance.js';
17
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
18
import { ShutdownReason } from '../../lifecycle/common/lifecycle.js';
19
import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js';
20
import { Barrier } from '../../../../base/common/async.js';
21
import { IHostService } from '../../host/browser/host.js';
22
import { applyZoom } from '../../../../platform/window/electron-browser/window.js';
23
import { getZoomLevel, isFullscreen, setFullscreen } from '../../../../base/browser/browser.js';
24
import { getActiveWindow } from '../../../../base/browser/dom.js';
25
import { IWorkbenchEnvironmentService } from '../../environment/common/environmentService.js';
26
import { isMacintosh } from '../../../../base/common/platform.js';
27
import { assert } from '../../../../base/common/assert.js';
28
import { IContextMenuService } from '../../../../platform/contextview/browser/contextView.js';
29
30
type NativeCodeWindow = CodeWindow & {
31
readonly vscode: ISandboxGlobals;
32
};
33
34
export class NativeAuxiliaryWindow extends AuxiliaryWindow {
35
36
private skipUnloadConfirmation = false;
37
38
private maximized = false;
39
private alwaysOnTop = false;
40
41
constructor(
42
window: CodeWindow,
43
container: HTMLElement,
44
stylesHaveLoaded: Barrier,
45
@IConfigurationService configurationService: IConfigurationService,
46
@INativeHostService private readonly nativeHostService: INativeHostService,
47
@IInstantiationService private readonly instantiationService: IInstantiationService,
48
@IHostService hostService: IHostService,
49
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
50
@IDialogService private readonly dialogService: IDialogService,
51
@IContextMenuService contextMenuService: IContextMenuService,
52
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService
53
) {
54
super(window, container, stylesHaveLoaded, configurationService, hostService, environmentService, contextMenuService, layoutService);
55
56
if (!isMacintosh) {
57
// For now, limit this to platforms that have clear maximised
58
// transitions (Windows, Linux) via window buttons.
59
this.handleMaximizedState();
60
}
61
62
this.handleFullScreenState();
63
this.handleAlwaysOnTopState();
64
}
65
66
private handleMaximizedState(): void {
67
(async () => {
68
this.maximized = await this.nativeHostService.isMaximized({ targetWindowId: this.window.vscodeWindowId });
69
})();
70
71
this._register(this.nativeHostService.onDidMaximizeWindow(windowId => {
72
if (windowId === this.window.vscodeWindowId) {
73
this.maximized = true;
74
}
75
}));
76
77
this._register(this.nativeHostService.onDidUnmaximizeWindow(windowId => {
78
if (windowId === this.window.vscodeWindowId) {
79
this.maximized = false;
80
}
81
}));
82
}
83
84
private handleAlwaysOnTopState(): void {
85
(async () => {
86
this.alwaysOnTop = await this.nativeHostService.isWindowAlwaysOnTop({ targetWindowId: this.window.vscodeWindowId });
87
})();
88
89
this._register(this.nativeHostService.onDidChangeWindowAlwaysOnTop(({ windowId, alwaysOnTop }) => {
90
if (windowId === this.window.vscodeWindowId) {
91
this.alwaysOnTop = alwaysOnTop;
92
}
93
}));
94
}
95
96
private async handleFullScreenState(): Promise<void> {
97
const fullscreen = await this.nativeHostService.isFullScreen({ targetWindowId: this.window.vscodeWindowId });
98
if (fullscreen) {
99
setFullscreen(true, this.window);
100
}
101
}
102
103
protected override async handleVetoBeforeClose(e: BeforeUnloadEvent, veto: string): Promise<void> {
104
this.preventUnload(e);
105
106
await this.dialogService.error(veto, localize('backupErrorDetails', "Try saving or reverting the editors with unsaved changes first and then try again."));
107
}
108
109
protected override async confirmBeforeClose(e: BeforeUnloadEvent): Promise<void> {
110
if (this.skipUnloadConfirmation) {
111
return;
112
}
113
114
this.preventUnload(e);
115
116
const confirmed = await this.instantiationService.invokeFunction(accessor => NativeAuxiliaryWindow.confirmOnShutdown(accessor, ShutdownReason.CLOSE));
117
if (confirmed) {
118
this.skipUnloadConfirmation = true;
119
this.nativeHostService.closeWindow({ targetWindowId: this.window.vscodeWindowId });
120
}
121
}
122
123
protected override preventUnload(e: BeforeUnloadEvent): void {
124
e.preventDefault();
125
e.returnValue = true;
126
}
127
128
override createState(): IAuxiliaryWindowOpenOptions {
129
const state = super.createState();
130
const fullscreen = isFullscreen(this.window);
131
return {
132
...state,
133
bounds: state.bounds,
134
mode: this.maximized ? AuxiliaryWindowMode.Maximized : fullscreen ? AuxiliaryWindowMode.Fullscreen : AuxiliaryWindowMode.Normal,
135
alwaysOnTop: this.alwaysOnTop
136
};
137
}
138
}
139
140
export class NativeAuxiliaryWindowService extends BrowserAuxiliaryWindowService {
141
142
constructor(
143
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
144
@IConfigurationService configurationService: IConfigurationService,
145
@INativeHostService private readonly nativeHostService: INativeHostService,
146
@IDialogService dialogService: IDialogService,
147
@IInstantiationService private readonly instantiationService: IInstantiationService,
148
@ITelemetryService telemetryService: ITelemetryService,
149
@IHostService hostService: IHostService,
150
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
151
@IContextMenuService contextMenuService: IContextMenuService,
152
) {
153
super(layoutService, dialogService, configurationService, telemetryService, hostService, environmentService, contextMenuService);
154
}
155
156
protected override async resolveWindowId(auxiliaryWindow: NativeCodeWindow): Promise<number> {
157
mark('code/auxiliaryWindow/willResolveWindowId');
158
const windowId = await auxiliaryWindow.vscode.ipcRenderer.invoke('vscode:registerAuxiliaryWindow', this.nativeHostService.windowId);
159
mark('code/auxiliaryWindow/didResolveWindowId');
160
assert(typeof windowId === 'number');
161
162
return windowId;
163
}
164
165
protected override createContainer(auxiliaryWindow: NativeCodeWindow, disposables: DisposableStore, options?: IAuxiliaryWindowOpenOptions) {
166
167
// Zoom level (either explicitly provided or inherited from main window)
168
let windowZoomLevel: number;
169
if (typeof options?.zoomLevel === 'number') {
170
windowZoomLevel = options.zoomLevel;
171
} else {
172
windowZoomLevel = getZoomLevel(getActiveWindow());
173
}
174
175
applyZoom(windowZoomLevel, auxiliaryWindow);
176
177
return super.createContainer(auxiliaryWindow, disposables);
178
}
179
180
protected override createAuxiliaryWindow(targetWindow: CodeWindow, container: HTMLElement, stylesHaveLoaded: Barrier): AuxiliaryWindow {
181
return new NativeAuxiliaryWindow(targetWindow, container, stylesHaveLoaded, this.configurationService, this.nativeHostService, this.instantiationService, this.hostService, this.environmentService, this.dialogService, this.contextMenuService, this.layoutService);
182
}
183
}
184
185
registerSingleton(IAuxiliaryWindowService, NativeAuxiliaryWindowService, InstantiationType.Delayed);
186
187