Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/sessions/electron-browser/parts/titlebarPart.ts
13394 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 { getZoomFactor } from '../../../base/browser/browser.js';
7
import { getWindow, getWindowId } from '../../../base/browser/dom.js';
8
import { IConfigurationService } from '../../../platform/configuration/common/configuration.js';
9
import { IContextKeyService } from '../../../platform/contextkey/common/contextkey.js';
10
import { IContextMenuService } from '../../../platform/contextview/browser/contextView.js';
11
import { IInstantiationService } from '../../../platform/instantiation/common/instantiation.js';
12
import { INativeHostService } from '../../../platform/native/common/native.js';
13
import { IProductService } from '../../../platform/product/common/productService.js';
14
import { IStorageService } from '../../../platform/storage/common/storage.js';
15
import { IThemeService } from '../../../platform/theme/common/themeService.js';
16
import { useWindowControlsOverlay } from '../../../platform/window/common/window.js';
17
import { IsWindowAlwaysOnTopContext } from '../../../workbench/common/contextkeys.js';
18
import { IHostService } from '../../../workbench/services/host/browser/host.js';
19
import { IWorkbenchLayoutService, Parts } from '../../../workbench/services/layout/browser/layoutService.js';
20
import { IAuxiliaryTitlebarPart } from '../../../workbench/browser/parts/titlebar/titlebarPart.js';
21
import { IEditorGroupsContainer } from '../../../workbench/services/editor/common/editorGroupsService.js';
22
import { CodeWindow, mainWindow } from '../../../base/browser/window.js';
23
import { TitlebarPart, TitleService } from '../../browser/parts/titlebarPart.js';
24
import { isMacintosh } from '../../../base/common/platform.js';
25
26
export class NativeTitlebarPart extends TitlebarPart {
27
28
private cachedWindowControlStyles: { bgColor: string; fgColor: string } | undefined;
29
private cachedWindowControlHeight: number | undefined;
30
31
constructor(
32
id: string,
33
targetWindow: CodeWindow,
34
@IContextMenuService contextMenuService: IContextMenuService,
35
@IConfigurationService configurationService: IConfigurationService,
36
@IInstantiationService instantiationService: IInstantiationService,
37
@IThemeService themeService: IThemeService,
38
@IStorageService storageService: IStorageService,
39
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
40
@IContextKeyService contextKeyService: IContextKeyService,
41
@IHostService hostService: IHostService,
42
@IProductService private readonly productService: IProductService,
43
@INativeHostService private readonly nativeHostService: INativeHostService,
44
) {
45
super(id, targetWindow, contextMenuService, configurationService, instantiationService, themeService, storageService, layoutService, contextKeyService, hostService);
46
47
this.handleWindowsAlwaysOnTop(targetWindow.vscodeWindowId, contextKeyService);
48
}
49
50
protected override createContentArea(parent: HTMLElement): HTMLElement {
51
52
// Workaround for macOS/Electron bug where the window does not
53
// appear in the "Windows" menu if the first `document.title`
54
// matches the BrowserWindow's initial title.
55
// See: https://github.com/microsoft/vscode/issues/191288
56
if (isMacintosh) {
57
const window = getWindow(this.element);
58
const nativeTitle = this.productService.nameLong;
59
if (!window.document.title || window.document.title === nativeTitle) {
60
window.document.title = `${nativeTitle} \u200b`;
61
}
62
window.document.title = nativeTitle;
63
}
64
65
return super.createContentArea(parent);
66
}
67
68
private async handleWindowsAlwaysOnTop(targetWindowId: number, contextKeyService: IContextKeyService): Promise<void> {
69
const isWindowAlwaysOnTopContext = IsWindowAlwaysOnTopContext.bindTo(contextKeyService);
70
71
this._register(this.nativeHostService.onDidChangeWindowAlwaysOnTop(({ windowId, alwaysOnTop }) => {
72
if (windowId === targetWindowId) {
73
isWindowAlwaysOnTopContext.set(alwaysOnTop);
74
}
75
}));
76
77
isWindowAlwaysOnTopContext.set(await this.nativeHostService.isWindowAlwaysOnTop({ targetWindowId }));
78
}
79
80
override updateStyles(): void {
81
super.updateStyles();
82
83
if (this.element) {
84
if (useWindowControlsOverlay(this.configurationService)) {
85
if (
86
!this.cachedWindowControlStyles ||
87
this.cachedWindowControlStyles.bgColor !== this.element.style.backgroundColor ||
88
this.cachedWindowControlStyles.fgColor !== this.element.style.color
89
) {
90
this.cachedWindowControlStyles = {
91
bgColor: this.element.style.backgroundColor,
92
fgColor: this.element.style.color
93
};
94
this.nativeHostService.updateWindowControls({
95
targetWindowId: getWindowId(getWindow(this.element)),
96
backgroundColor: this.element.style.backgroundColor,
97
foregroundColor: this.element.style.color
98
});
99
}
100
}
101
}
102
}
103
104
override layout(width: number, height: number): void {
105
super.layout(width, height);
106
107
if (useWindowControlsOverlay(this.configurationService)) {
108
const newHeight = Math.round(height * getZoomFactor(getWindow(this.element)));
109
if (newHeight !== this.cachedWindowControlHeight) {
110
this.cachedWindowControlHeight = newHeight;
111
this.nativeHostService.updateWindowControls({
112
targetWindowId: getWindowId(getWindow(this.element)),
113
height: newHeight
114
});
115
}
116
}
117
}
118
}
119
120
class MainNativeTitlebarPart extends NativeTitlebarPart {
121
122
constructor(
123
@IContextMenuService contextMenuService: IContextMenuService,
124
@IConfigurationService configurationService: IConfigurationService,
125
@IInstantiationService instantiationService: IInstantiationService,
126
@IThemeService themeService: IThemeService,
127
@IStorageService storageService: IStorageService,
128
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
129
@IContextKeyService contextKeyService: IContextKeyService,
130
@IHostService hostService: IHostService,
131
@IProductService productService: IProductService,
132
@INativeHostService nativeHostService: INativeHostService,
133
) {
134
super(Parts.TITLEBAR_PART, mainWindow, contextMenuService, configurationService, instantiationService, themeService, storageService, layoutService, contextKeyService, hostService, productService, nativeHostService);
135
}
136
}
137
138
class AuxiliaryNativeTitlebarPart extends NativeTitlebarPart implements IAuxiliaryTitlebarPart {
139
140
private static COUNTER = 1;
141
142
get height() { return this.minimumHeight; }
143
144
constructor(
145
readonly container: HTMLElement,
146
private readonly mainTitlebar: TitlebarPart,
147
@IContextMenuService contextMenuService: IContextMenuService,
148
@IConfigurationService configurationService: IConfigurationService,
149
@IInstantiationService instantiationService: IInstantiationService,
150
@IThemeService themeService: IThemeService,
151
@IStorageService storageService: IStorageService,
152
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
153
@IContextKeyService contextKeyService: IContextKeyService,
154
@IHostService hostService: IHostService,
155
@IProductService productService: IProductService,
156
@INativeHostService nativeHostService: INativeHostService,
157
) {
158
const id = AuxiliaryNativeTitlebarPart.COUNTER++;
159
super(`workbench.parts.auxiliaryTitle.${id}`, getWindow(container), contextMenuService, configurationService, instantiationService, themeService, storageService, layoutService, contextKeyService, hostService, productService, nativeHostService);
160
}
161
162
override get preventZoom(): boolean {
163
return getZoomFactor(getWindow(this.element)) < 1 || !this.mainTitlebar.hasZoomableElements;
164
}
165
}
166
167
export class NativeTitleService extends TitleService {
168
169
protected override createMainTitlebarPart(): MainNativeTitlebarPart {
170
return this.instantiationService.createInstance(MainNativeTitlebarPart);
171
}
172
173
protected override doCreateAuxiliaryTitlebarPart(container: HTMLElement, _editorGroupsContainer: IEditorGroupsContainer, instantiationService: IInstantiationService): AuxiliaryNativeTitlebarPart {
174
return instantiationService.createInstance(AuxiliaryNativeTitlebarPart, container, this.mainPart);
175
}
176
}
177
178