Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/services/layout/browser/layoutService.ts
5237 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 { refineServiceDecorator } from '../../../../platform/instantiation/common/instantiation.js';
7
import { Event } from '../../../../base/common/event.js';
8
import { ILayoutService } from '../../../../platform/layout/browser/layoutService.js';
9
import { Part } from '../../../browser/part.js';
10
import { IDimension } from '../../../../base/browser/dom.js';
11
import { Direction, IViewSize } from '../../../../base/browser/ui/grid/grid.js';
12
import { isMacintosh, isNative, isWeb } from '../../../../base/common/platform.js';
13
import { isAuxiliaryWindow } from '../../../../base/browser/window.js';
14
import { CustomTitleBarVisibility, TitleBarSetting, getMenuBarVisibility, hasCustomTitlebar, hasNativeMenu, hasNativeTitlebar } from '../../../../platform/window/common/window.js';
15
import { isFullscreen, isWCOEnabled } from '../../../../base/browser/browser.js';
16
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
17
import { IDisposable } from '../../../../base/common/lifecycle.js';
18
19
export const IWorkbenchLayoutService = refineServiceDecorator<ILayoutService, IWorkbenchLayoutService>(ILayoutService);
20
21
export const enum Parts {
22
TITLEBAR_PART = 'workbench.parts.titlebar',
23
BANNER_PART = 'workbench.parts.banner',
24
ACTIVITYBAR_PART = 'workbench.parts.activitybar',
25
SIDEBAR_PART = 'workbench.parts.sidebar',
26
PANEL_PART = 'workbench.parts.panel',
27
AUXILIARYBAR_PART = 'workbench.parts.auxiliarybar',
28
EDITOR_PART = 'workbench.parts.editor',
29
STATUSBAR_PART = 'workbench.parts.statusbar'
30
}
31
32
export const enum ZenModeSettings {
33
SHOW_TABS = 'zenMode.showTabs',
34
HIDE_LINENUMBERS = 'zenMode.hideLineNumbers',
35
HIDE_STATUSBAR = 'zenMode.hideStatusBar',
36
HIDE_ACTIVITYBAR = 'zenMode.hideActivityBar',
37
CENTER_LAYOUT = 'zenMode.centerLayout',
38
FULLSCREEN = 'zenMode.fullScreen',
39
RESTORE = 'zenMode.restore',
40
SILENT_NOTIFICATIONS = 'zenMode.silentNotifications',
41
}
42
43
export const enum LayoutSettings {
44
ACTIVITY_BAR_LOCATION = 'workbench.activityBar.location',
45
ACTIVITY_BAR_AUTO_HIDE = 'workbench.activityBar.autoHide',
46
EDITOR_TABS_MODE = 'workbench.editor.showTabs',
47
EDITOR_ACTIONS_LOCATION = 'workbench.editor.editorActionsLocation',
48
COMMAND_CENTER = 'window.commandCenter',
49
LAYOUT_ACTIONS = 'workbench.layoutControl.enabled'
50
}
51
52
export const enum ActivityBarPosition {
53
DEFAULT = 'default',
54
TOP = 'top',
55
BOTTOM = 'bottom',
56
HIDDEN = 'hidden'
57
}
58
59
export const enum EditorTabsMode {
60
MULTIPLE = 'multiple',
61
SINGLE = 'single',
62
NONE = 'none'
63
}
64
65
export const enum EditorActionsLocation {
66
DEFAULT = 'default',
67
TITLEBAR = 'titleBar',
68
HIDDEN = 'hidden'
69
}
70
71
export const enum Position {
72
LEFT,
73
RIGHT,
74
BOTTOM,
75
TOP
76
}
77
78
export function isHorizontal(position: Position): boolean {
79
return position === Position.BOTTOM || position === Position.TOP;
80
}
81
82
export const enum PartOpensMaximizedOptions {
83
ALWAYS,
84
NEVER,
85
REMEMBER_LAST
86
}
87
88
export type PanelAlignment = 'left' | 'center' | 'right' | 'justify';
89
90
export function positionToString(position: Position): string {
91
switch (position) {
92
case Position.LEFT: return 'left';
93
case Position.RIGHT: return 'right';
94
case Position.BOTTOM: return 'bottom';
95
case Position.TOP: return 'top';
96
default: return 'bottom';
97
}
98
}
99
100
const positionsByString: { [key: string]: Position } = {
101
[positionToString(Position.LEFT)]: Position.LEFT,
102
[positionToString(Position.RIGHT)]: Position.RIGHT,
103
[positionToString(Position.BOTTOM)]: Position.BOTTOM,
104
[positionToString(Position.TOP)]: Position.TOP
105
};
106
107
export function positionFromString(str: string): Position {
108
return positionsByString[str];
109
}
110
111
function partOpensMaximizedSettingToString(setting: PartOpensMaximizedOptions): string {
112
switch (setting) {
113
case PartOpensMaximizedOptions.ALWAYS: return 'always';
114
case PartOpensMaximizedOptions.NEVER: return 'never';
115
case PartOpensMaximizedOptions.REMEMBER_LAST: return 'preserve';
116
default: return 'preserve';
117
}
118
}
119
120
const partOpensMaximizedByString: { [key: string]: PartOpensMaximizedOptions } = {
121
[partOpensMaximizedSettingToString(PartOpensMaximizedOptions.ALWAYS)]: PartOpensMaximizedOptions.ALWAYS,
122
[partOpensMaximizedSettingToString(PartOpensMaximizedOptions.NEVER)]: PartOpensMaximizedOptions.NEVER,
123
[partOpensMaximizedSettingToString(PartOpensMaximizedOptions.REMEMBER_LAST)]: PartOpensMaximizedOptions.REMEMBER_LAST
124
};
125
126
export function partOpensMaximizedFromString(str: string): PartOpensMaximizedOptions {
127
return partOpensMaximizedByString[str];
128
}
129
130
export type MULTI_WINDOW_PARTS = Parts.EDITOR_PART | Parts.STATUSBAR_PART | Parts.TITLEBAR_PART;
131
export type SINGLE_WINDOW_PARTS = Exclude<Parts, MULTI_WINDOW_PARTS>;
132
133
export function isMultiWindowPart(part: Parts): part is MULTI_WINDOW_PARTS {
134
return part === Parts.EDITOR_PART ||
135
part === Parts.STATUSBAR_PART ||
136
part === Parts.TITLEBAR_PART;
137
}
138
139
export interface IPartVisibilityChangeEvent {
140
readonly partId: string;
141
readonly visible: boolean;
142
}
143
144
export interface IWorkbenchLayoutService extends ILayoutService {
145
146
readonly _serviceBrand: undefined;
147
148
/**
149
* Emits when the zen mode is enabled or disabled.
150
*/
151
readonly onDidChangeZenMode: Event<boolean>;
152
153
/**
154
* Emits when the target window is maximized or unmaximized.
155
*/
156
readonly onDidChangeWindowMaximized: Event<{ readonly windowId: number; readonly maximized: boolean }>;
157
158
/**
159
* Emits when main editor centered layout is enabled or disabled.
160
*/
161
readonly onDidChangeMainEditorCenteredLayout: Event<boolean>;
162
163
/*
164
* Emit when panel position changes.
165
*/
166
readonly onDidChangePanelPosition: Event<string>;
167
168
/**
169
* Emit when panel alignment changes.
170
*/
171
readonly onDidChangePanelAlignment: Event<PanelAlignment>;
172
173
/**
174
* Emit when part visibility changes.
175
*/
176
readonly onDidChangePartVisibility: Event<IPartVisibilityChangeEvent>;
177
178
/**
179
* Emit when notifications (toasts or center) visibility changes.
180
*/
181
readonly onDidChangeNotificationsVisibility: Event<boolean>;
182
183
/*
184
* Emit when auxiliary bar maximized state changes.
185
*/
186
readonly onDidChangeAuxiliaryBarMaximized: Event<void>;
187
188
/**
189
* True if a default layout with default editors was applied at startup
190
*/
191
readonly openedDefaultEditors: boolean;
192
193
/**
194
* Run a layout of the workbench.
195
*/
196
layout(): void;
197
198
/**
199
* Asks the part service if all parts have been fully restored. For editor part
200
* this means that the contents of visible editors have loaded.
201
*/
202
isRestored(): boolean;
203
204
/**
205
* A promise for to await the `isRestored()` condition to be `true`.
206
*/
207
readonly whenRestored: Promise<void>;
208
209
/**
210
* Returns whether the given part has the keyboard focus or not.
211
*/
212
hasFocus(part: Parts): boolean;
213
214
/**
215
* Focuses the part in the target window. If the part is not visible this is a noop.
216
*/
217
focusPart(part: SINGLE_WINDOW_PARTS): void;
218
focusPart(part: MULTI_WINDOW_PARTS, targetWindow: Window): void;
219
focusPart(part: Parts, targetWindow: Window): void;
220
221
/**
222
* Returns the target window container or parts HTML element within, if there is one.
223
*/
224
getContainer(targetWindow: Window): HTMLElement;
225
getContainer(targetWindow: Window, part: Parts): HTMLElement | undefined;
226
227
/**
228
* Returns if the part is visible in the target window.
229
*/
230
isVisible(part: SINGLE_WINDOW_PARTS): boolean;
231
isVisible(part: MULTI_WINDOW_PARTS, targetWindow: Window): boolean;
232
isVisible(part: Parts, targetWindow: Window): boolean;
233
234
/**
235
* Set part hidden or not in the target window.
236
*/
237
setPartHidden(hidden: boolean, part: Parts): void;
238
239
/**
240
* Maximizes the panel height if the panel is not already maximized.
241
* Shrinks the panel to the default starting size if the panel is maximized.
242
*/
243
toggleMaximizedPanel(): void;
244
245
/**
246
* Returns true if the panel is maximized.
247
*/
248
isPanelMaximized(): boolean;
249
250
/**
251
* Maximizes the auxiliary sidebar by hiding the editor and panel areas.
252
* Restores the previous layout if the auxiliary sidebar is already maximized.
253
*/
254
toggleMaximizedAuxiliaryBar(): void;
255
256
/**
257
* Maximizes or restores the auxiliary sidebar.
258
*
259
* @returns `true` if there was a change in the maximization state.
260
*/
261
setAuxiliaryBarMaximized(maximized: boolean): boolean;
262
263
/**
264
* Returns true if the auxiliary sidebar is maximized.
265
*/
266
isAuxiliaryBarMaximized(): boolean;
267
268
/**
269
* Returns true if the main window has a border.
270
*/
271
hasMainWindowBorder(): boolean;
272
273
/**
274
* Returns the main window border radius if any.
275
*/
276
getMainWindowBorderRadius(): string | undefined;
277
278
/**
279
* Gets the current side bar position. Note that the sidebar can be hidden too.
280
*/
281
getSideBarPosition(): Position;
282
283
/**
284
* Toggles the menu bar visibility.
285
*/
286
toggleMenuBar(): void;
287
288
/*
289
* Gets the current panel position. Note that the panel can be hidden too.
290
*/
291
getPanelPosition(): Position;
292
293
/**
294
* Sets the panel position.
295
*/
296
setPanelPosition(position: Position): void;
297
298
/**
299
* Gets the panel alignement.
300
*/
301
getPanelAlignment(): PanelAlignment;
302
303
/**
304
* Sets the panel alignment.
305
*/
306
setPanelAlignment(alignment: PanelAlignment): void;
307
308
/**
309
* Gets the maximum possible size for editor in the given container.
310
*/
311
getMaximumEditorDimensions(container: HTMLElement): IDimension;
312
313
/**
314
* Toggles the workbench in and out of zen mode - parts get hidden and window goes fullscreen.
315
*/
316
toggleZenMode(): void;
317
318
/**
319
* Returns whether the centered editor layout is active on the main editor part.
320
*/
321
isMainEditorLayoutCentered(): boolean;
322
323
/**
324
* Sets the main editor part in and out of centered layout.
325
*/
326
centerMainEditorLayout(active: boolean): void;
327
328
/**
329
* Get the provided parts size in the main window.
330
*/
331
getSize(part: Parts): IViewSize;
332
333
/**
334
* Set the provided parts size in the main window.
335
*/
336
setSize(part: Parts, size: IViewSize): void;
337
338
/**
339
* Resize the provided part in the main window.
340
*/
341
resizePart(part: Parts, sizeChangeWidth: number, sizeChangeHeight: number): void;
342
343
/**
344
* Register a part to participate in the layout.
345
*/
346
registerPart(part: Part): IDisposable;
347
348
/**
349
* Returns whether the target window is maximized.
350
*/
351
isWindowMaximized(targetWindow: Window): boolean;
352
353
/**
354
* Updates the maximized state of the target window.
355
*/
356
updateWindowMaximizedState(targetWindow: Window, maximized: boolean): void;
357
358
/**
359
* Returns the next visible view part in a given direction in the main window.
360
*/
361
getVisibleNeighborPart(part: Parts, direction: Direction): Parts | undefined;
362
}
363
364
export function shouldShowCustomTitleBar(configurationService: IConfigurationService, window: Window, menuBarToggled?: boolean): boolean {
365
if (!hasCustomTitlebar(configurationService)) {
366
return false;
367
}
368
369
const inFullscreen = isFullscreen(window);
370
const nativeTitleBarEnabled = hasNativeTitlebar(configurationService);
371
372
if (!isWeb) {
373
const showCustomTitleBar = configurationService.getValue<CustomTitleBarVisibility>(TitleBarSetting.CUSTOM_TITLE_BAR_VISIBILITY);
374
if (showCustomTitleBar === CustomTitleBarVisibility.NEVER && nativeTitleBarEnabled || showCustomTitleBar === CustomTitleBarVisibility.WINDOWED && inFullscreen) {
375
return false;
376
}
377
}
378
379
if (!isTitleBarEmpty(configurationService)) {
380
return true;
381
}
382
383
// Hide custom title bar when native title bar enabled and custom title bar is empty
384
if (nativeTitleBarEnabled && hasNativeMenu(configurationService)) {
385
return false;
386
}
387
388
// macOS desktop does not need a title bar when full screen
389
if (isMacintosh && isNative) {
390
return !inFullscreen;
391
}
392
393
// non-fullscreen native must show the title bar
394
if (isNative && !inFullscreen) {
395
return true;
396
}
397
398
// if WCO is visible, we have to show the title bar
399
if (isWCOEnabled() && !inFullscreen) {
400
return true;
401
}
402
403
// remaining behavior is based on menubar visibility
404
const menuBarVisibility = !isAuxiliaryWindow(window) ? getMenuBarVisibility(configurationService) : 'hidden';
405
switch (menuBarVisibility) {
406
case 'classic':
407
return !inFullscreen || !!menuBarToggled;
408
case 'compact':
409
case 'hidden':
410
return false;
411
case 'toggle':
412
return !!menuBarToggled;
413
case 'visible':
414
return true;
415
default:
416
return isWeb ? false : !inFullscreen || !!menuBarToggled;
417
}
418
}
419
420
function isTitleBarEmpty(configurationService: IConfigurationService): boolean {
421
422
// with the command center enabled, we should always show
423
if (configurationService.getValue<boolean>(LayoutSettings.COMMAND_CENTER)) {
424
return false;
425
}
426
427
// with the activity bar on top, we should always show
428
const activityBarPosition = configurationService.getValue<ActivityBarPosition>(LayoutSettings.ACTIVITY_BAR_LOCATION);
429
if (activityBarPosition === ActivityBarPosition.TOP || activityBarPosition === ActivityBarPosition.BOTTOM) {
430
return false;
431
}
432
433
// with the editor actions on top, we should always show
434
const editorActionsLocation = configurationService.getValue<EditorActionsLocation>(LayoutSettings.EDITOR_ACTIONS_LOCATION);
435
const editorTabsMode = configurationService.getValue<EditorTabsMode>(LayoutSettings.EDITOR_TABS_MODE);
436
if (editorActionsLocation === EditorActionsLocation.TITLEBAR || editorActionsLocation === EditorActionsLocation.DEFAULT && editorTabsMode === EditorTabsMode.NONE) {
437
return false;
438
}
439
440
// with the layout actions on top, we should always show
441
if (configurationService.getValue<boolean>(LayoutSettings.LAYOUT_ACTIONS)) {
442
return false;
443
}
444
445
return true;
446
}
447
448