Path: blob/main/src/vs/workbench/services/layout/browser/layoutService.ts
5237 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',44ACTIVITY_BAR_AUTO_HIDE = 'workbench.activityBar.autoHide',45EDITOR_TABS_MODE = 'workbench.editor.showTabs',46EDITOR_ACTIONS_LOCATION = 'workbench.editor.editorActionsLocation',47COMMAND_CENTER = 'window.commandCenter',48LAYOUT_ACTIONS = 'workbench.layoutControl.enabled'49}5051export const enum ActivityBarPosition {52DEFAULT = 'default',53TOP = 'top',54BOTTOM = 'bottom',55HIDDEN = 'hidden'56}5758export const enum EditorTabsMode {59MULTIPLE = 'multiple',60SINGLE = 'single',61NONE = 'none'62}6364export const enum EditorActionsLocation {65DEFAULT = 'default',66TITLEBAR = 'titleBar',67HIDDEN = 'hidden'68}6970export const enum Position {71LEFT,72RIGHT,73BOTTOM,74TOP75}7677export function isHorizontal(position: Position): boolean {78return position === Position.BOTTOM || position === Position.TOP;79}8081export const enum PartOpensMaximizedOptions {82ALWAYS,83NEVER,84REMEMBER_LAST85}8687export type PanelAlignment = 'left' | 'center' | 'right' | 'justify';8889export function positionToString(position: Position): string {90switch (position) {91case Position.LEFT: return 'left';92case Position.RIGHT: return 'right';93case Position.BOTTOM: return 'bottom';94case Position.TOP: return 'top';95default: return 'bottom';96}97}9899const positionsByString: { [key: string]: Position } = {100[positionToString(Position.LEFT)]: Position.LEFT,101[positionToString(Position.RIGHT)]: Position.RIGHT,102[positionToString(Position.BOTTOM)]: Position.BOTTOM,103[positionToString(Position.TOP)]: Position.TOP104};105106export function positionFromString(str: string): Position {107return positionsByString[str];108}109110function partOpensMaximizedSettingToString(setting: PartOpensMaximizedOptions): string {111switch (setting) {112case PartOpensMaximizedOptions.ALWAYS: return 'always';113case PartOpensMaximizedOptions.NEVER: return 'never';114case PartOpensMaximizedOptions.REMEMBER_LAST: return 'preserve';115default: return 'preserve';116}117}118119const partOpensMaximizedByString: { [key: string]: PartOpensMaximizedOptions } = {120[partOpensMaximizedSettingToString(PartOpensMaximizedOptions.ALWAYS)]: PartOpensMaximizedOptions.ALWAYS,121[partOpensMaximizedSettingToString(PartOpensMaximizedOptions.NEVER)]: PartOpensMaximizedOptions.NEVER,122[partOpensMaximizedSettingToString(PartOpensMaximizedOptions.REMEMBER_LAST)]: PartOpensMaximizedOptions.REMEMBER_LAST123};124125export function partOpensMaximizedFromString(str: string): PartOpensMaximizedOptions {126return partOpensMaximizedByString[str];127}128129export type MULTI_WINDOW_PARTS = Parts.EDITOR_PART | Parts.STATUSBAR_PART | Parts.TITLEBAR_PART;130export type SINGLE_WINDOW_PARTS = Exclude<Parts, MULTI_WINDOW_PARTS>;131132export function isMultiWindowPart(part: Parts): part is MULTI_WINDOW_PARTS {133return part === Parts.EDITOR_PART ||134part === Parts.STATUSBAR_PART ||135part === Parts.TITLEBAR_PART;136}137138export interface IPartVisibilityChangeEvent {139readonly partId: string;140readonly visible: boolean;141}142143export interface IWorkbenchLayoutService extends ILayoutService {144145readonly _serviceBrand: undefined;146147/**148* Emits when the zen mode is enabled or disabled.149*/150readonly onDidChangeZenMode: Event<boolean>;151152/**153* Emits when the target window is maximized or unmaximized.154*/155readonly onDidChangeWindowMaximized: Event<{ readonly windowId: number; readonly maximized: boolean }>;156157/**158* Emits when main editor centered layout is enabled or disabled.159*/160readonly onDidChangeMainEditorCenteredLayout: Event<boolean>;161162/*163* Emit when panel position changes.164*/165readonly onDidChangePanelPosition: Event<string>;166167/**168* Emit when panel alignment changes.169*/170readonly onDidChangePanelAlignment: Event<PanelAlignment>;171172/**173* Emit when part visibility changes.174*/175readonly onDidChangePartVisibility: Event<IPartVisibilityChangeEvent>;176177/**178* Emit when notifications (toasts or center) visibility changes.179*/180readonly onDidChangeNotificationsVisibility: Event<boolean>;181182/*183* Emit when auxiliary bar maximized state changes.184*/185readonly onDidChangeAuxiliaryBarMaximized: Event<void>;186187/**188* True if a default layout with default editors was applied at startup189*/190readonly openedDefaultEditors: boolean;191192/**193* Run a layout of the workbench.194*/195layout(): void;196197/**198* Asks the part service if all parts have been fully restored. For editor part199* this means that the contents of visible editors have loaded.200*/201isRestored(): boolean;202203/**204* A promise for to await the `isRestored()` condition to be `true`.205*/206readonly whenRestored: Promise<void>;207208/**209* Returns whether the given part has the keyboard focus or not.210*/211hasFocus(part: Parts): boolean;212213/**214* Focuses the part in the target window. If the part is not visible this is a noop.215*/216focusPart(part: SINGLE_WINDOW_PARTS): void;217focusPart(part: MULTI_WINDOW_PARTS, targetWindow: Window): void;218focusPart(part: Parts, targetWindow: Window): void;219220/**221* Returns the target window container or parts HTML element within, if there is one.222*/223getContainer(targetWindow: Window): HTMLElement;224getContainer(targetWindow: Window, part: Parts): HTMLElement | undefined;225226/**227* Returns if the part is visible in the target window.228*/229isVisible(part: SINGLE_WINDOW_PARTS): boolean;230isVisible(part: MULTI_WINDOW_PARTS, targetWindow: Window): boolean;231isVisible(part: Parts, targetWindow: Window): boolean;232233/**234* Set part hidden or not in the target window.235*/236setPartHidden(hidden: boolean, part: Parts): void;237238/**239* Maximizes the panel height if the panel is not already maximized.240* Shrinks the panel to the default starting size if the panel is maximized.241*/242toggleMaximizedPanel(): void;243244/**245* Returns true if the panel is maximized.246*/247isPanelMaximized(): boolean;248249/**250* Maximizes the auxiliary sidebar by hiding the editor and panel areas.251* Restores the previous layout if the auxiliary sidebar is already maximized.252*/253toggleMaximizedAuxiliaryBar(): void;254255/**256* Maximizes or restores the auxiliary sidebar.257*258* @returns `true` if there was a change in the maximization state.259*/260setAuxiliaryBarMaximized(maximized: boolean): boolean;261262/**263* Returns true if the auxiliary sidebar is maximized.264*/265isAuxiliaryBarMaximized(): boolean;266267/**268* Returns true if the main window has a border.269*/270hasMainWindowBorder(): boolean;271272/**273* Returns the main window border radius if any.274*/275getMainWindowBorderRadius(): string | undefined;276277/**278* Gets the current side bar position. Note that the sidebar can be hidden too.279*/280getSideBarPosition(): Position;281282/**283* Toggles the menu bar visibility.284*/285toggleMenuBar(): void;286287/*288* Gets the current panel position. Note that the panel can be hidden too.289*/290getPanelPosition(): Position;291292/**293* Sets the panel position.294*/295setPanelPosition(position: Position): void;296297/**298* Gets the panel alignement.299*/300getPanelAlignment(): PanelAlignment;301302/**303* Sets the panel alignment.304*/305setPanelAlignment(alignment: PanelAlignment): void;306307/**308* Gets the maximum possible size for editor in the given container.309*/310getMaximumEditorDimensions(container: HTMLElement): IDimension;311312/**313* Toggles the workbench in and out of zen mode - parts get hidden and window goes fullscreen.314*/315toggleZenMode(): void;316317/**318* Returns whether the centered editor layout is active on the main editor part.319*/320isMainEditorLayoutCentered(): boolean;321322/**323* Sets the main editor part in and out of centered layout.324*/325centerMainEditorLayout(active: boolean): void;326327/**328* Get the provided parts size in the main window.329*/330getSize(part: Parts): IViewSize;331332/**333* Set the provided parts size in the main window.334*/335setSize(part: Parts, size: IViewSize): void;336337/**338* Resize the provided part in the main window.339*/340resizePart(part: Parts, sizeChangeWidth: number, sizeChangeHeight: number): void;341342/**343* Register a part to participate in the layout.344*/345registerPart(part: Part): IDisposable;346347/**348* Returns whether the target window is maximized.349*/350isWindowMaximized(targetWindow: Window): boolean;351352/**353* Updates the maximized state of the target window.354*/355updateWindowMaximizedState(targetWindow: Window, maximized: boolean): void;356357/**358* Returns the next visible view part in a given direction in the main window.359*/360getVisibleNeighborPart(part: Parts, direction: Direction): Parts | undefined;361}362363export function shouldShowCustomTitleBar(configurationService: IConfigurationService, window: Window, menuBarToggled?: boolean): boolean {364if (!hasCustomTitlebar(configurationService)) {365return false;366}367368const inFullscreen = isFullscreen(window);369const nativeTitleBarEnabled = hasNativeTitlebar(configurationService);370371if (!isWeb) {372const showCustomTitleBar = configurationService.getValue<CustomTitleBarVisibility>(TitleBarSetting.CUSTOM_TITLE_BAR_VISIBILITY);373if (showCustomTitleBar === CustomTitleBarVisibility.NEVER && nativeTitleBarEnabled || showCustomTitleBar === CustomTitleBarVisibility.WINDOWED && inFullscreen) {374return false;375}376}377378if (!isTitleBarEmpty(configurationService)) {379return true;380}381382// Hide custom title bar when native title bar enabled and custom title bar is empty383if (nativeTitleBarEnabled && hasNativeMenu(configurationService)) {384return false;385}386387// macOS desktop does not need a title bar when full screen388if (isMacintosh && isNative) {389return !inFullscreen;390}391392// non-fullscreen native must show the title bar393if (isNative && !inFullscreen) {394return true;395}396397// if WCO is visible, we have to show the title bar398if (isWCOEnabled() && !inFullscreen) {399return true;400}401402// remaining behavior is based on menubar visibility403const menuBarVisibility = !isAuxiliaryWindow(window) ? getMenuBarVisibility(configurationService) : 'hidden';404switch (menuBarVisibility) {405case 'classic':406return !inFullscreen || !!menuBarToggled;407case 'compact':408case 'hidden':409return false;410case 'toggle':411return !!menuBarToggled;412case 'visible':413return true;414default:415return isWeb ? false : !inFullscreen || !!menuBarToggled;416}417}418419function isTitleBarEmpty(configurationService: IConfigurationService): boolean {420421// with the command center enabled, we should always show422if (configurationService.getValue<boolean>(LayoutSettings.COMMAND_CENTER)) {423return false;424}425426// with the activity bar on top, we should always show427const activityBarPosition = configurationService.getValue<ActivityBarPosition>(LayoutSettings.ACTIVITY_BAR_LOCATION);428if (activityBarPosition === ActivityBarPosition.TOP || activityBarPosition === ActivityBarPosition.BOTTOM) {429return false;430}431432// with the editor actions on top, we should always show433const editorActionsLocation = configurationService.getValue<EditorActionsLocation>(LayoutSettings.EDITOR_ACTIONS_LOCATION);434const editorTabsMode = configurationService.getValue<EditorTabsMode>(LayoutSettings.EDITOR_TABS_MODE);435if (editorActionsLocation === EditorActionsLocation.TITLEBAR || editorActionsLocation === EditorActionsLocation.DEFAULT && editorTabsMode === EditorTabsMode.NONE) {436return false;437}438439// with the layout actions on top, we should always show440if (configurationService.getValue<boolean>(LayoutSettings.LAYOUT_ACTIONS)) {441return false;442}443444return true;445}446447448