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