Path: blob/main/src/vs/workbench/services/layout/browser/layoutService.ts
4780 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 { refineServiceDecorator } from '../../../../platform/instantiation/common/instantiation.js';6import { Event } from '../../../../base/common/event.js';7import { ILayoutService } from '../../../../platform/layout/browser/layoutService.js';8import { Part } from '../../../browser/part.js';9import { IDimension } from '../../../../base/browser/dom.js';10import { Direction, IViewSize } from '../../../../base/browser/ui/grid/grid.js';11import { isMacintosh, isNative, isWeb } from '../../../../base/common/platform.js';12import { isAuxiliaryWindow } from '../../../../base/browser/window.js';13import { CustomTitleBarVisibility, TitleBarSetting, getMenuBarVisibility, hasCustomTitlebar, hasNativeMenu, hasNativeTitlebar } from '../../../../platform/window/common/window.js';14import { isFullscreen, isWCOEnabled } from '../../../../base/browser/browser.js';15import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';16import { IDisposable } from '../../../../base/common/lifecycle.js';1718export const IWorkbenchLayoutService = refineServiceDecorator<ILayoutService, IWorkbenchLayoutService>(ILayoutService);1920export const enum Parts {21TITLEBAR_PART = 'workbench.parts.titlebar',22BANNER_PART = 'workbench.parts.banner',23ACTIVITYBAR_PART = 'workbench.parts.activitybar',24SIDEBAR_PART = 'workbench.parts.sidebar',25PANEL_PART = 'workbench.parts.panel',26AUXILIARYBAR_PART = 'workbench.parts.auxiliarybar',27EDITOR_PART = 'workbench.parts.editor',28STATUSBAR_PART = 'workbench.parts.statusbar'29}3031export const enum ZenModeSettings {32SHOW_TABS = 'zenMode.showTabs',33HIDE_LINENUMBERS = 'zenMode.hideLineNumbers',34HIDE_STATUSBAR = 'zenMode.hideStatusBar',35HIDE_ACTIVITYBAR = 'zenMode.hideActivityBar',36CENTER_LAYOUT = 'zenMode.centerLayout',37FULLSCREEN = 'zenMode.fullScreen',38RESTORE = 'zenMode.restore',39SILENT_NOTIFICATIONS = 'zenMode.silentNotifications',40}4142export const enum LayoutSettings {43ACTIVITY_BAR_LOCATION = 'workbench.activityBar.location',44EDITOR_TABS_MODE = 'workbench.editor.showTabs',45EDITOR_ACTIONS_LOCATION = 'workbench.editor.editorActionsLocation',46COMMAND_CENTER = 'window.commandCenter',47LAYOUT_ACTIONS = 'workbench.layoutControl.enabled'48}4950export const enum ActivityBarPosition {51DEFAULT = 'default',52TOP = 'top',53BOTTOM = 'bottom',54HIDDEN = 'hidden'55}5657export const enum EditorTabsMode {58MULTIPLE = 'multiple',59SINGLE = 'single',60NONE = 'none'61}6263export const enum EditorActionsLocation {64DEFAULT = 'default',65TITLEBAR = 'titleBar',66HIDDEN = 'hidden'67}6869export const enum Position {70LEFT,71RIGHT,72BOTTOM,73TOP74}7576export function isHorizontal(position: Position): boolean {77return position === Position.BOTTOM || position === Position.TOP;78}7980export const enum PartOpensMaximizedOptions {81ALWAYS,82NEVER,83REMEMBER_LAST84}8586export type PanelAlignment = 'left' | 'center' | 'right' | 'justify';8788export function positionToString(position: Position): string {89switch (position) {90case Position.LEFT: return 'left';91case Position.RIGHT: return 'right';92case Position.BOTTOM: return 'bottom';93case Position.TOP: return 'top';94default: return 'bottom';95}96}9798const positionsByString: { [key: string]: Position } = {99[positionToString(Position.LEFT)]: Position.LEFT,100[positionToString(Position.RIGHT)]: Position.RIGHT,101[positionToString(Position.BOTTOM)]: Position.BOTTOM,102[positionToString(Position.TOP)]: Position.TOP103};104105export function positionFromString(str: string): Position {106return positionsByString[str];107}108109function partOpensMaximizedSettingToString(setting: PartOpensMaximizedOptions): string {110switch (setting) {111case PartOpensMaximizedOptions.ALWAYS: return 'always';112case PartOpensMaximizedOptions.NEVER: return 'never';113case PartOpensMaximizedOptions.REMEMBER_LAST: return 'preserve';114default: return 'preserve';115}116}117118const partOpensMaximizedByString: { [key: string]: PartOpensMaximizedOptions } = {119[partOpensMaximizedSettingToString(PartOpensMaximizedOptions.ALWAYS)]: PartOpensMaximizedOptions.ALWAYS,120[partOpensMaximizedSettingToString(PartOpensMaximizedOptions.NEVER)]: PartOpensMaximizedOptions.NEVER,121[partOpensMaximizedSettingToString(PartOpensMaximizedOptions.REMEMBER_LAST)]: PartOpensMaximizedOptions.REMEMBER_LAST122};123124export function partOpensMaximizedFromString(str: string): PartOpensMaximizedOptions {125return partOpensMaximizedByString[str];126}127128export type MULTI_WINDOW_PARTS = Parts.EDITOR_PART | Parts.STATUSBAR_PART | Parts.TITLEBAR_PART;129export type SINGLE_WINDOW_PARTS = Exclude<Parts, MULTI_WINDOW_PARTS>;130131export function isMultiWindowPart(part: Parts): part is MULTI_WINDOW_PARTS {132return part === Parts.EDITOR_PART ||133part === Parts.STATUSBAR_PART ||134part === Parts.TITLEBAR_PART;135}136137export interface IWorkbenchLayoutService extends ILayoutService {138139readonly _serviceBrand: undefined;140141/**142* Emits when the zen mode is enabled or disabled.143*/144readonly onDidChangeZenMode: Event<boolean>;145146/**147* Emits when the target window is maximized or unmaximized.148*/149readonly onDidChangeWindowMaximized: Event<{ readonly windowId: number; readonly maximized: boolean }>;150151/**152* Emits when main editor centered layout is enabled or disabled.153*/154readonly onDidChangeMainEditorCenteredLayout: Event<boolean>;155156/*157* Emit when panel position changes.158*/159readonly onDidChangePanelPosition: Event<string>;160161/**162* Emit when panel alignment changes.163*/164readonly onDidChangePanelAlignment: Event<PanelAlignment>;165166/**167* Emit when part visibility changes168*/169readonly onDidChangePartVisibility: Event<void>;170171/**172* Emit when notifications (toasts or center) visibility changes.173*/174readonly onDidChangeNotificationsVisibility: Event<boolean>;175176/*177* Emit when auxiliary bar maximized state changes.178*/179readonly onDidChangeAuxiliaryBarMaximized: Event<void>;180181/**182* True if a default layout with default editors was applied at startup183*/184readonly openedDefaultEditors: boolean;185186/**187* Run a layout of the workbench.188*/189layout(): void;190191/**192* Asks the part service if all parts have been fully restored. For editor part193* this means that the contents of visible editors have loaded.194*/195isRestored(): boolean;196197/**198* A promise for to await the `isRestored()` condition to be `true`.199*/200readonly whenRestored: Promise<void>;201202/**203* Returns whether the given part has the keyboard focus or not.204*/205hasFocus(part: Parts): boolean;206207/**208* Focuses the part in the target window. If the part is not visible this is a noop.209*/210focusPart(part: SINGLE_WINDOW_PARTS): void;211focusPart(part: MULTI_WINDOW_PARTS, targetWindow: Window): void;212focusPart(part: Parts, targetWindow: Window): void;213214/**215* Returns the target window container or parts HTML element within, if there is one.216*/217getContainer(targetWindow: Window): HTMLElement;218getContainer(targetWindow: Window, part: Parts): HTMLElement | undefined;219220/**221* Returns if the part is visible in the target window.222*/223isVisible(part: SINGLE_WINDOW_PARTS): boolean;224isVisible(part: MULTI_WINDOW_PARTS, targetWindow: Window): boolean;225isVisible(part: Parts, targetWindow: Window): boolean;226227/**228* Set part hidden or not in the target window.229*/230setPartHidden(hidden: boolean, part: Parts): void;231232/**233* Maximizes the panel height if the panel is not already maximized.234* Shrinks the panel to the default starting size if the panel is maximized.235*/236toggleMaximizedPanel(): void;237238/**239* Returns true if the panel is maximized.240*/241isPanelMaximized(): boolean;242243/**244* Maximizes the auxiliary sidebar by hiding the editor and panel areas.245* Restores the previous layout if the auxiliary sidebar is already maximized.246*/247toggleMaximizedAuxiliaryBar(): void;248249/**250* Maximizes or restores the auxiliary sidebar.251*252* @returns `true` if there was a change in the maximization state.253*/254setAuxiliaryBarMaximized(maximized: boolean): boolean;255256/**257* Returns true if the auxiliary sidebar is maximized.258*/259isAuxiliaryBarMaximized(): boolean;260261/**262* Returns true if the main window has a border.263*/264hasMainWindowBorder(): boolean;265266/**267* Returns the main window border radius if any.268*/269getMainWindowBorderRadius(): string | undefined;270271/**272* Gets the current side bar position. Note that the sidebar can be hidden too.273*/274getSideBarPosition(): Position;275276/**277* Toggles the menu bar visibility.278*/279toggleMenuBar(): void;280281/*282* Gets the current panel position. Note that the panel can be hidden too.283*/284getPanelPosition(): Position;285286/**287* Sets the panel position.288*/289setPanelPosition(position: Position): void;290291/**292* Gets the panel alignement.293*/294getPanelAlignment(): PanelAlignment;295296/**297* Sets the panel alignment.298*/299setPanelAlignment(alignment: PanelAlignment): void;300301/**302* Gets the maximum possible size for editor in the given container.303*/304getMaximumEditorDimensions(container: HTMLElement): IDimension;305306/**307* Toggles the workbench in and out of zen mode - parts get hidden and window goes fullscreen.308*/309toggleZenMode(): void;310311/**312* Returns whether the centered editor layout is active on the main editor part.313*/314isMainEditorLayoutCentered(): boolean;315316/**317* Sets the main editor part in and out of centered layout.318*/319centerMainEditorLayout(active: boolean): void;320321/**322* Get the provided parts size in the main window.323*/324getSize(part: Parts): IViewSize;325326/**327* Set the provided parts size in the main window.328*/329setSize(part: Parts, size: IViewSize): void;330331/**332* Resize the provided part in the main window.333*/334resizePart(part: Parts, sizeChangeWidth: number, sizeChangeHeight: number): void;335336/**337* Register a part to participate in the layout.338*/339registerPart(part: Part): IDisposable;340341/**342* Returns whether the target window is maximized.343*/344isWindowMaximized(targetWindow: Window): boolean;345346/**347* Updates the maximized state of the target window.348*/349updateWindowMaximizedState(targetWindow: Window, maximized: boolean): void;350351/**352* Returns the next visible view part in a given direction in the main window.353*/354getVisibleNeighborPart(part: Parts, direction: Direction): Parts | undefined;355}356357export function shouldShowCustomTitleBar(configurationService: IConfigurationService, window: Window, menuBarToggled?: boolean): boolean {358if (!hasCustomTitlebar(configurationService)) {359return false;360}361362const inFullscreen = isFullscreen(window);363const nativeTitleBarEnabled = hasNativeTitlebar(configurationService);364365if (!isWeb) {366const showCustomTitleBar = configurationService.getValue<CustomTitleBarVisibility>(TitleBarSetting.CUSTOM_TITLE_BAR_VISIBILITY);367if (showCustomTitleBar === CustomTitleBarVisibility.NEVER && nativeTitleBarEnabled || showCustomTitleBar === CustomTitleBarVisibility.WINDOWED && inFullscreen) {368return false;369}370}371372if (!isTitleBarEmpty(configurationService)) {373return true;374}375376// Hide custom title bar when native title bar enabled and custom title bar is empty377if (nativeTitleBarEnabled && hasNativeMenu(configurationService)) {378return false;379}380381// macOS desktop does not need a title bar when full screen382if (isMacintosh && isNative) {383return !inFullscreen;384}385386// non-fullscreen native must show the title bar387if (isNative && !inFullscreen) {388return true;389}390391// if WCO is visible, we have to show the title bar392if (isWCOEnabled() && !inFullscreen) {393return true;394}395396// remaining behavior is based on menubar visibility397const menuBarVisibility = !isAuxiliaryWindow(window) ? getMenuBarVisibility(configurationService) : 'hidden';398switch (menuBarVisibility) {399case 'classic':400return !inFullscreen || !!menuBarToggled;401case 'compact':402case 'hidden':403return false;404case 'toggle':405return !!menuBarToggled;406case 'visible':407return true;408default:409return isWeb ? false : !inFullscreen || !!menuBarToggled;410}411}412413function isTitleBarEmpty(configurationService: IConfigurationService): boolean {414415// with the command center enabled, we should always show416if (configurationService.getValue<boolean>(LayoutSettings.COMMAND_CENTER)) {417return false;418}419420// with the activity bar on top, we should always show421const activityBarPosition = configurationService.getValue<ActivityBarPosition>(LayoutSettings.ACTIVITY_BAR_LOCATION);422if (activityBarPosition === ActivityBarPosition.TOP || activityBarPosition === ActivityBarPosition.BOTTOM) {423return false;424}425426// with the editor actions on top, we should always show427const editorActionsLocation = configurationService.getValue<EditorActionsLocation>(LayoutSettings.EDITOR_ACTIONS_LOCATION);428const editorTabsMode = configurationService.getValue<EditorTabsMode>(LayoutSettings.EDITOR_TABS_MODE);429if (editorActionsLocation === EditorActionsLocation.TITLEBAR || editorActionsLocation === EditorActionsLocation.DEFAULT && editorTabsMode === EditorTabsMode.NONE) {430return false;431}432433// with the layout actions on top, we should always show434if (configurationService.getValue<boolean>(LayoutSettings.LAYOUT_ACTIONS)) {435return false;436}437438return true;439}440441442