Path: blob/main/src/vs/sessions/electron-browser/parts/titlebarPart.ts
13394 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 { getZoomFactor } from '../../../base/browser/browser.js';6import { getWindow, getWindowId } from '../../../base/browser/dom.js';7import { IConfigurationService } from '../../../platform/configuration/common/configuration.js';8import { IContextKeyService } from '../../../platform/contextkey/common/contextkey.js';9import { IContextMenuService } from '../../../platform/contextview/browser/contextView.js';10import { IInstantiationService } from '../../../platform/instantiation/common/instantiation.js';11import { INativeHostService } from '../../../platform/native/common/native.js';12import { IProductService } from '../../../platform/product/common/productService.js';13import { IStorageService } from '../../../platform/storage/common/storage.js';14import { IThemeService } from '../../../platform/theme/common/themeService.js';15import { useWindowControlsOverlay } from '../../../platform/window/common/window.js';16import { IsWindowAlwaysOnTopContext } from '../../../workbench/common/contextkeys.js';17import { IHostService } from '../../../workbench/services/host/browser/host.js';18import { IWorkbenchLayoutService, Parts } from '../../../workbench/services/layout/browser/layoutService.js';19import { IAuxiliaryTitlebarPart } from '../../../workbench/browser/parts/titlebar/titlebarPart.js';20import { IEditorGroupsContainer } from '../../../workbench/services/editor/common/editorGroupsService.js';21import { CodeWindow, mainWindow } from '../../../base/browser/window.js';22import { TitlebarPart, TitleService } from '../../browser/parts/titlebarPart.js';23import { isMacintosh } from '../../../base/common/platform.js';2425export class NativeTitlebarPart extends TitlebarPart {2627private cachedWindowControlStyles: { bgColor: string; fgColor: string } | undefined;28private cachedWindowControlHeight: number | undefined;2930constructor(31id: string,32targetWindow: CodeWindow,33@IContextMenuService contextMenuService: IContextMenuService,34@IConfigurationService configurationService: IConfigurationService,35@IInstantiationService instantiationService: IInstantiationService,36@IThemeService themeService: IThemeService,37@IStorageService storageService: IStorageService,38@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,39@IContextKeyService contextKeyService: IContextKeyService,40@IHostService hostService: IHostService,41@IProductService private readonly productService: IProductService,42@INativeHostService private readonly nativeHostService: INativeHostService,43) {44super(id, targetWindow, contextMenuService, configurationService, instantiationService, themeService, storageService, layoutService, contextKeyService, hostService);4546this.handleWindowsAlwaysOnTop(targetWindow.vscodeWindowId, contextKeyService);47}4849protected override createContentArea(parent: HTMLElement): HTMLElement {5051// Workaround for macOS/Electron bug where the window does not52// appear in the "Windows" menu if the first `document.title`53// matches the BrowserWindow's initial title.54// See: https://github.com/microsoft/vscode/issues/19128855if (isMacintosh) {56const window = getWindow(this.element);57const nativeTitle = this.productService.nameLong;58if (!window.document.title || window.document.title === nativeTitle) {59window.document.title = `${nativeTitle} \u200b`;60}61window.document.title = nativeTitle;62}6364return super.createContentArea(parent);65}6667private async handleWindowsAlwaysOnTop(targetWindowId: number, contextKeyService: IContextKeyService): Promise<void> {68const isWindowAlwaysOnTopContext = IsWindowAlwaysOnTopContext.bindTo(contextKeyService);6970this._register(this.nativeHostService.onDidChangeWindowAlwaysOnTop(({ windowId, alwaysOnTop }) => {71if (windowId === targetWindowId) {72isWindowAlwaysOnTopContext.set(alwaysOnTop);73}74}));7576isWindowAlwaysOnTopContext.set(await this.nativeHostService.isWindowAlwaysOnTop({ targetWindowId }));77}7879override updateStyles(): void {80super.updateStyles();8182if (this.element) {83if (useWindowControlsOverlay(this.configurationService)) {84if (85!this.cachedWindowControlStyles ||86this.cachedWindowControlStyles.bgColor !== this.element.style.backgroundColor ||87this.cachedWindowControlStyles.fgColor !== this.element.style.color88) {89this.cachedWindowControlStyles = {90bgColor: this.element.style.backgroundColor,91fgColor: this.element.style.color92};93this.nativeHostService.updateWindowControls({94targetWindowId: getWindowId(getWindow(this.element)),95backgroundColor: this.element.style.backgroundColor,96foregroundColor: this.element.style.color97});98}99}100}101}102103override layout(width: number, height: number): void {104super.layout(width, height);105106if (useWindowControlsOverlay(this.configurationService)) {107const newHeight = Math.round(height * getZoomFactor(getWindow(this.element)));108if (newHeight !== this.cachedWindowControlHeight) {109this.cachedWindowControlHeight = newHeight;110this.nativeHostService.updateWindowControls({111targetWindowId: getWindowId(getWindow(this.element)),112height: newHeight113});114}115}116}117}118119class MainNativeTitlebarPart extends NativeTitlebarPart {120121constructor(122@IContextMenuService contextMenuService: IContextMenuService,123@IConfigurationService configurationService: IConfigurationService,124@IInstantiationService instantiationService: IInstantiationService,125@IThemeService themeService: IThemeService,126@IStorageService storageService: IStorageService,127@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,128@IContextKeyService contextKeyService: IContextKeyService,129@IHostService hostService: IHostService,130@IProductService productService: IProductService,131@INativeHostService nativeHostService: INativeHostService,132) {133super(Parts.TITLEBAR_PART, mainWindow, contextMenuService, configurationService, instantiationService, themeService, storageService, layoutService, contextKeyService, hostService, productService, nativeHostService);134}135}136137class AuxiliaryNativeTitlebarPart extends NativeTitlebarPart implements IAuxiliaryTitlebarPart {138139private static COUNTER = 1;140141get height() { return this.minimumHeight; }142143constructor(144readonly container: HTMLElement,145private readonly mainTitlebar: TitlebarPart,146@IContextMenuService contextMenuService: IContextMenuService,147@IConfigurationService configurationService: IConfigurationService,148@IInstantiationService instantiationService: IInstantiationService,149@IThemeService themeService: IThemeService,150@IStorageService storageService: IStorageService,151@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,152@IContextKeyService contextKeyService: IContextKeyService,153@IHostService hostService: IHostService,154@IProductService productService: IProductService,155@INativeHostService nativeHostService: INativeHostService,156) {157const id = AuxiliaryNativeTitlebarPart.COUNTER++;158super(`workbench.parts.auxiliaryTitle.${id}`, getWindow(container), contextMenuService, configurationService, instantiationService, themeService, storageService, layoutService, contextKeyService, hostService, productService, nativeHostService);159}160161override get preventZoom(): boolean {162return getZoomFactor(getWindow(this.element)) < 1 || !this.mainTitlebar.hasZoomableElements;163}164}165166export class NativeTitleService extends TitleService {167168protected override createMainTitlebarPart(): MainNativeTitlebarPart {169return this.instantiationService.createInstance(MainNativeTitlebarPart);170}171172protected override doCreateAuxiliaryTitlebarPart(container: HTMLElement, _editorGroupsContainer: IEditorGroupsContainer, instantiationService: IInstantiationService): AuxiliaryNativeTitlebarPart {173return instantiationService.createInstance(AuxiliaryNativeTitlebarPart, container, this.mainPart);174}175}176177178