workbench.ts 83.6 KB
Newer Older
E
Erich Gamma 已提交
1 2 3 4 5
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

6
import 'vs/workbench/browser/style';
7

B
Benjamin Pasero 已提交
8
import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle';
J
Joao Moreno 已提交
9
import { Event, Emitter } from 'vs/base/common/event';
10
import { EventType, addDisposableListener, addClasses, scheduleAtNextAnimationFrame, addClass, removeClass, trackFocus, isAncestor, getClientArea, position, size } from 'vs/base/browser/dom';
B
Benjamin Pasero 已提交
11
import { RunOnceScheduler, runWhenIdle } from 'vs/base/common/async';
12 13 14
import { getZoomLevel, onDidChangeFullscreen, isFullscreen, getZoomFactor } from 'vs/base/browser/browser';
import { mark } from 'vs/base/common/performance';
import { onUnexpectedError, setUnexpectedErrorHandler } from 'vs/base/common/errors';
15
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
16
import { Registry } from 'vs/platform/registry/common/platform';
17
import { isWindows, isLinux, isMacintosh, language } from 'vs/base/common/platform';
18
import { IResourceInput } from 'vs/platform/editor/common/editor';
J
Johannes Rieken 已提交
19
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
20
import { IEditorInputFactoryRegistry, Extensions as EditorExtensions, TextCompareEditorVisibleContext, TEXT_DIFF_EDITOR_ID, EditorsVisibleContext, InEditorZenModeContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, IUntitledResourceInput, IResourceDiffInput, SplitEditorsVertically, TextCompareEditorActiveContext, ActiveEditorContext } from 'vs/workbench/common/editor';
J
Johannes Rieken 已提交
21 22 23 24
import { ActivitybarPart } from 'vs/workbench/browser/parts/activitybar/activitybarPart';
import { SidebarPart } from 'vs/workbench/browser/parts/sidebar/sidebarPart';
import { PanelPart } from 'vs/workbench/browser/parts/panel/panelPart';
import { StatusbarPart } from 'vs/workbench/browser/parts/statusbar/statusbarPart';
B
Benjamin Pasero 已提交
25
import { TitlebarPart } from 'vs/workbench/browser/parts/titlebar/titlebarPart';
26
import { EditorPart } from 'vs/workbench/browser/parts/editor/editorPart';
27
import { IActionBarRegistry, Extensions as ActionBarExtensions } from 'vs/workbench/browser/actions';
J
Johannes Rieken 已提交
28 29
import { PanelRegistry, Extensions as PanelExtensions } from 'vs/workbench/browser/panel';
import { QuickOpenController } from 'vs/workbench/browser/parts/quickopen/quickOpenController';
C
Christof Marti 已提交
30 31
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { QuickInputService } from 'vs/workbench/browser/parts/quickinput/quickInput';
J
Johannes Rieken 已提交
32
import { getServices } from 'vs/platform/instantiation/common/extensions';
33
import { Position, Parts, IPartService, IDimension, PositionToString, ILayoutOptions } from 'vs/workbench/services/part/common/partService';
34
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
35
import { IStorageService, StorageScope, IWillSaveStateEvent, WillSaveStateReason } from 'vs/platform/storage/common/storage';
S
SteVen Batten 已提交
36
import { ContextMenuService as HTMLContextMenuService } from 'vs/platform/contextview/browser/contextMenuService';
J
Johannes Rieken 已提交
37
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
38
import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing';
J
Johannes Rieken 已提交
39
import { ContextKeyService } from 'vs/platform/contextkey/browser/contextKeyService';
40 41
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IKeybindingEditingService, KeybindingsEditingService } from 'vs/workbench/services/keybinding/common/keybindingEditing';
42
import { RawContextKey, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
I
isidor 已提交
43
import { IActivityService } from 'vs/workbench/services/activity/common/activity';
B
Benjamin Pasero 已提交
44
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
J
Johannes Rieken 已提交
45 46 47
import { IFileService } from 'vs/platform/files/common/files';
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
B
Benjamin Pasero 已提交
48
import { ITitleService } from 'vs/workbench/services/title/common/titleService';
J
Johannes Rieken 已提交
49
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
50
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
J
Johannes Rieken 已提交
51 52 53
import { IHistoryService } from 'vs/workbench/services/history/common/history';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
54
import { TextFileService } from 'vs/workbench/services/textfile/common/textFileService';
J
Johannes Rieken 已提交
55
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
56
import { IProgressService2 } from 'vs/platform/progress/common/progress';
57
import { ProgressService2 } from 'vs/workbench/services/progress/browser/progressService2';
58
import { TextModelResolverService } from 'vs/workbench/services/textmodelResolver/common/textModelResolverService';
59
import { ITextModelService } from 'vs/editor/common/services/resolverService';
J
Johannes Rieken 已提交
60
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
B
Benjamin Pasero 已提交
61
import { LifecyclePhase, StartupKind, ILifecycleService, WillShutdownEvent } from 'vs/platform/lifecycle/common/lifecycle';
62
import { IWindowService, IWindowConfiguration, IPath, MenuBarVisibility, getTitleBarStyle, IWindowsService } from 'vs/platform/windows/common/windows';
J
Johannes Rieken 已提交
63
import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar';
64
import { IMenuService } from 'vs/platform/actions/common/actions';
65
import { MenuService } from 'vs/platform/actions/common/menuService';
S
SteVen Batten 已提交
66
import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';
J
Johannes Rieken 已提交
67
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
68
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
69
import { FileDecorationsService } from 'vs/workbench/services/decorations/browser/decorationsService';
J
Johannes Rieken 已提交
70
import { IDecorationsService } from 'vs/workbench/services/decorations/browser/decorations';
I
isidor 已提交
71
import { ActivityService } from 'vs/workbench/services/activity/browser/activityService';
72
import { URI } from 'vs/base/common/uri';
J
Joao Moreno 已提交
73
import { IListService, ListService } from 'vs/platform/list/browser/listService';
74
import { InputFocusedContext, IsMacContext, IsLinuxContext, IsWindowsContext, SupportsOpenFileFolderContext, SupportsWorkspacesContext, IsDevelopmentContext, HasMacNativeTabsContext } from 'vs/platform/contextkey/common/contextkeys';
75
import { IViewsService } from 'vs/workbench/common/views';
S
Sandeep Somavarapu 已提交
76
import { ViewsService } from 'vs/workbench/browser/parts/views/views';
77 78
import { INotificationService } from 'vs/platform/notification/common/notification';
import { NotificationService } from 'vs/workbench/services/notification/common/notificationService';
79 80
import { NotificationsCenter } from 'vs/workbench/browser/parts/notifications/notificationsCenter';
import { NotificationsAlerts } from 'vs/workbench/browser/parts/notifications/notificationsAlerts';
81
import { NotificationsStatus } from 'vs/workbench/browser/parts/notifications/notificationsStatus';
82
import { registerNotificationCommands } from 'vs/workbench/browser/parts/notifications/notificationsCommands';
83
import { NotificationsToasts } from 'vs/workbench/browser/parts/notifications/notificationsToasts';
S
Sandeep Somavarapu 已提交
84 85
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
import { PreferencesService } from 'vs/workbench/services/preferences/browser/preferencesService';
86
import { IEditorService, IResourceEditor } from 'vs/workbench/services/editor/common/editorService';
87
import { IEditorGroupsService, GroupDirection, preferredSideBySideGroupDirection } from 'vs/workbench/services/editor/common/editorGroupsService';
88
import { EditorService } from 'vs/workbench/services/editor/browser/editorService';
S
SteVen Batten 已提交
89
import { ContextViewService } from 'vs/platform/contextview/browser/contextViewService';
A
Alex Dima 已提交
90
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
91
import { IFileDialogService, IDialogService } from 'vs/platform/dialogs/common/dialogs';
S
SteVen Batten 已提交
92
import { Sizing, Direction, Grid, View } from 'vs/base/browser/ui/grid/grid';
I
isidor 已提交
93
import { IEditor } from 'vs/editor/common/editorCommon';
94
import { WorkbenchLayout } from 'vs/workbench/browser/layout';
95 96 97 98 99 100
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { setARIAContainer } from 'vs/base/browser/ui/aria/aria';
import { restoreFontInfo, readFontInfo, saveFontInfo } from 'vs/editor/browser/config/configuration';
import { BareFontInfo } from 'vs/editor/common/config/fontInfo';
import { ILogService } from 'vs/platform/log/common/log';
import { toErrorMessage } from 'vs/base/common/errorMessage';
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
import { ILabelService } from 'vs/platform/label/common/label';
import { LabelService } from 'vs/workbench/services/label/common/labelService';
import { IHashService } from 'vs/workbench/services/hash/common/hashService';
import { ITelemetryServiceConfig, TelemetryService } from 'vs/platform/telemetry/common/telemetryService';
import { combinedAppender, LogAppender, NullTelemetryService, configurationTelemetry } from 'vs/platform/telemetry/common/telemetryUtils';
import ErrorTelemetry from 'vs/platform/telemetry/browser/errorTelemetry';
import { IDownloadService } from 'vs/platform/download/common/download';
import { IExtensionGalleryService, IExtensionManagementServerService, IExtensionManagementService, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { ExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionEnablementService';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { CommandService } from 'vs/workbench/services/commands/common/commandService';
import { IMarkerService } from 'vs/platform/markers/common/markers';
import { MarkerService } from 'vs/platform/markers/common/markerService';
import { IModeService } from 'vs/editor/common/services/modeService';
import { WorkbenchModeServiceImpl } from 'vs/workbench/services/mode/common/workbenchModeService';
import { ITextResourceConfigurationService, ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration';
import { TextResourceConfigurationService } from 'vs/editor/common/services/resourceConfigurationImpl';
import { IModelService } from 'vs/editor/common/services/modelService';
import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl';
import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDecorationService';
import { MarkerDecorationsService } from 'vs/editor/common/services/markerDecorationsServiceImpl';
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';
import { EditorWorkerServiceImpl } from 'vs/editor/common/services/editorWorkerServiceImpl';
import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
import { ISearchService, ISearchHistoryService } from 'vs/workbench/services/search/common/search';
import { SearchHistoryService } from 'vs/workbench/services/search/common/searchHistoryService';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { CodeEditorService } from 'vs/workbench/services/editor/browser/codeEditorService';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { OpenerService } from 'vs/editor/browser/services/openerService';
import { IIntegrityService } from 'vs/workbench/services/integrity/common/integrity';
import { ILocalizationsService } from 'vs/platform/localizations/common/localizations';
135
import { HistoryService } from 'vs/workbench/services/history/browser/history';
136
import { ConfigurationResolverService } from 'vs/workbench/services/configurationResolver/browser/configurationResolverService';
137
import { WorkbenchThemeService } from 'vs/workbench/services/themes/browser/workbenchThemeService';
138

139
// todo@move
140 141
import product from 'vs/platform/node/product';
import pkg from 'vs/platform/node/package';
142 143

// import@node
144 145 146 147
import { BackupFileService, InMemoryBackupFileService } from 'vs/workbench/services/backup/node/backupFileService';
import { WorkspaceService, DefaultConfigurationExportHelper } from 'vs/workbench/services/configuration/node/configurationService';
import { JSONEditingService } from 'vs/workbench/services/configuration/node/jsonEditingService';
import { WorkspaceEditingService } from 'vs/workbench/services/workspace/node/workspaceEditingService';
148
import { getDelayedChannel } from 'vs/base/parts/ipc/node/ipc';
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
import { HashService } from 'vs/workbench/services/hash/node/hashService';
import { connect as connectNet } from 'vs/base/parts/ipc/node/ipc.net';
import { DialogChannel } from 'vs/platform/dialogs/node/dialogIpc';
import { TelemetryAppenderClient } from 'vs/platform/telemetry/node/telemetryIpc';
import { resolveWorkbenchCommonProperties } from 'vs/platform/telemetry/node/workbenchCommonProperties';
import { IRequestService } from 'vs/platform/request/node/request';
import { RequestService } from 'vs/platform/request/node/requestService';
import { DownloadService } from 'vs/platform/download/node/downloadService';
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService';
import { IRemoteAgentService } from 'vs/workbench/services/remote/node/remoteAgentService';
import { DownloadServiceChannel } from 'vs/platform/download/node/downloadIpc';
import { LogLevelSetterChannel } from 'vs/platform/log/node/logIpc';
import { ExtensionManagementChannelClient } from 'vs/platform/extensionManagement/node/extensionManagementIpc';
import { ExtensionManagementServerService } from 'vs/workbench/services/extensions/node/extensionManagementServerService';
import { MultiExtensionManagementService } from 'vs/workbench/services/extensionManagement/node/multiExtensionManagement';
import { SearchService } from 'vs/workbench/services/search/node/searchService';
import { IntegrityServiceImpl } from 'vs/workbench/services/integrity/node/integrityServiceImpl';
import { LocalizationsChannelClient } from 'vs/platform/localizations/node/localizationsIpc';

// import@electron-browser
import { ContextMenuService as NativeContextMenuService } from 'vs/workbench/services/contextview/electron-browser/contextmenuService';
import { WorkbenchKeybindingService } from 'vs/workbench/services/keybinding/electron-browser/keybindingService';
import { RemoteFileService } from 'vs/workbench/services/files/electron-browser/remoteFileService';
import { ClipboardService } from 'vs/platform/clipboard/electron-browser/clipboardService';
import { LifecycleService } from 'vs/platform/lifecycle/electron-browser/lifecycleService';
import { IExtensionUrlHandler, ExtensionUrlHandler } from 'vs/workbench/services/extensions/electron-browser/inactiveExtensionUrlHandler';
175
import { DialogService, FileDialogService } from 'vs/workbench/services/dialogs/electron-browser/dialogService';
176 177 178 179 180 181 182 183
import { IBroadcastService, BroadcastService } from 'vs/workbench/services/broadcast/electron-browser/broadcastService';
import { WindowService } from 'vs/platform/windows/electron-browser/windowService';
import { RemoteAuthorityResolverService } from 'vs/platform/remote/electron-browser/remoteAuthorityResolverService';
import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl';
import { ExtensionService } from 'vs/workbench/services/extensions/electron-browser/extensionService';
import { TextResourcePropertiesService } from 'vs/workbench/services/textfile/electron-browser/textResourcePropertiesService';
import { ITextMateService } from 'vs/workbench/services/textMate/electron-browser/textMateService';
import { TextMateService } from 'vs/workbench/services/textMate/electron-browser/TMSyntax';
184

I
isidor 已提交
185 186
interface IZenModeSettings {
	fullScreen: boolean;
187
	centerLayout: boolean;
I
isidor 已提交
188
	hideTabs: boolean;
189
	hideActivityBar: boolean;
I
isidor 已提交
190
	hideStatusBar: boolean;
I
isidor 已提交
191
	hideLineNumbers: boolean;
I
isidor 已提交
192
	restore: boolean;
I
isidor 已提交
193 194
}

195
interface IWorkbenchStartedInfo {
196 197
	customKeybindingsCount: number;
	pinnedViewlets: string[];
198
	restoredViewlet: string;
199
	restoredEditorsCount: number;
200
}
201 202
type FontAliasingOption = 'default' | 'antialiased' | 'none' | 'auto';

B
Benjamin Pasero 已提交
203 204
const fontAliasingValues: FontAliasingOption[] = ['antialiased', 'none', 'auto'];

205 206
const Identifiers = {
	WORKBENCH_CONTAINER: 'workbench.main.container',
B
Benjamin Pasero 已提交
207
	TITLEBAR_PART: 'workbench.parts.titlebar',
208 209 210 211
	ACTIVITYBAR_PART: 'workbench.parts.activitybar',
	SIDEBAR_PART: 'workbench.parts.sidebar',
	PANEL_PART: 'workbench.parts.panel',
	EDITOR_PART: 'workbench.parts.editor',
S
SteVen Batten 已提交
212
	STATUSBAR_PART: 'workbench.parts.statusbar'
213 214
};

J
Joao Moreno 已提交
215 216 217 218 219 220 221 222
function getWorkbenchStateString(state: WorkbenchState): string {
	switch (state) {
		case WorkbenchState.EMPTY: return 'empty';
		case WorkbenchState.FOLDER: return 'folder';
		case WorkbenchState.WORKSPACE: return 'workspace';
	}
}

223 224 225 226 227 228 229 230 231
interface IZenMode {
	active: boolean;
	transitionedToFullScreen: boolean;
	transitionedToCenteredEditorLayout: boolean;
	transitionDisposeables: IDisposable[];
	wasSideBarVisible: boolean;
	wasPanelVisible: boolean;
}

232 233 234 235 236 237
interface IWorkbenchUIState {
	lastPanelHeight?: number;
	lastPanelWidth?: number;
	lastSidebarDimension?: number;
}

238
export class Workbench extends Disposable implements IPartService {
E
Erich Gamma 已提交
239

240
	private static readonly sidebarHiddenStorageKey = 'workbench.sidebar.hidden';
241
	private static readonly menubarVisibilityConfigurationKey = 'window.menuBarVisibility';
242 243
	private static readonly panelHiddenStorageKey = 'workbench.panel.hidden';
	private static readonly zenModeActiveStorageKey = 'workbench.zenmode.active';
244
	private static readonly centeredEditorLayoutActiveStorageKey = 'workbench.centerededitorlayout.active';
245
	private static readonly panelPositionStorageKey = 'workbench.panel.location';
246
	private static readonly defaultPanelPositionStorageKey = 'workbench.panel.defaultLocation';
247 248 249 250 251
	private static readonly sidebarPositionConfigurationKey = 'workbench.sideBar.location';
	private static readonly statusbarVisibleConfigurationKey = 'workbench.statusBar.visible';
	private static readonly activityBarVisibleConfigurationKey = 'workbench.activityBar.visible';
	private static readonly closeWhenEmptyConfigurationKey = 'window.closeWhenEmpty';
	private static readonly fontAliasingConfigurationKey = 'workbench.fontAliasing';
252

B
Benjamin Pasero 已提交
253 254
	_serviceBrand: any;

B
Benjamin Pasero 已提交
255 256 257 258 259 260
	private readonly _onShutdown = this._register(new Emitter<void>());
	get onShutdown(): Event<void> { return this._onShutdown.event; }

	private readonly _onWillShutdown = this._register(new Emitter<WillShutdownEvent>());
	get onWillShutdown(): Event<WillShutdownEvent> { return this._onWillShutdown.event; }

261 262 263
	private previousErrorValue: string;
	private previousErrorTime: number = 0;

B
Benjamin Pasero 已提交
264
	private workbench: HTMLElement;
E
Erich Gamma 已提交
265
	private workbenchStarted: boolean;
B
Benjamin Pasero 已提交
266
	private workbenchRestored: boolean;
E
Erich Gamma 已提交
267
	private workbenchShutdown: boolean;
268

269 270
	private editorService: EditorService;
	private editorGroupService: IEditorGroupsService;
J
Joao Moreno 已提交
271
	private contextViewService: ContextViewService;
272
	private contextKeyService: IContextKeyService;
273
	private keybindingService: IKeybindingService;
274
	private backupFileService: IBackupFileService;
275 276 277 278 279
	private notificationService: NotificationService;
	private themeService: WorkbenchThemeService;
	private telemetryService: ITelemetryService;
	private windowService: IWindowService;
	private lifecycleService: LifecycleService;
280
	private fileService: IFileService;
281 282
	private quickInput: QuickInputService;

S
SteVen Batten 已提交
283
	private workbenchGrid: Grid<View> | WorkbenchLayout;
284

B
Benjamin Pasero 已提交
285
	private titlebarPart: TitlebarPart;
E
Erich Gamma 已提交
286 287
	private activitybarPart: ActivitybarPart;
	private sidebarPart: SidebarPart;
I
isidor 已提交
288
	private panelPart: PanelPart;
E
Erich Gamma 已提交
289 290
	private editorPart: EditorPart;
	private statusbarPart: StatusbarPart;
S
SteVen Batten 已提交
291 292 293 294 295 296 297 298

	private titlebarPartView: View;
	private activitybarPartView: View;
	private sidebarPartView: View;
	private panelPartView: View;
	private editorPartView: View;
	private statusbarPartView: View;

E
Erich Gamma 已提交
299
	private quickOpen: QuickOpenController;
300
	private notificationsCenter: NotificationsCenter;
301
	private notificationsToasts: NotificationsToasts;
302

S
SteVen Batten 已提交
303
	private editorHidden: boolean;
E
Erich Gamma 已提交
304
	private sideBarHidden: boolean;
305
	private statusBarHidden: boolean;
S
Sanders Lauture 已提交
306
	private activityBarHidden: boolean;
307
	private menubarToggled: boolean;
E
Erich Gamma 已提交
308
	private sideBarPosition: Position;
I
isidor 已提交
309
	private panelPosition: Position;
I
isidor 已提交
310
	private panelHidden: boolean;
S
SteVen Batten 已提交
311
	private menubarVisibility: MenuBarVisibility;
312 313
	private zenMode: IZenMode;
	private fontAliasing: FontAliasingOption;
314
	private hasInitialFilesToOpen: boolean;
315
	private shouldCenterLayout = false;
316 317 318 319 320
	private uiState: IWorkbenchUIState = {
		lastPanelHeight: 350,
		lastPanelWidth: 350,
		lastSidebarDimension: 300,
	};
321

I
isidor 已提交
322
	private inZenMode: IContextKey<boolean>;
323
	private sideBarVisibleContext: IContextKey<boolean>;
324

B
Benjamin Pasero 已提交
325
	private closeEmptyWindowScheduler: RunOnceScheduler = this._register(new RunOnceScheduler(() => this.onAllEditorsClosed(), 50));
E
Erich Gamma 已提交
326

327
	constructor(
328
		private container: HTMLElement,
J
Joao Moreno 已提交
329
		private configuration: IWindowConfiguration,
B
Benjamin Pasero 已提交
330
		private serviceCollection: ServiceCollection,
331 332
		@IInstantiationService private readonly instantiationService: IInstantiationService,
		@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
B
Benjamin Pasero 已提交
333
		@IStorageService private readonly storageService: IStorageService,
334 335
		@IConfigurationService private readonly configurationService: WorkspaceService,
		@IEnvironmentService private readonly environmentService: IEnvironmentService,
336 337
		@ILogService private readonly logService: ILogService,
		@IWindowsService private readonly windowsService: IWindowsService
338
	) {
339
		super();
E
Erich Gamma 已提交
340

341
		this.hasInitialFilesToOpen = !!(
B
Benjamin Pasero 已提交
342 343
			(configuration.filesToCreate && configuration.filesToCreate.length > 0) ||
			(configuration.filesToOpen && configuration.filesToOpen.length > 0) ||
344
			(configuration.filesToDiff && configuration.filesToDiff.length > 0));
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387

		this.registerErrorHandler();
	}

	private registerErrorHandler(): void {

		// Listen on unhandled rejection events
		window.addEventListener('unhandledrejection', (event: PromiseRejectionEvent) => {

			// See https://developer.mozilla.org/en-US/docs/Web/API/PromiseRejectionEvent
			onUnexpectedError(event.reason);

			// Prevent the printing of this event to the console
			event.preventDefault();
		});

		// Install handler for unexpected errors
		setUnexpectedErrorHandler(error => this.handleUnexpectedError(error));
	}

	private handleUnexpectedError(error: any): void {
		const errorMsg = toErrorMessage(error, true);
		if (!errorMsg) {
			return;
		}

		const now = Date.now();
		if (errorMsg === this.previousErrorValue && now - this.previousErrorTime <= 1000) {
			return; // Return if error message identical to previous and shorter than 1 second
		}

		this.previousErrorTime = now;
		this.previousErrorValue = errorMsg;

		// Log it
		this.logService.error(errorMsg);

		// Show to user if friendly message provided
		if (error && error.friendlyMessage && this.notificationService) {
			this.notificationService.error(error.friendlyMessage);
		}
	}

388
	startup(): void {
389
		try {
390
			this.doStartup().then(undefined, error => this.logService.error(toErrorMessage(error, true)));
391 392 393 394 395
		} catch (error) {
			this.logService.error(toErrorMessage(error, true));

			throw error; // rethrow because this is a critical issue we cannot handle properly here
		}
396 397
	}

398
	private doStartup(): Promise<void> {
399
		this.workbenchStarted = true;
E
Erich Gamma 已提交
400

B
Benjamin Pasero 已提交
401 402 403
		// Logging
		this.logService.trace('workbench configuration', JSON.stringify(this.configuration));

404 405 406 407 408 409 410 411 412 413
		// ARIA
		setARIAContainer(document.body);

		// Warm up font cache information before building up too many dom elements
		restoreFontInfo(this.storageService);
		readFontInfo(BareFontInfo.createFromRawSettings(this.configurationService.getValue('editor'), getZoomLevel()));
		this._register(this.storageService.onWillSaveState(() => {
			saveFontInfo(this.storageService); // Keep font info for next startup around
		}));

B
Benjamin Pasero 已提交
414
		// Create Workbench Container
415
		this.createWorkbench();
E
Erich Gamma 已提交
416

417
		// Services
B
Benjamin Pasero 已提交
418
		this.initServices(this.serviceCollection);
E
Erich Gamma 已提交
419

420 421
		// Context Keys
		this.handleContextKeys();
J
Joao Moreno 已提交
422

423 424
		// Register Listeners
		this.registerListeners();
E
Erich Gamma 已提交
425

426 427
		// Settings
		this.initSettings();
E
Erich Gamma 已提交
428

429 430
		// Create Workbench and Parts
		this.renderWorkbench();
431

432 433
		// Workbench Layout
		this.createWorkbenchLayout();
B
polish  
Benjamin Pasero 已提交
434

435 436 437 438 439 440 441 442 443 444 445 446
		// Layout
		this.layout();

		// Handle case where workbench is not starting up properly
		const timeoutHandle = setTimeout(() => {
			this.logService.warn('Workbench did not finish loading in 10 seconds, that might be a problem that should be reported.');
		}, 10000);

		this.lifecycleService.when(LifecyclePhase.Restored).then(() => {
			clearTimeout(timeoutHandle);
		});

447
		// Restore Parts
B
Benjamin Pasero 已提交
448 449
		return this.restoreParts();
	}
450

B
Benjamin Pasero 已提交
451
	private createWorkbench(): void {
B
Benjamin Pasero 已提交
452 453
		this.workbench = document.createElement('div');
		this.workbench.id = Identifiers.WORKBENCH_CONTAINER;
454

455
		addClasses(this.workbench, 'monaco-workbench', isWindows ? 'windows' : isLinux ? 'linux' : 'mac');
456
	}
E
Erich Gamma 已提交
457

B
Benjamin Pasero 已提交
458
	private initServices(serviceCollection: ServiceCollection): void {
459

460
		// Parts
461
		serviceCollection.set(IPartService, this);
E
Erich Gamma 已提交
462

463 464 465
		// Labels
		serviceCollection.set(ILabelService, new SyncDescriptor(LabelService, undefined, true));

466
		// Clipboard
J
Johannes Rieken 已提交
467
		serviceCollection.set(IClipboardService, new SyncDescriptor(ClipboardService));
468

469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515
		// Broadcast
		serviceCollection.set(IBroadcastService, new SyncDescriptor(BroadcastService, [this.configuration.windowId]));

		// Notifications
		this.notificationService = new NotificationService();
		serviceCollection.set(INotificationService, this.notificationService);

		// Window
		this.windowService = this.instantiationService.createInstance(WindowService, this.configuration);
		serviceCollection.set(IWindowService, this.windowService);

		// Shared Process
		const sharedProcess = this.windowsService.whenSharedProcessReady()
			.then(() => connectNet(this.environmentService.sharedIPCHandle, `window:${this.configuration.windowId}`))
			.then(client => {
				client.registerChannel('dialog', this.instantiationService.createInstance(DialogChannel));

				return client;
			});

		// Telemetry
		if (!this.environmentService.isExtensionDevelopment && !this.environmentService.args['disable-telemetry'] && !!product.enableTelemetry) {
			const channel = getDelayedChannel(sharedProcess.then(c => c.getChannel('telemetryAppender')));
			const config: ITelemetryServiceConfig = {
				appender: combinedAppender(new TelemetryAppenderClient(channel), new LogAppender(this.logService)),
				commonProperties: resolveWorkbenchCommonProperties(this.storageService, product.commit, pkg.version, this.configuration.machineId, this.environmentService.installSourcePath),
				piiPaths: [this.environmentService.appRoot, this.environmentService.extensionsPath]
			};

			this.telemetryService = this._register(this.instantiationService.createInstance(TelemetryService, config));
			this._register(new ErrorTelemetry(this.telemetryService));
		} else {
			this.telemetryService = NullTelemetryService;
		}

		serviceCollection.set(ITelemetryService, this.telemetryService);
		this._register(configurationTelemetry(this.telemetryService, this.configurationService));

		// Dialogs
		serviceCollection.set(IDialogService, this.instantiationService.createInstance(DialogService));

		// Lifecycle
		this.lifecycleService = this.instantiationService.createInstance(LifecycleService);
		this.lifecycleService.phase = LifecyclePhase.Ready; // Set lifecycle phase to `Ready`

		serviceCollection.set(ILifecycleService, this.lifecycleService);

B
Benjamin Pasero 已提交
516 517 518 519 520
		this._register(this.lifecycleService.onWillShutdown(event => this._onWillShutdown.fire(event)));
		this._register(this.lifecycleService.onShutdown(() => {
			this._onShutdown.fire();
			this.dispose();
		}));
521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612

		// Request Service
		serviceCollection.set(IRequestService, new SyncDescriptor(RequestService, undefined, true));

		// Download Service
		serviceCollection.set(IDownloadService, new SyncDescriptor(DownloadService, undefined, true));

		// Extension Gallery
		serviceCollection.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService, undefined, true));

		// Remote Resolver
		const remoteAuthorityResolverService = new RemoteAuthorityResolverService();
		serviceCollection.set(IRemoteAuthorityResolverService, remoteAuthorityResolverService);

		// Remote Agent
		const remoteAgentService = new RemoteAgentService(this.configuration, this.notificationService, this.environmentService, remoteAuthorityResolverService);
		serviceCollection.set(IRemoteAgentService, remoteAgentService);

		const remoteAgentConnection = remoteAgentService.getConnection();
		if (remoteAgentConnection) {
			remoteAgentConnection.registerChannel('dialog', this.instantiationService.createInstance(DialogChannel));
			remoteAgentConnection.registerChannel('download', new DownloadServiceChannel());
			remoteAgentConnection.registerChannel('loglevel', new LogLevelSetterChannel(this.logService));
		}

		// Extensions Management
		const extensionManagementChannel = getDelayedChannel(sharedProcess.then(c => c.getChannel('extensions')));
		const extensionManagementChannelClient = new ExtensionManagementChannelClient(extensionManagementChannel);
		serviceCollection.set(IExtensionManagementServerService, new SyncDescriptor(ExtensionManagementServerService, [extensionManagementChannelClient]));
		serviceCollection.set(IExtensionManagementService, new SyncDescriptor(MultiExtensionManagementService));

		// Extension Enablement
		const extensionEnablementService = this._register(this.instantiationService.createInstance(ExtensionEnablementService));
		serviceCollection.set(IExtensionEnablementService, extensionEnablementService);

		// Extensions
		serviceCollection.set(IExtensionService, this.instantiationService.createInstance(ExtensionService));

		// Theming
		this.themeService = this.instantiationService.createInstance(WorkbenchThemeService, document.body);
		serviceCollection.set(IWorkbenchThemeService, this.themeService);

		// Commands
		serviceCollection.set(ICommandService, new SyncDescriptor(CommandService, undefined, true));

		// Markers
		serviceCollection.set(IMarkerService, new SyncDescriptor(MarkerService, undefined, true));

		// Editor Mode
		serviceCollection.set(IModeService, new SyncDescriptor(WorkbenchModeServiceImpl));

		// Text Resource Config
		serviceCollection.set(ITextResourceConfigurationService, new SyncDescriptor(TextResourceConfigurationService));

		// Text Resource Properties
		serviceCollection.set(ITextResourcePropertiesService, new SyncDescriptor(TextResourcePropertiesService));

		// Editor Models
		serviceCollection.set(IModelService, new SyncDescriptor(ModelServiceImpl, undefined, true));

		// Marker Decorations
		serviceCollection.set(IMarkerDecorationsService, new SyncDescriptor(MarkerDecorationsService));

		// Editor Worker
		serviceCollection.set(IEditorWorkerService, new SyncDescriptor(EditorWorkerServiceImpl));

		// Untitled Editors
		serviceCollection.set(IUntitledEditorService, new SyncDescriptor(UntitledEditorService, undefined, true));

		// Text Mate
		serviceCollection.set(ITextMateService, new SyncDescriptor(TextMateService));

		// Search
		serviceCollection.set(ISearchService, new SyncDescriptor(SearchService));
		serviceCollection.set(ISearchHistoryService, new SyncDescriptor(SearchHistoryService));

		// Code Editor
		serviceCollection.set(ICodeEditorService, new SyncDescriptor(CodeEditorService));

		// Opener
		serviceCollection.set(IOpenerService, new SyncDescriptor(OpenerService, undefined, true));

		// Integrity
		serviceCollection.set(IIntegrityService, new SyncDescriptor(IntegrityServiceImpl));

		// Localization
		const localizationsChannel = getDelayedChannel(sharedProcess.then(c => c.getChannel('localizations')));
		serviceCollection.set(ILocalizationsService, new SyncDescriptor(LocalizationsChannelClient, [localizationsChannel]));

		// Hash
		serviceCollection.set(IHashService, new SyncDescriptor(HashService, undefined, true));

613 614 615 616
		// Status bar
		this.statusbarPart = this.instantiationService.createInstance(StatusbarPart, Identifiers.STATUSBAR_PART);
		serviceCollection.set(IStatusbarService, this.statusbarPart);

617 618 619
		// Progress 2
		serviceCollection.set(IProgressService2, new SyncDescriptor(ProgressService2));

620
		// Keybindings
A
Alex Dima 已提交
621
		this.contextKeyService = this.instantiationService.createInstance(ContextKeyService);
622
		serviceCollection.set(IContextKeyService, this.contextKeyService);
623

B
Benjamin Pasero 已提交
624
		this.keybindingService = this.instantiationService.createInstance(WorkbenchKeybindingService, window);
625
		serviceCollection.set(IKeybindingService, this.keybindingService);
A
Alex Dima 已提交
626

627 628 629
		// List
		serviceCollection.set(IListService, this.instantiationService.createInstance(ListService));

J
Joao Moreno 已提交
630
		// Context view service
B
Benjamin Pasero 已提交
631
		this.contextViewService = this.instantiationService.createInstance(ContextViewService, this.workbench);
J
Joao Moreno 已提交
632 633
		serviceCollection.set(IContextViewService, this.contextViewService);

S
SteVen Batten 已提交
634
		// Use themable context menus when custom titlebar is enabled to match custom menubar
B
Benjamin Pasero 已提交
635
		if (!isMacintosh && this.useCustomTitleBarStyle()) {
J
fix npe  
Johannes Rieken 已提交
636
			serviceCollection.set(IContextMenuService, new SyncDescriptor(HTMLContextMenuService, [null]));
S
SteVen Batten 已提交
637 638 639
		} else {
			serviceCollection.set(IContextMenuService, new SyncDescriptor(NativeContextMenuService));
		}
640

641 642
		// Menus/Actions
		serviceCollection.set(IMenuService, new SyncDescriptor(MenuService));
643

P
Pine Wu 已提交
644
		// Sidebar part
645
		this.sidebarPart = this.instantiationService.createInstance(SidebarPart, Identifiers.SIDEBAR_PART);
P
Pine Wu 已提交
646 647

		// Viewlet service
I
isidor 已提交
648
		serviceCollection.set(IViewletService, this.sidebarPart);
E
Erich Gamma 已提交
649

I
isidor 已提交
650
		// Panel service (panel part)
651 652
		this.panelPart = this.instantiationService.createInstance(PanelPart, Identifiers.PANEL_PART);
		serviceCollection.set(IPanelService, this.panelPart);
I
isidor 已提交
653

654 655 656
		// views service
		const viewsService = this.instantiationService.createInstance(ViewsService);
		serviceCollection.set(IViewsService, viewsService);
S
Sandeep Somavarapu 已提交
657

E
Erich Gamma 已提交
658
		// Activity service (activitybar part)
659
		this.activitybarPart = this.instantiationService.createInstance(ActivitybarPart, Identifiers.ACTIVITYBAR_PART);
I
isidor 已提交
660 661
		const activityService = this.instantiationService.createInstance(ActivityService, this.activitybarPart, this.panelPart);
		serviceCollection.set(IActivityService, activityService);
E
Erich Gamma 已提交
662

663 664 665
		// File Service
		this.fileService = this.instantiationService.createInstance(RemoteFileService);
		serviceCollection.set(IFileService, this.fileService);
S
#47154  
Sandeep Somavarapu 已提交
666
		this.configurationService.acquireFileService(this.fileService);
A
Alex Dima 已提交
667
		this.themeService.acquireFileService(this.fileService);
668

669 670
		// Editor and Group services
		const restorePreviousEditorState = !this.hasInitialFilesToOpen;
671
		this.editorPart = this.instantiationService.createInstance(EditorPart, Identifiers.EDITOR_PART, restorePreviousEditorState);
B
Benjamin Pasero 已提交
672
		this.editorGroupService = this.editorPart;
673 674 675
		serviceCollection.set(IEditorGroupsService, this.editorPart);
		this.editorService = this.instantiationService.createInstance(EditorService);
		serviceCollection.set(IEditorService, this.editorService);
E
Erich Gamma 已提交
676

677 678 679
		// Title bar
		this.titlebarPart = this.instantiationService.createInstance(TitlebarPart, Identifiers.TITLEBAR_PART);
		serviceCollection.set(ITitleService, this.titlebarPart);
B
Benjamin Pasero 已提交
680

681
		// History
682
		serviceCollection.set(IHistoryService, new SyncDescriptor(HistoryService));
683

M
Martin Aeschlimann 已提交
684
		// File Dialogs
685
		serviceCollection.set(IFileDialogService, new SyncDescriptor(FileDialogService));
M
Martin Aeschlimann 已提交
686

687
		// Backup File Service
B
Benjamin Pasero 已提交
688 689
		if (this.configuration.backupPath) {
			this.backupFileService = this.instantiationService.createInstance(BackupFileService, this.configuration.backupPath);
B
Benjamin Pasero 已提交
690 691 692
		} else {
			this.backupFileService = new InMemoryBackupFileService();
		}
693
		serviceCollection.set(IBackupFileService, this.backupFileService);
694

695
		// Text File Service
696
		serviceCollection.set(ITextFileService, new SyncDescriptor(TextFileService));
697

698
		// File Decorations
J
Johannes Rieken 已提交
699
		serviceCollection.set(IDecorationsService, new SyncDescriptor(FileDecorationsService));
700

J
Joao Moreno 已提交
701
		// Inactive extension URL handler
J
Joao Moreno 已提交
702
		serviceCollection.set(IExtensionUrlHandler, new SyncDescriptor(ExtensionUrlHandler));
J
Joao Moreno 已提交
703

B
Benjamin Pasero 已提交
704
		// Text Model Resolver Service
705
		serviceCollection.set(ITextModelService, new SyncDescriptor(TextModelResolverService));
B
Benjamin Pasero 已提交
706

707 708 709 710
		// JSON Editing
		const jsonEditingService = this.instantiationService.createInstance(JSONEditingService);
		serviceCollection.set(IJSONEditingService, jsonEditingService);

711 712 713
		// Workspace Editing
		serviceCollection.set(IWorkspaceEditingService, new SyncDescriptor(WorkspaceEditingService));

714 715 716
		// Keybinding Editing
		serviceCollection.set(IKeybindingEditingService, this.instantiationService.createInstance(KeybindingsEditingService));

717
		// Configuration Resolver
718
		serviceCollection.set(IConfigurationResolverService, new SyncDescriptor(ConfigurationResolverService, [process.env]));
719

E
Erich Gamma 已提交
720
		// Quick open service (quick open controller)
721 722
		this.quickOpen = this.instantiationService.createInstance(QuickOpenController);
		serviceCollection.set(IQuickOpenService, this.quickOpen);
723

C
Christof Marti 已提交
724 725 726 727
		// Quick input service
		this.quickInput = this.instantiationService.createInstance(QuickInputService);
		serviceCollection.set(IQuickInputService, this.quickInput);

S
Sandeep Somavarapu 已提交
728 729 730
		// PreferencesService
		serviceCollection.set(IPreferencesService, this.instantiationService.createInstance(PreferencesService));

B
polish  
Benjamin Pasero 已提交
731
		// Contributed services
B
Benjamin Pasero 已提交
732
		const contributedServices = getServices();
E
Erich Gamma 已提交
733
		for (let contributedService of contributedServices) {
734
			serviceCollection.set(contributedService.id, contributedService.descriptor);
E
Erich Gamma 已提交
735 736 737
		}

		// Set the some services to registries that have been created eagerly
738
		Registry.as<IActionBarRegistry>(ActionBarExtensions.Actionbar).setInstantiationService(this.instantiationService);
739
		Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).start(this.instantiationService, this.lifecycleService);
740
		Registry.as<IEditorInputFactoryRegistry>(EditorExtensions.EditorInputFactories).setInstantiationService(this.instantiationService);
741

742
		this.instantiationService.createInstance(DefaultConfigurationExportHelper);
743

B
Benjamin Pasero 已提交
744
		this.configurationService.acquireInstantiationService(this.instantiationService);
E
Erich Gamma 已提交
745 746
	}

747
	//#region event handling
E
Erich Gamma 已提交
748

749
	private registerListeners(): void {
I
isidor 已提交
750

751
		// Storage
752
		this._register(this.storageService.onWillSaveState(e => this.saveState(e)));
753

754
		// Listen to visible editor changes
755
		this._register(this.editorService.onDidVisibleEditorsChange(() => this.onDidVisibleEditorsChange()));
B
Benjamin Pasero 已提交
756

757 758 759
		// Listen to editor group activations when editor is hidden
		this._register(this.editorPart.onDidActivateGroup(() => { if (this.editorHidden) { this.setEditorHidden(false); } }));

760
		// Listen to editor closing (if we run with --wait)
B
Benjamin Pasero 已提交
761
		const filesToWait = this.configuration.filesToWait;
762
		if (filesToWait) {
763
			const resourcesToWaitFor = filesToWait.paths.map(p => p.fileUri);
764
			const waitMarkerFile = URI.file(filesToWait.waitMarkerFilePath);
765
			const listenerDispose = this.editorService.onDidCloseEditor(() => this.onEditorClosed(listenerDispose, resourcesToWaitFor, waitMarkerFile));
I
isidor 已提交
766

767
			this._register(listenerDispose);
768
		}
S
Sanders Lauture 已提交
769

770
		// Configuration changes
771
		this._register(this.configurationService.onDidChangeConfiguration(() => this.onDidUpdateConfiguration()));
I
isidor 已提交
772

773
		// Fullscreen changes
774
		this._register(onDidChangeFullscreen(() => this.onFullscreenChanged()));
B
Benjamin Pasero 已提交
775 776 777 778

		// Group changes
		this._register(this.editorGroupService.onDidAddGroup(() => this.centerEditorLayout(this.shouldCenterLayout)));
		this._register(this.editorGroupService.onDidRemoveGroup(() => this.centerEditorLayout(this.shouldCenterLayout)));
779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804

		// Layout
		this._register(addDisposableListener(window, EventType.RESIZE, e => this.onWindowResize(e, true)));

		// Prevent workbench from scrolling #55456
		this._register(addDisposableListener(this.workbench, EventType.SCROLL, () => {
			this.workbench.scrollTop = 0;
		}));
	}

	private onWindowResize(e: any, retry: boolean): void {
		if (e.target === window) {
			if (window.document && window.document.body && window.document.body.clientWidth === 0) {
				// TODO@Ben this is an electron issue on macOS when simple fullscreen is enabled
				// where for some reason the window clientWidth is reported as 0 when switching
				// between simple fullscreen and normal screen. In that case we schedule the layout
				// call at the next animation frame once, in the hope that the dimensions are
				// proper then.
				if (retry) {
					scheduleAtNextAnimationFrame(() => this.onWindowResize(e, false));
				}
				return;
			}

			this.layout();
		}
805
	}
806

807
	private onFullscreenChanged(): void {
S
SrTobi 已提交
808

809
		// Apply as CSS class
810 811
		if (isFullscreen()) {
			addClass(this.workbench, 'fullscreen');
812
		} else {
813
			removeClass(this.workbench, 'fullscreen');
B
Benjamin Pasero 已提交
814

815 816 817 818
			if (this.zenMode.transitionedToFullScreen && this.zenMode.active) {
				this.toggleZenMode();
			}
		}
E
Erich Gamma 已提交
819

820
		// Changing fullscreen state of the window has an impact on custom title bar visibility, so we need to update
B
Benjamin Pasero 已提交
821
		if (this.useCustomTitleBarStyle()) {
822 823 824
			this._onTitleBarVisibilityChange.fire();
			this.layout(); // handle title bar when fullscreen changes
		}
825 826
	}

827 828 829 830
	private onMenubarToggled(visible: boolean) {
		if (visible !== this.menubarToggled) {
			this.menubarToggled = visible;

831
			if (isFullscreen() && (this.menubarVisibility === 'toggle' || this.menubarVisibility === 'default')) {
832
				this._onTitleBarVisibilityChange.fire();
833 834 835 836 837
				this.layout();
			}
		}
	}

838
	private onEditorClosed(listenerDispose: IDisposable, resourcesToWaitFor: URI[], waitMarkerFile: URI): void {
E
Erich Gamma 已提交
839

840 841 842
		// In wait mode, listen to changes to the editors and wait until the files
		// are closed that the user wants to wait for. When this happens we delete
		// the wait marker file to signal to the outside that editing is done.
843
		if (resourcesToWaitFor.every(resource => !this.editorService.isOpen({ resource }))) {
844
			listenerDispose.dispose();
845
			this.fileService.del(waitMarkerFile);
846
		}
E
Erich Gamma 已提交
847 848
	}

849
	private onDidVisibleEditorsChange(): void {
850
		const visibleEditors = this.editorService.visibleControls;
E
Erich Gamma 已提交
851

852 853 854 855 856 857 858 859 860
		// Close when empty: check if we should close the window based on the setting
		// Overruled by: window has a workspace opened or this window is for extension development
		// or setting is disabled. Also enabled when running with --wait from the command line.
		if (visibleEditors.length === 0 && this.contextService.getWorkbenchState() === WorkbenchState.EMPTY && !this.environmentService.isExtensionDevelopment) {
			const closeWhenEmpty = this.configurationService.getValue<boolean>(Workbench.closeWhenEmptyConfigurationKey);
			if (closeWhenEmpty || this.environmentService.args.wait) {
				this.closeEmptyWindowScheduler.schedule();
			}
		}
861 862 863 864

		if (this.editorHidden) {
			this.setEditorHidden(false);
		}
865 866
	}

867
	private onAllEditorsClosed(): void {
868
		const visibleEditors = this.editorService.visibleControls.length;
869 870
		if (visibleEditors === 0) {
			this.windowService.closeWindow();
E
Erich Gamma 已提交
871 872 873
		}
	}

874 875 876 877 878
	private onDidUpdateConfiguration(skipLayout?: boolean): void {
		const newSidebarPositionValue = this.configurationService.getValue<string>(Workbench.sidebarPositionConfigurationKey);
		const newSidebarPosition = (newSidebarPositionValue === 'right') ? Position.RIGHT : Position.LEFT;
		if (newSidebarPosition !== this.getSideBarPosition()) {
			this.setSideBarPosition(newSidebarPosition);
879
		}
E
Erich Gamma 已提交
880

881
		this.setPanelPositionFromStorageOrConfig();
E
Erich Gamma 已提交
882

883 884 885
		const fontAliasing = this.configurationService.getValue<FontAliasingOption>(Workbench.fontAliasingConfigurationKey);
		if (fontAliasing !== this.fontAliasing) {
			this.setFontAliasing(fontAliasing);
886 887
		}

888 889 890 891 892
		if (!this.zenMode.active) {
			const newStatusbarHiddenValue = !this.configurationService.getValue<boolean>(Workbench.statusbarVisibleConfigurationKey);
			if (newStatusbarHiddenValue !== this.statusBarHidden) {
				this.setStatusBarHidden(newStatusbarHiddenValue, skipLayout);
			}
893

894 895 896 897
			const newActivityBarHiddenValue = !this.configurationService.getValue<boolean>(Workbench.activityBarVisibleConfigurationKey);
			if (newActivityBarHiddenValue !== this.activityBarHidden) {
				this.setActivityBarHidden(newActivityBarHiddenValue, skipLayout);
			}
B
Benjamin Pasero 已提交
898
		}
S
SteVen Batten 已提交
899

900
		const newMenubarVisibility = this.configurationService.getValue<MenuBarVisibility>(Workbench.menubarVisibilityConfigurationKey);
901
		this.setMenubarVisibility(newMenubarVisibility, !!skipLayout);
902
	}
B
Benjamin Pasero 已提交
903

904
	//#endregion
B
Benjamin Pasero 已提交
905

906
	private handleContextKeys(): void {
I
isidor 已提交
907 908 909
		IsMacContext.bindTo(this.contextKeyService);
		IsLinuxContext.bindTo(this.contextKeyService);
		IsWindowsContext.bindTo(this.contextKeyService);
910 911 912 913 914 915

		const windowConfig = this.configurationService.getValue<IWindowConfiguration>();
		HasMacNativeTabsContext.bindTo(this.contextKeyService).set(windowConfig && windowConfig.window && windowConfig.window.nativeTabs);

		IsDevelopmentContext.bindTo(this.contextKeyService).set(!this.environmentService.isBuilt || this.environmentService.isExtensionDevelopment);

916
		SupportsWorkspacesContext.bindTo(this.contextKeyService);
917 918 919
		SupportsOpenFileFolderContext.bindTo(this.contextKeyService).set(!!this.windowService.getConfiguration().remoteAuthority);

		this.inZenMode = InEditorZenModeContext.bindTo(this.contextKeyService);
920

921 922
		const sidebarVisibleContextRaw = new RawContextKey<boolean>('sidebarVisible', false);
		this.sideBarVisibleContext = sidebarVisibleContextRaw.bindTo(this.contextKeyService);
923

924
		const activeEditorContext = ActiveEditorContext.bindTo(this.contextKeyService);
925 926
		const editorsVisibleContext = EditorsVisibleContext.bindTo(this.contextKeyService);
		const textCompareEditorVisible = TextCompareEditorVisibleContext.bindTo(this.contextKeyService);
927
		const textCompareEditorActive = TextCompareEditorActiveContext.bindTo(this.contextKeyService);
928 929
		const activeEditorGroupEmpty = ActiveEditorGroupEmptyContext.bindTo(this.contextKeyService);
		const multipleEditorGroups = MultipleEditorGroupsContext.bindTo(this.contextKeyService);
930

931
		const updateEditorContextKeys = () => {
932
			const activeControl = this.editorService.activeControl;
933
			const visibleEditors = this.editorService.visibleControls;
E
Erich Gamma 已提交
934

935
			textCompareEditorActive.set(!!activeControl && activeControl.getId() === TEXT_DIFF_EDITOR_ID);
936
			textCompareEditorVisible.set(visibleEditors.some(control => control.getId() === TEXT_DIFF_EDITOR_ID));
I
isidor 已提交
937

938 939 940 941
			if (visibleEditors.length > 0) {
				editorsVisibleContext.set(true);
			} else {
				editorsVisibleContext.reset();
942
			}
B
Benjamin Pasero 已提交
943

944
			if (!this.editorService.activeEditor) {
945 946 947
				activeEditorGroupEmpty.set(true);
			} else {
				activeEditorGroupEmpty.reset();
948
			}
949

B
Benjamin Pasero 已提交
950
			if (this.editorGroupService.count > 1) {
951 952 953 954
				multipleEditorGroups.set(true);
			} else {
				multipleEditorGroups.reset();
			}
955 956 957 958 959 960

			if (activeControl) {
				activeEditorContext.set(activeControl.getId());
			} else {
				activeEditorContext.reset();
			}
961
		};
B
Benjamin Pasero 已提交
962

963
		this.editorPart.whenRestored.then(() => updateEditorContextKeys());
964 965
		this._register(this.editorService.onDidActiveEditorChange(() => updateEditorContextKeys()));
		this._register(this.editorService.onDidVisibleEditorsChange(() => updateEditorContextKeys()));
B
Benjamin Pasero 已提交
966 967
		this._register(this.editorGroupService.onDidAddGroup(() => updateEditorContextKeys()));
		this._register(this.editorGroupService.onDidRemoveGroup(() => updateEditorContextKeys()));
968

969
		const inputFocused = InputFocusedContext.bindTo(this.contextKeyService);
B
Benjamin Pasero 已提交
970 971

		function activeElementIsInput(): boolean {
972
			return !!document.activeElement && (document.activeElement.tagName === 'INPUT' || document.activeElement.tagName === 'TEXTAREA');
B
Benjamin Pasero 已提交
973 974 975 976 977 978 979
		}

		function trackInputFocus(): void {
			const isInputFocused = activeElementIsInput();
			inputFocused.set(isInputFocused);

			if (isInputFocused) {
980
				const tracker = trackFocus(document.activeElement as HTMLElement);
J
Joao Moreno 已提交
981
				Event.once(tracker.onDidBlur)(() => {
B
Benjamin Pasero 已提交
982 983 984 985 986 987 988
					inputFocused.set(activeElementIsInput());

					tracker.dispose();
				});
			}
		}

989
		this._register(addDisposableListener(window, 'focusin', () => trackInputFocus(), true));
990 991 992 993 994 995

		const workbenchStateRawContext = new RawContextKey<string>('workbenchState', getWorkbenchStateString(this.configurationService.getWorkbenchState()));
		const workbenchStateContext = workbenchStateRawContext.bindTo(this.contextKeyService);
		this._register(this.configurationService.onDidChangeWorkbenchState(() => {
			workbenchStateContext.set(getWorkbenchStateString(this.configurationService.getWorkbenchState()));
		}));
I
isidor 已提交
996

997 998 999 1000 1001
		const workspaceFolderCountRawContext = new RawContextKey<number>('workspaceFolderCount', this.configurationService.getWorkspace().folders.length);
		const workspaceFolderCountContext = workspaceFolderCountRawContext.bindTo(this.contextKeyService);
		this._register(this.configurationService.onDidChangeWorkspaceFolders(() => {
			workspaceFolderCountContext.set(this.configurationService.getWorkspace().folders.length);
		}));
1002

1003
		const splitEditorsVerticallyContext = SplitEditorsVertically.bindTo(this.contextKeyService);
S
Sanders Lauture 已提交
1004

1005 1006 1007 1008
		const updateSplitEditorsVerticallyContext = () => {
			const direction = preferredSideBySideGroupDirection(this.configurationService);
			splitEditorsVerticallyContext.set(direction === GroupDirection.DOWN);
		};
S
Sanders Lauture 已提交
1009

1010 1011 1012 1013 1014
		this._register(this.configurationService.onDidChangeConfiguration(e => {
			if (e.affectsConfiguration('workbench.editor.openSideBySideDirection')) {
				updateSplitEditorsVerticallyContext();
			}
		}));
E
Erich Gamma 已提交
1015

1016
		updateSplitEditorsVerticallyContext();
1017
	}
E
Erich Gamma 已提交
1018

1019
	private restoreParts(): Promise<void> {
J
Johannes Rieken 已提交
1020
		const restorePromises: Promise<any>[] = [];
B
Benjamin Pasero 已提交
1021

1022
		// Restore Editorpart
1023
		mark('willRestoreEditors');
1024
		restorePromises.push(this.editorPart.whenRestored.then(() => {
B
Benjamin Pasero 已提交
1025 1026 1027 1028

			function openEditors(editors: IResourceEditor[], editorService: IEditorService) {
				if (editors.length) {
					return editorService.openEditors(editors);
1029
				}
E
Erich Gamma 已提交
1030

J
Johannes Rieken 已提交
1031
				return Promise.resolve(undefined);
B
Benjamin Pasero 已提交
1032 1033 1034 1035 1036 1037 1038 1039 1040
			}

			const editorsToOpen = this.resolveEditorsToOpen();

			if (Array.isArray(editorsToOpen)) {
				return openEditors(editorsToOpen, this.editorService);
			}

			return editorsToOpen.then(editors => openEditors(editors, this.editorService));
1041
		}).then(() => mark('didRestoreEditors')));
E
Erich Gamma 已提交
1042

1043
		// Restore Sidebar
1044
		let viewletIdToRestore: string | undefined;
1045 1046
		if (!this.sideBarHidden) {
			this.sideBarVisibleContext.set(true);
1047

1048
			if (this.shouldRestoreLastOpenedViewlet()) {
1049
				viewletIdToRestore = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE);
1050
			}
1051

1052
			if (!viewletIdToRestore) {
I
isidor 已提交
1053
				viewletIdToRestore = this.sidebarPart.getDefaultViewletId();
1054
			}
E
Erich Gamma 已提交
1055

1056
			mark('willRestoreViewlet');
I
isidor 已提交
1057 1058
			restorePromises.push(this.sidebarPart.openViewlet(viewletIdToRestore)
				.then(viewlet => viewlet || this.sidebarPart.openViewlet(this.sidebarPart.getDefaultViewletId()))
1059
				.then(() => mark('didRestoreViewlet')));
1060 1061
		}

1062 1063
		// Restore Panel
		const panelRegistry = Registry.as<PanelRegistry>(PanelExtensions.Panels);
1064
		const panelId = this.storageService.get(PanelPart.activePanelSettingsKey, StorageScope.WORKSPACE, panelRegistry.getDefaultPanelId());
1065
		if (!this.panelHidden && !!panelId) {
1066
			mark('willRestorePanel');
1067
			const isPanelToRestoreEnabled = !!this.panelPart.getPanels().filter(p => p.id === panelId).length;
1068
			const panelIdToRestore = isPanelToRestoreEnabled ? panelId : panelRegistry.getDefaultPanelId();
1069
			this.panelPart.openPanel(panelIdToRestore, false);
1070
			mark('didRestorePanel');
I
isidor 已提交
1071 1072
		}

1073 1074 1075
		// Restore Zen Mode if active and supported for restore on startup
		const zenConfig = this.configurationService.getValue<IZenModeSettings>('zenMode');
		const wasZenActive = this.storageService.getBoolean(Workbench.zenModeActiveStorageKey, StorageScope.WORKSPACE, false);
1076
		if (wasZenActive && zenConfig.restore) {
I
isidor 已提交
1077
			this.toggleZenMode(true, true);
I
isidor 已提交
1078 1079
		}

B
Benjamin Pasero 已提交
1080
		// Restore Forced Editor Center Mode
1081
		if (this.storageService.getBoolean(Workbench.centeredEditorLayoutActiveStorageKey, StorageScope.WORKSPACE, false)) {
I
isidor 已提交
1082
			this.centerEditorLayout(true);
S
SrTobi 已提交
1083
		}
1084

1085
		const onRestored = (error?: Error): void => {
B
Benjamin Pasero 已提交
1086 1087 1088 1089 1090
			this.workbenchRestored = true;

			// Set lifecycle phase to `Restored`
			this.lifecycleService.phase = LifecyclePhase.Restored;

1091 1092 1093 1094 1095 1096 1097
			// Set lifecycle phase to `Eventually` after a short delay and when
			// idle (min 2.5sec, max 5sec)
			setTimeout(() => {
				this._register(runWhenIdle(() => {
					this.lifecycleService.phase = LifecyclePhase.Eventually;
				}, 2500));
			}, 2500);
1098

1099
			if (error) {
1100
				onUnexpectedError(error);
1101
			}
I
isidor 已提交
1102

1103
			this.logStartupTelemetry({
1104
				customKeybindingsCount: this.keybindingService.customKeybindingsCount(),
P
Pine Wu 已提交
1105
				pinnedViewlets: this.activitybarPart.getPinnedViewletIds(),
1106
				restoredViewlet: viewletIdToRestore,
1107
				restoredEditorsCount: this.editorService.visibleEditors.length
1108
			});
1109
		};
1110

B
Benjamin Pasero 已提交
1111
		return Promise.all(restorePromises).then(() => onRestored(), error => onRestored(error));
E
Erich Gamma 已提交
1112 1113
	}

1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157
	private logStartupTelemetry(info: IWorkbenchStartedInfo): void {
		const { filesToOpen, filesToCreate, filesToDiff } = this.configuration;

		/* __GDPR__
			"workspaceLoad" : {
				"userAgent" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
				"windowSize.innerHeight": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
				"windowSize.innerWidth": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
				"windowSize.outerHeight": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
				"windowSize.outerWidth": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
				"emptyWorkbench": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
				"workbench.filesToOpen": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
				"workbench.filesToCreate": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
				"workbench.filesToDiff": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
				"customKeybindingsCount": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
				"theme": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
				"language": { "classification": "SystemMetaData", "purpose": "BusinessInsight" },
				"pinnedViewlets": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
				"restoredViewlet": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
				"restoredEditors": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
				"pinnedViewlets": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
				"startupKind": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }
			}
		*/
		this.telemetryService.publicLog('workspaceLoad', {
			userAgent: navigator.userAgent,
			windowSize: { innerHeight: window.innerHeight, innerWidth: window.innerWidth, outerHeight: window.outerHeight, outerWidth: window.outerWidth },
			emptyWorkbench: this.contextService.getWorkbenchState() === WorkbenchState.EMPTY,
			'workbench.filesToOpen': filesToOpen && filesToOpen.length || 0,
			'workbench.filesToCreate': filesToCreate && filesToCreate.length || 0,
			'workbench.filesToDiff': filesToDiff && filesToDiff.length || 0,
			customKeybindingsCount: info.customKeybindingsCount,
			theme: this.themeService.getColorTheme().id,
			language,
			pinnedViewlets: info.pinnedViewlets,
			restoredViewlet: info.restoredViewlet,
			restoredEditors: info.restoredEditorsCount,
			startupKind: this.lifecycleService.startupKind
		});

		// Telemetry: startup metrics
		mark('didStartWorkbench');
	}

1158 1159 1160
	private shouldRestoreLastOpenedViewlet(): boolean {
		if (!this.environmentService.isBuilt) {
			return true; // always restore sidebar when we are in development mode
E
Erich Gamma 已提交
1161 1162
		}

1163 1164
		// always restore sidebar when the window was reloaded
		return this.lifecycleService.startupKind === StartupKind.ReloadedWindow;
E
Erich Gamma 已提交
1165 1166
	}

J
Johannes Rieken 已提交
1167
	private resolveEditorsToOpen(): Promise<IResourceEditor[]> | IResourceEditor[] {
I
isidor 已提交
1168

B
Benjamin Pasero 已提交
1169
		// Files to open, diff or create
1170
		if (this.hasInitialFilesToOpen) {
I
isidor 已提交
1171

B
Benjamin Pasero 已提交
1172
			// Files to diff is exclusive
B
Benjamin Pasero 已提交
1173
			const filesToDiff = this.toInputs(this.configuration.filesToDiff, false);
1174
			if (filesToDiff && filesToDiff.length === 2) {
B
Benjamin Pasero 已提交
1175
				return [<IResourceDiffInput>{
1176 1177
					leftResource: filesToDiff[0].resource,
					rightResource: filesToDiff[1].resource,
B
Benjamin Pasero 已提交
1178
					options: { pinned: true },
B
Benjamin Pasero 已提交
1179
					forceFile: true
B
Benjamin Pasero 已提交
1180
				}];
B
Benjamin Pasero 已提交
1181
			}
I
isidor 已提交
1182

B
Benjamin Pasero 已提交
1183 1184
			const filesToCreate = this.toInputs(this.configuration.filesToCreate, true);
			const filesToOpen = this.toInputs(this.configuration.filesToOpen, false);
I
isidor 已提交
1185

1186
			// Otherwise: Open/Create files
B
Benjamin Pasero 已提交
1187
			return [...filesToOpen, ...filesToCreate];
B
Benjamin Pasero 已提交
1188
		}
I
isidor 已提交
1189

1190
		// Empty workbench
1191
		else if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY && this.openUntitledFile()) {
B
Benjamin Pasero 已提交
1192
			const isEmpty = this.editorGroupService.count === 1 && this.editorGroupService.activeGroup.count === 0;
1193
			if (!isEmpty) {
B
Benjamin Pasero 已提交
1194
				return []; // do not open any empty untitled file if we restored editors from previous session
1195
			}
B
Benjamin Pasero 已提交
1196

1197 1198
			return this.backupFileService.hasBackups().then(hasBackups => {
				if (hasBackups) {
B
Benjamin Pasero 已提交
1199
					return []; // do not open any empty untitled file if we have backups to restore
1200
				}
B
Benjamin Pasero 已提交
1201

B
Benjamin Pasero 已提交
1202
				return [<IUntitledResourceInput>{}];
1203
			});
1204
		}
1205

B
Benjamin Pasero 已提交
1206
		return [];
B
Benjamin Pasero 已提交
1207
	}
1208

1209
	private toInputs(paths: IPath[], isNew: boolean): Array<IResourceInput | IUntitledResourceInput> {
B
Benjamin Pasero 已提交
1210 1211
		if (!paths || !paths.length) {
			return [];
1212
		}
I
isidor 已提交
1213

B
Benjamin Pasero 已提交
1214
		return paths.map(p => {
1215
			const resource = p.fileUri;
1216 1217 1218 1219
			let input: IResourceInput | IUntitledResourceInput;
			if (isNew) {
				input = { filePath: resource.fsPath, options: { pinned: true } } as IUntitledResourceInput;
			} else {
B
Benjamin Pasero 已提交
1220
				input = { resource, options: { pinned: true }, forceFile: true } as IResourceInput;
1221
			}
E
Erich Gamma 已提交
1222

1223
			if (!isNew && p.lineNumber) {
B
Benjamin Pasero 已提交
1224 1225 1226 1227 1228
				input.options.selection = {
					startLineNumber: p.lineNumber,
					startColumn: p.columnNumber
				};
			}
1229

B
Benjamin Pasero 已提交
1230 1231
			return input;
		});
1232 1233
	}

1234
	private openUntitledFile() {
1235
		const startupEditor = this.configurationService.inspect('workbench.startupEditor');
B
Benjamin Pasero 已提交
1236 1237

		// Fallback to previous workbench.welcome.enabled setting in case startupEditor is not defined
1238
		if (!startupEditor.user && !startupEditor.workspace) {
1239 1240 1241
			const welcomeEnabledValue = this.configurationService.getValue('workbench.welcome.enabled');
			if (typeof welcomeEnabledValue === 'boolean') {
				return !welcomeEnabledValue;
1242
			}
1243
		}
E
Erich Gamma 已提交
1244

1245
		return startupEditor.value === 'newUntitledFile';
1246
	}
E
Erich Gamma 已提交
1247 1248

	private initSettings(): void {
1249

S
SteVen Batten 已提交
1250 1251 1252
		// Editor visiblity
		this.editorHidden = false;

E
Erich Gamma 已提交
1253
		// Sidebar visibility
1254
		this.sideBarHidden = this.storageService.getBoolean(Workbench.sidebarHiddenStorageKey, StorageScope.WORKSPACE, this.contextService.getWorkbenchState() === WorkbenchState.EMPTY);
1255

I
isidor 已提交
1256
		// Panel part visibility
1257
		const panelRegistry = Registry.as<PanelRegistry>(PanelExtensions.Panels);
1258
		this.panelHidden = this.storageService.getBoolean(Workbench.panelHiddenStorageKey, StorageScope.WORKSPACE, true);
1259 1260
		if (!panelRegistry.getDefaultPanelId()) {
			this.panelHidden = true; // we hide panel part if there is no default panel
1261 1262
		}

E
Erich Gamma 已提交
1263
		// Sidebar position
1264
		const sideBarPosition = this.configurationService.getValue<string>(Workbench.sidebarPositionConfigurationKey);
1265
		this.sideBarPosition = (sideBarPosition === 'right') ? Position.RIGHT : Position.LEFT;
1266

I
isidor 已提交
1267
		// Panel position
1268
		this.setPanelPositionFromStorageOrConfig();
1269

1270
		// Menubar visibility
1271
		const menuBarVisibility = this.configurationService.getValue<MenuBarVisibility>(Workbench.menubarVisibilityConfigurationKey);
S
SteVen Batten 已提交
1272
		this.setMenubarVisibility(menuBarVisibility, true);
1273

B
Benjamin Pasero 已提交
1274
		// Statusbar visibility
1275
		const statusBarVisible = this.configurationService.getValue<string>(Workbench.statusbarVisibleConfigurationKey);
1276
		this.statusBarHidden = !statusBarVisible;
1277

S
Sanders Lauture 已提交
1278
		// Activity bar visibility
1279
		const activityBarVisible = this.configurationService.getValue<string>(Workbench.activityBarVisibleConfigurationKey);
S
Sanders Lauture 已提交
1280
		this.activityBarHidden = !activityBarVisible;
1281

1282
		// Font aliasing
1283
		this.fontAliasing = this.configurationService.getValue<FontAliasingOption>(Workbench.fontAliasingConfigurationKey);
1284

I
isidor 已提交
1285 1286
		// Zen mode
		this.zenMode = {
I
isidor 已提交
1287
			active: false,
1288
			transitionedToFullScreen: false,
1289
			transitionedToCenteredEditorLayout: false,
1290
			wasSideBarVisible: false,
1291 1292
			wasPanelVisible: false,
			transitionDisposeables: []
I
isidor 已提交
1293
		};
E
Erich Gamma 已提交
1294 1295
	}

1296 1297
	private setPanelPositionFromStorageOrConfig() {
		const defaultPanelPosition = this.configurationService.getValue<string>(Workbench.defaultPanelPositionStorageKey);
1298
		const panelPosition = this.storageService.get(Workbench.panelPositionStorageKey, StorageScope.WORKSPACE, defaultPanelPosition);
1299

1300 1301
		this.panelPosition = (panelPosition === 'right') ? Position.RIGHT : Position.BOTTOM;
	}
1302

B
Benjamin Pasero 已提交
1303 1304
	private useCustomTitleBarStyle(): boolean {
		return getTitleBarStyle(this.configurationService, this.environmentService) === 'custom';
B
Benjamin Pasero 已提交
1305 1306
	}

1307
	private saveLastPanelDimension(): void {
S
SteVen Batten 已提交
1308
		if (!(this.workbenchGrid instanceof Grid)) {
1309 1310 1311 1312
			return;
		}

		if (this.panelPosition === Position.BOTTOM) {
S
SteVen Batten 已提交
1313
			this.uiState.lastPanelHeight = this.workbenchGrid.getViewSize(this.panelPartView);
1314
		} else {
S
SteVen Batten 已提交
1315
			this.uiState.lastPanelWidth = this.workbenchGrid.getViewSize(this.panelPartView);
1316 1317 1318 1319 1320 1321 1322
		}
	}

	private getLastPanelDimension(position: Position): number | undefined {
		return position === Position.BOTTOM ? this.uiState.lastPanelHeight : this.uiState.lastPanelWidth;
	}

1323 1324
	private setStatusBarHidden(hidden: boolean, skipLayout?: boolean): void {
		this.statusBarHidden = hidden;
B
Benjamin Pasero 已提交
1325

1326 1327
		// Adjust CSS
		if (hidden) {
1328
			addClass(this.workbench, 'nostatusbar');
E
Erich Gamma 已提交
1329
		} else {
1330
			removeClass(this.workbench, 'nostatusbar');
E
Erich Gamma 已提交
1331 1332
		}

1333 1334
		// Layout
		if (!skipLayout) {
S
SteVen Batten 已提交
1335
			if (this.workbenchGrid instanceof Grid) {
S
SteVen Batten 已提交
1336
				this.layout();
1337 1338 1339
			} else {
				this.workbenchGrid.layout();
			}
1340 1341 1342
		}
	}

1343
	private setFontAliasing(aliasing: FontAliasingOption) {
1344
		this.fontAliasing = aliasing;
S
Sanders Lauture 已提交
1345

B
Benjamin Pasero 已提交
1346 1347 1348 1349 1350
		// Remove all
		document.body.classList.remove(...fontAliasingValues.map(value => `monaco-font-aliasing-${value}`));

		// Add specific
		if (fontAliasingValues.some(option => option === aliasing)) {
1351
			document.body.classList.add(`monaco-font-aliasing-${aliasing}`);
S
Sanders Lauture 已提交
1352
		}
1353 1354
	}

E
Erich Gamma 已提交
1355
	private createWorkbenchLayout(): void {
1356
		if (this.configurationService.getValue('workbench.useExperimentalGridLayout')) {
1357

S
SteVen Batten 已提交
1358 1359 1360 1361 1362 1363 1364 1365 1366
			// Create view wrappers for all parts
			this.titlebarPartView = new View(this.titlebarPart);
			this.sidebarPartView = new View(this.sidebarPart);
			this.activitybarPartView = new View(this.activitybarPart);
			this.editorPartView = new View(this.editorPart);
			this.panelPartView = new View(this.panelPart);
			this.statusbarPartView = new View(this.statusbarPart);

			this.workbenchGrid = new Grid(this.editorPartView, { proportionalLayout: false });
1367

1368
			this.workbench.prepend(this.workbenchGrid.element);
1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387
		} else {
			this.workbenchGrid = this.instantiationService.createInstance(
				WorkbenchLayout,
				this.container,
				this.workbench,
				{
					titlebar: this.titlebarPart,
					activitybar: this.activitybarPart,
					editor: this.editorPart,
					sidebar: this.sidebarPart,
					panel: this.panelPart,
					statusbar: this.statusbarPart,
				},
				this.quickOpen,
				this.quickInput,
				this.notificationsCenter,
				this.notificationsToasts
			);
		}
E
Erich Gamma 已提交
1388 1389 1390 1391 1392 1393
	}

	private renderWorkbench(): void {

		// Apply sidebar state as CSS class
		if (this.sideBarHidden) {
1394
			addClass(this.workbench, 'nosidebar');
E
Erich Gamma 已提交
1395
		}
B
Benjamin Pasero 已提交
1396

1397
		if (this.panelHidden) {
1398
			addClass(this.workbench, 'nopanel');
1399
		}
B
Benjamin Pasero 已提交
1400

1401
		if (this.statusBarHidden) {
1402
			addClass(this.workbench, 'nostatusbar');
1403
		}
E
Erich Gamma 已提交
1404

B
Benjamin Pasero 已提交
1405
		// Apply font aliasing
1406 1407
		this.setFontAliasing(this.fontAliasing);

1408
		// Apply fullscreen state
1409 1410
		if (isFullscreen()) {
			addClass(this.workbench, 'fullscreen');
B
Benjamin Pasero 已提交
1411 1412
		}

E
Erich Gamma 已提交
1413
		// Create Parts
B
Benjamin Pasero 已提交
1414
		this.createTitlebarPart();
E
Erich Gamma 已提交
1415 1416 1417
		this.createActivityBarPart();
		this.createSidebarPart();
		this.createEditorPart();
1418
		this.createPanelPart();
E
Erich Gamma 已提交
1419 1420
		this.createStatusbarPart();

1421 1422
		// Notification Handlers
		this.createNotificationsHandlers();
1423

1424 1425

		// Menubar visibility changes
B
Benjamin Pasero 已提交
1426
		if ((isWindows || isLinux) && this.useCustomTitleBarStyle()) {
1427 1428 1429
			this.titlebarPart.onMenubarVisibilityChange()(e => this.onMenubarToggled(e));
		}

E
Erich Gamma 已提交
1430
		// Add Workbench to DOM
B
Benjamin Pasero 已提交
1431
		this.container.appendChild(this.workbench);
E
Erich Gamma 已提交
1432 1433
	}

B
Benjamin Pasero 已提交
1434
	private createTitlebarPart(): void {
B
Benjamin Pasero 已提交
1435
		const titlebarContainer = this.createPart(Identifiers.TITLEBAR_PART, ['part', 'titlebar'], 'contentinfo');
B
Benjamin Pasero 已提交
1436

B
Benjamin Pasero 已提交
1437
		this.titlebarPart.create(titlebarContainer);
B
Benjamin Pasero 已提交
1438 1439
	}

E
Erich Gamma 已提交
1440
	private createActivityBarPart(): void {
B
Benjamin Pasero 已提交
1441
		const activitybarPartContainer = this.createPart(Identifiers.ACTIVITYBAR_PART, ['part', 'activitybar', this.sideBarPosition === Position.LEFT ? 'left' : 'right'], 'navigation');
E
Erich Gamma 已提交
1442

B
Benjamin Pasero 已提交
1443
		this.activitybarPart.create(activitybarPartContainer);
E
Erich Gamma 已提交
1444 1445 1446
	}

	private createSidebarPart(): void {
B
Benjamin Pasero 已提交
1447
		const sidebarPartContainer = this.createPart(Identifiers.SIDEBAR_PART, ['part', 'sidebar', this.sideBarPosition === Position.LEFT ? 'left' : 'right'], 'complementary');
E
Erich Gamma 已提交
1448

B
Benjamin Pasero 已提交
1449
		this.sidebarPart.create(sidebarPartContainer);
E
Erich Gamma 已提交
1450 1451
	}

I
isidor 已提交
1452
	private createPanelPart(): void {
B
Benjamin Pasero 已提交
1453
		const panelPartContainer = this.createPart(Identifiers.PANEL_PART, ['part', 'panel', this.panelPosition === Position.BOTTOM ? 'bottom' : 'right'], 'complementary');
I
isidor 已提交
1454

B
Benjamin Pasero 已提交
1455
		this.panelPart.create(panelPartContainer);
I
isidor 已提交
1456 1457
	}

E
Erich Gamma 已提交
1458
	private createEditorPart(): void {
B
Benjamin Pasero 已提交
1459
		const editorContainer = this.createPart(Identifiers.EDITOR_PART, ['part', 'editor'], 'main');
E
Erich Gamma 已提交
1460

B
Benjamin Pasero 已提交
1461
		this.editorPart.create(editorContainer);
E
Erich Gamma 已提交
1462 1463 1464
	}

	private createStatusbarPart(): void {
B
Benjamin Pasero 已提交
1465 1466 1467 1468 1469 1470 1471
		const statusbarContainer = this.createPart(Identifiers.STATUSBAR_PART, ['part', 'statusbar'], 'contentinfo');

		this.statusbarPart.create(statusbarContainer);
	}

	private createPart(id: string, classes: string[], role: string): HTMLElement {
		const part = document.createElement('div');
1472
		classes.forEach(clazz => addClass(part, clazz));
B
Benjamin Pasero 已提交
1473 1474 1475
		part.id = id;
		part.setAttribute('role', role);

1476 1477 1478 1479 1480
		if (!this.configurationService.getValue('workbench.useExperimentalGridLayout')) {
			// Insert all workbench parts at the beginning. Issue #52531
			// This is primarily for the title bar to allow overriding -webkit-app-region
			this.workbench.insertBefore(part, this.workbench.lastChild);
		}
E
Erich Gamma 已提交
1481

B
Benjamin Pasero 已提交
1482
		return part;
E
Erich Gamma 已提交
1483 1484
	}

1485 1486
	private createNotificationsHandlers(): void {

1487
		// Notifications Center
B
Benjamin Pasero 已提交
1488
		this.notificationsCenter = this._register(this.instantiationService.createInstance(NotificationsCenter, this.workbench, this.notificationService.model));
1489

1490
		// Notifications Toasts
B
Benjamin Pasero 已提交
1491
		this.notificationsToasts = this._register(this.instantiationService.createInstance(NotificationsToasts, this.workbench, this.notificationService.model));
1492

1493
		// Notifications Alerts
1494
		this._register(this.instantiationService.createInstance(NotificationsAlerts, this.notificationService.model));
1495 1496 1497 1498

		// Notifications Status
		const notificationsStatus = this.instantiationService.createInstance(NotificationsStatus, this.notificationService.model);

1499
		// Eventing
1500
		this._register(this.notificationsCenter.onDidChangeVisibility(() => {
1501 1502 1503 1504 1505 1506 1507 1508

			// Update status
			notificationsStatus.update(this.notificationsCenter.isVisible);

			// Update toasts
			this.notificationsToasts.update(this.notificationsCenter.isVisible);
		}));

1509
		// Register Commands
1510
		registerNotificationCommands(this.notificationsCenter, this.notificationsToasts);
1511 1512
	}

1513
	private saveState(e: IWillSaveStateEvent): void {
1514
		if (this.zenMode.active) {
B
Benjamin Pasero 已提交
1515
			this.storageService.store(Workbench.zenModeActiveStorageKey, true, StorageScope.WORKSPACE);
1516
		} else {
B
Benjamin Pasero 已提交
1517
			this.storageService.remove(Workbench.zenModeActiveStorageKey, StorageScope.WORKSPACE);
1518
		}
1519 1520 1521 1522 1523 1524 1525 1526

		if (e.reason === WillSaveStateReason.SHUTDOWN && this.zenMode.active) {
			const zenConfig = this.configurationService.getValue<IZenModeSettings>('zenMode');
			if (!zenConfig.restore) {
				// We will not restore zen mode, need to clear all zen mode state changes
				this.toggleZenMode(true);
			}
		}
1527 1528
	}

1529
	dispose(): void {
1530
		super.dispose();
1531 1532 1533 1534 1535 1536

		this.workbenchShutdown = true;
	}

	//#region IPartService

M
Matt Bierner 已提交
1537
	private readonly _onTitleBarVisibilityChange: Emitter<void> = this._register(new Emitter<void>());
1538
	get onTitleBarVisibilityChange(): Event<void> { return this._onTitleBarVisibilityChange.event; }
1539

1540
	get onEditorLayout(): Event<IDimension> { return this.editorPart.onDidLayout; }
1541

B
Benjamin Pasero 已提交
1542 1543
	isRestored(): boolean {
		return !!(this.workbenchRestored && this.workbenchStarted);
1544
	}
1545

1546 1547 1548 1549 1550
	hasFocus(part: Parts): boolean {
		const activeElement = document.activeElement;
		if (!activeElement) {
			return false;
		}
1551

1552
		const container = this.getContainer(part);
1553
		return isAncestor(activeElement, container);
1554
	}
1555

1556
	getContainer(part: Parts): HTMLElement | null {
1557 1558
		switch (part) {
			case Parts.TITLEBAR_PART:
1559
				return this.titlebarPart.getContainer();
1560
			case Parts.ACTIVITYBAR_PART:
1561
				return this.activitybarPart.getContainer();
1562
			case Parts.SIDEBAR_PART:
1563
				return this.sidebarPart.getContainer();
1564
			case Parts.PANEL_PART:
1565
				return this.panelPart.getContainer();
1566
			case Parts.EDITOR_PART:
1567
				return this.editorPart.getContainer();
1568
			case Parts.STATUSBAR_PART:
1569
				return this.statusbarPart.getContainer();
1570
		}
1571

1572
		return null;
1573
	}
1574

1575 1576 1577
	isVisible(part: Parts): boolean {
		switch (part) {
			case Parts.TITLEBAR_PART:
B
Benjamin Pasero 已提交
1578
				if (!this.useCustomTitleBarStyle()) {
1579
					return false;
1580
				} else if (!isFullscreen()) {
1581 1582 1583 1584 1585 1586 1587 1588 1589 1590
					return true;
				} else if (isMacintosh) {
					return false;
				} else if (this.menubarVisibility === 'visible') {
					return true;
				} else if (this.menubarVisibility === 'toggle' || this.menubarVisibility === 'default') {
					return this.menubarToggled;
				}

				return false;
1591 1592 1593 1594 1595 1596 1597 1598
			case Parts.SIDEBAR_PART:
				return !this.sideBarHidden;
			case Parts.PANEL_PART:
				return !this.panelHidden;
			case Parts.STATUSBAR_PART:
				return !this.statusBarHidden;
			case Parts.ACTIVITYBAR_PART:
				return !this.activityBarHidden;
1599 1600
			case Parts.EDITOR_PART:
				return this.workbenchGrid instanceof Grid ? !this.editorHidden : true;
E
Erich Gamma 已提交
1601
		}
1602

1603
		return true; // any other part cannot be hidden
E
Erich Gamma 已提交
1604 1605
	}

1606 1607 1608
	getTitleBarOffset(): number {
		let offset = 0;
		if (this.isVisible(Parts.TITLEBAR_PART)) {
S
SteVen Batten 已提交
1609
			if (this.workbenchGrid instanceof Grid) {
S
SteVen Batten 已提交
1610
				offset = this.titlebarPart.maximumHeight;
S
SteVen Batten 已提交
1611 1612 1613
			} else {
				offset = this.workbenchGrid.partLayoutInfo.titlebar.height;

B
Benjamin Pasero 已提交
1614 1615 1616
				if (isMacintosh || this.menubarVisibility === 'hidden') {
					offset /= getZoomFactor();
				}
1617
			}
E
Erich Gamma 已提交
1618
		}
1619 1620

		return offset;
E
Erich Gamma 已提交
1621
	}
1622

1623 1624
	getWorkbenchElement(): HTMLElement {
		return this.workbench;
1625
	}
1626

I
isidor 已提交
1627
	toggleZenMode(skipLayout?: boolean, restoring = false): void {
I
isidor 已提交
1628
		this.zenMode.active = !this.zenMode.active;
1629
		this.zenMode.transitionDisposeables = dispose(this.zenMode.transitionDisposeables);
1630

1631 1632
		// Check if zen mode transitioned to full screen and if now we are out of zen mode
		// -> we need to go out of full screen (same goes for the centered editor layout)
1633
		let toggleFullScreen = false;
I
isidor 已提交
1634 1635 1636 1637 1638 1639 1640 1641
		const setLineNumbers = (lineNumbers: any) => {
			this.editorService.visibleControls.forEach(editor => {
				const control = <IEditor>editor.getControl();
				if (control) {
					control.updateOptions({ lineNumbers });
				}
			});
		};
1642 1643

		// Zen Mode Active
I
isidor 已提交
1644
		if (this.zenMode.active) {
1645
			const config = this.configurationService.getValue<IZenModeSettings>('zenMode');
1646

1647
			toggleFullScreen = !isFullscreen() && config.fullScreen;
I
isidor 已提交
1648
			this.zenMode.transitionedToFullScreen = restoring ? config.fullScreen : toggleFullScreen;
1649
			this.zenMode.transitionedToCenteredEditorLayout = !this.isEditorLayoutCentered() && config.centerLayout;
1650 1651
			this.zenMode.wasSideBarVisible = this.isVisible(Parts.SIDEBAR_PART);
			this.zenMode.wasPanelVisible = this.isVisible(Parts.PANEL_PART);
1652

1653 1654
			this.setPanelHidden(true, true);
			this.setSideBarHidden(true, true);
I
isidor 已提交
1655

1656 1657 1658
			if (config.hideActivityBar) {
				this.setActivityBarHidden(true, true);
			}
1659

I
isidor 已提交
1660
			if (config.hideStatusBar) {
I
isidor 已提交
1661 1662
				this.setStatusBarHidden(true, true);
			}
1663

I
isidor 已提交
1664 1665 1666 1667 1668
			if (config.hideLineNumbers) {
				setLineNumbers('off');
				this.zenMode.transitionDisposeables.push(this.editorService.onDidVisibleEditorsChange(() => setLineNumbers('off')));
			}

1669 1670
			if (config.hideTabs && this.editorPart.partOptions.showTabs) {
				this.zenMode.transitionDisposeables.push(this.editorPart.enforcePartOptions({ showTabs: false }));
I
isidor 已提交
1671
			}
1672 1673 1674 1675

			if (config.centerLayout) {
				this.centerEditorLayout(true, true);
			}
1676 1677 1678 1679
		}

		// Zen Mode Inactive
		else {
1680
			if (this.zenMode.wasPanelVisible) {
1681
				this.setPanelHidden(false, true);
1682
			}
1683

1684
			if (this.zenMode.wasSideBarVisible) {
1685
				this.setSideBarHidden(false, true);
1686
			}
1687

1688 1689 1690
			if (this.zenMode.transitionedToCenteredEditorLayout) {
				this.centerEditorLayout(false, true);
			}
I
isidor 已提交
1691
			setLineNumbers(this.configurationService.getValue('editor.lineNumbers'));
1692

1693 1694
			// Status bar and activity bar visibility come from settings -> update their visibility.
			this.onDidUpdateConfiguration(true);
1695

B
Benjamin Pasero 已提交
1696
			this.editorGroupService.activeGroup.focus();
1697

1698
			toggleFullScreen = this.zenMode.transitionedToFullScreen && isFullscreen();
I
isidor 已提交
1699
		}
1700

1701
		this.inZenMode.set(this.zenMode.active);
I
isidor 已提交
1702

I
isidor 已提交
1703
		if (!skipLayout) {
1704
			this.layout();
I
isidor 已提交
1705
		}
1706

1707
		if (toggleFullScreen) {
1708
			this.windowService.toggleFullScreen();
1709
		}
I
isidor 已提交
1710 1711
	}

S
SteVen Batten 已提交
1712
	private updateGrid(): void {
S
SteVen Batten 已提交
1713
		if (!(this.workbenchGrid instanceof Grid)) {
1714 1715 1716
			return;
		}

S
SteVen Batten 已提交
1717 1718 1719 1720 1721
		let panelInGrid = this.workbenchGrid.hasView(this.panelPartView);
		let sidebarInGrid = this.workbenchGrid.hasView(this.sidebarPartView);
		let activityBarInGrid = this.workbenchGrid.hasView(this.activitybarPartView);
		let statusBarInGrid = this.workbenchGrid.hasView(this.statusbarPartView);
		let titlebarInGrid = this.workbenchGrid.hasView(this.titlebarPartView);
1722

S
SteVen Batten 已提交
1723 1724 1725
		// Add parts to grid
		if (!statusBarInGrid) {
			this.workbenchGrid.addView(this.statusbarPartView, Sizing.Split, this.editorPartView, Direction.Down);
S
SteVen Batten 已提交
1726 1727 1728
			statusBarInGrid = true;
		}

1729
		if (!titlebarInGrid && this.useCustomTitleBarStyle()) {
S
SteVen Batten 已提交
1730 1731 1732
			this.workbenchGrid.addView(this.titlebarPartView, Sizing.Split, this.editorPartView, Direction.Up);
			titlebarInGrid = true;
		}
S
SteVen Batten 已提交
1733

S
SteVen Batten 已提交
1734 1735 1736 1737
		if (!activityBarInGrid) {
			this.workbenchGrid.addView(this.activitybarPartView, Sizing.Split, panelInGrid && this.sideBarPosition === this.panelPosition ? this.panelPartView : this.editorPartView, this.sideBarPosition === Position.RIGHT ? Direction.Right : Direction.Left);
			activityBarInGrid = true;
		}
S
SteVen Batten 已提交
1738

S
SteVen Batten 已提交
1739 1740 1741 1742
		if (!sidebarInGrid) {
			this.workbenchGrid.addView(this.sidebarPartView, this.uiState.lastSidebarDimension !== undefined ? this.uiState.lastSidebarDimension : Sizing.Split, this.activitybarPartView, this.sideBarPosition === Position.LEFT ? Direction.Right : Direction.Left);
			sidebarInGrid = true;
		}
S
SteVen Batten 已提交
1743

S
SteVen Batten 已提交
1744 1745 1746
		if (!panelInGrid) {
			this.workbenchGrid.addView(this.panelPartView, this.getLastPanelDimension(this.panelPosition) !== undefined ? this.getLastPanelDimension(this.panelPosition) : Sizing.Split, this.editorPartView, this.panelPosition === Position.BOTTOM ? Direction.Down : Direction.Right);
			panelInGrid = true;
S
SteVen Batten 已提交
1747 1748
		}

S
SteVen Batten 已提交
1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773
		// Hide parts
		if (this.panelHidden) {
			this.panelPartView.hide();
		}

		if (this.statusBarHidden) {
			this.statusbarPartView.hide();
		}

		if (!this.isVisible(Parts.TITLEBAR_PART)) {
			this.titlebarPartView.hide();
		}

		if (this.activityBarHidden) {
			this.activitybarPartView.hide();
		}

		if (this.sideBarHidden) {
			this.sidebarPartView.hide();
		}

		if (this.editorHidden) {
			this.editorPartView.hide();
		}

S
SteVen Batten 已提交
1774
		// Show visible parts
S
SteVen Batten 已提交
1775 1776 1777 1778
		if (!this.editorHidden) {
			this.editorPartView.show();
		}

S
SteVen Batten 已提交
1779 1780 1781
		if (!this.statusBarHidden) {
			this.statusbarPartView.show();
		}
S
SteVen Batten 已提交
1782

S
SteVen Batten 已提交
1783 1784
		if (this.isVisible(Parts.TITLEBAR_PART)) {
			this.titlebarPartView.show();
S
SteVen Batten 已提交
1785 1786
		}

S
SteVen Batten 已提交
1787 1788 1789
		if (!this.activityBarHidden) {
			this.activitybarPartView.show();
		}
S
SteVen Batten 已提交
1790

S
SteVen Batten 已提交
1791 1792
		if (!this.sideBarHidden) {
			this.sidebarPartView.show();
S
SteVen Batten 已提交
1793 1794
		}

S
SteVen Batten 已提交
1795 1796
		if (!this.panelHidden) {
			this.panelPartView.show();
S
SteVen Batten 已提交
1797 1798 1799
		}
	}

1800
	private layout(options?: ILayoutOptions): void {
S
SteVen Batten 已提交
1801 1802 1803
		this.contextViewService.layout();

		if (this.workbenchStarted && !this.workbenchShutdown) {
S
SteVen Batten 已提交
1804
			if (this.workbenchGrid instanceof Grid) {
1805 1806 1807
				const dimensions = getClientArea(this.container);
				position(this.workbench, 0, 0, 0, 0, 'relative');
				size(this.workbench, dimensions.width, dimensions.height);
S
SteVen Batten 已提交
1808

S
SteVen Batten 已提交
1809
				// Layout the grid
S
SteVen Batten 已提交
1810
				this.workbenchGrid.layout(dimensions.width, dimensions.height);
S
SteVen Batten 已提交
1811 1812 1813 1814 1815 1816 1817 1818

				// Layout non-view ui components
				this.quickInput.layout(dimensions);
				this.quickOpen.layout(dimensions);
				this.notificationsCenter.layout(dimensions);
				this.notificationsToasts.layout(dimensions);

				// Update grid view membership
1819
				this.updateGrid();
S
SteVen Batten 已提交
1820 1821
			} else {
				this.workbenchGrid.layout(options);
1822
			}
1823 1824 1825
		}
	}

1826
	isEditorLayoutCentered(): boolean {
1827
		return this.shouldCenterLayout;
S
SrTobi 已提交
1828 1829
	}

1830
	centerEditorLayout(active: boolean, skipLayout?: boolean): void {
B
Benjamin Pasero 已提交
1831
		this.storageService.store(Workbench.centeredEditorLayoutActiveStorageKey, active, StorageScope.WORKSPACE);
1832 1833
		this.shouldCenterLayout = active;
		let smartActive = active;
1834
		if (this.editorPart.groups.length > 1 && this.configurationService.getValue('workbench.editor.centeredLayoutAutoResize')) {
B
Benjamin Pasero 已提交
1835
			smartActive = false; // Respect the auto resize setting - do not go into centered layout if there is more than 1 group.
1836
		}
B
Benjamin Pasero 已提交
1837

1838
		// Enter Centered Editor Layout
1839 1840
		if (this.editorPart.isLayoutCentered() !== smartActive) {
			this.editorPart.centerLayout(smartActive);
1841

1842 1843 1844
			if (!skipLayout) {
				this.layout();
			}
1845
		}
S
SrTobi 已提交
1846 1847
	}

1848
	resizePart(part: Parts, sizeChange: number): void {
S
SteVen Batten 已提交
1849
		let view: View;
1850 1851
		switch (part) {
			case Parts.SIDEBAR_PART:
S
SteVen Batten 已提交
1852
				view = this.sidebarPartView;
1853
			case Parts.PANEL_PART:
S
SteVen Batten 已提交
1854
				view = this.panelPartView;
1855
			case Parts.EDITOR_PART:
S
SteVen Batten 已提交
1856 1857
				view = this.editorPartView;
				if (this.workbenchGrid instanceof Grid) {
1858 1859 1860 1861
					this.workbenchGrid.resizeView(view, this.workbenchGrid.getViewSize(view) + sizeChange);
				} else {
					this.workbenchGrid.resizePart(part, sizeChange);
				}
1862 1863
				break;
			default:
B
Benjamin Pasero 已提交
1864
				return; // Cannot resize other parts
1865 1866 1867
		}
	}

1868 1869
	setActivityBarHidden(hidden: boolean, skipLayout?: boolean): void {
		this.activityBarHidden = hidden;
1870

1871 1872
		// Layout
		if (!skipLayout) {
S
SteVen Batten 已提交
1873
			if (this.workbenchGrid instanceof Grid) {
S
SteVen Batten 已提交
1874
				this.layout();
1875 1876 1877
			} else {
				this.workbenchGrid.layout();
			}
1878
		}
1879
	}
1880

S
SteVen Batten 已提交
1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897
	setEditorHidden(hidden: boolean, skipLayout?: boolean): void {
		if (!(this.workbenchGrid instanceof Grid)) {
			return;
		}

		this.editorHidden = hidden;

		// The editor and the panel cannot be hidden at the same time
		if (this.editorHidden && this.panelHidden) {
			this.setPanelHidden(false, true);
		}

		if (!skipLayout) {
			this.layout();
		}
	}

1898
	setSideBarHidden(hidden: boolean, skipLayout?: boolean): void {
1899 1900 1901 1902 1903
		this.sideBarHidden = hidden;
		this.sideBarVisibleContext.set(!hidden);

		// Adjust CSS
		if (hidden) {
1904
			addClass(this.workbench, 'nosidebar');
1905
		} else {
1906
			removeClass(this.workbench, 'nosidebar');
1907 1908
		}

1909 1910
		// If sidebar becomes hidden, also hide the current active Viewlet if any
		if (hidden && this.sidebarPart.getActiveViewlet()) {
1911 1912 1913 1914 1915 1916 1917 1918 1919
			this.sidebarPart.hideActiveViewlet();
			const activePanel = this.panelPart.getActivePanel();

			// Pass Focus to Editor or Panel if Sidebar is now hidden
			if (this.hasFocus(Parts.PANEL_PART) && activePanel) {
				activePanel.focus();
			} else {
				this.editorGroupService.activeGroup.focus();
			}
1920 1921 1922 1923 1924 1925
		}

		// If sidebar becomes visible, show last active Viewlet or default viewlet
		else if (!hidden && !this.sidebarPart.getActiveViewlet()) {
			const viewletToOpen = this.sidebarPart.getLastActiveViewletId();
			if (viewletToOpen) {
I
isidor 已提交
1926
				const viewlet = this.sidebarPart.openViewlet(viewletToOpen, true);
1927
				if (!viewlet) {
I
isidor 已提交
1928
					this.sidebarPart.openViewlet(this.sidebarPart.getDefaultViewletId(), true);
1929
				}
1930
			}
1931 1932
		}

1933 1934 1935 1936 1937 1938 1939
		// Remember in settings
		const defaultHidden = this.contextService.getWorkbenchState() === WorkbenchState.EMPTY;
		if (hidden !== defaultHidden) {
			this.storageService.store(Workbench.sidebarHiddenStorageKey, hidden ? 'true' : 'false', StorageScope.WORKSPACE);
		} else {
			this.storageService.remove(Workbench.sidebarHiddenStorageKey, StorageScope.WORKSPACE);
		}
1940

1941 1942
		// Layout
		if (!skipLayout) {
S
SteVen Batten 已提交
1943
			if (this.workbenchGrid instanceof Grid) {
S
SteVen Batten 已提交
1944
				this.layout();
1945 1946 1947
			} else {
				this.workbenchGrid.layout();
			}
1948
		}
1949
	}
1950

1951
	setPanelHidden(hidden: boolean, skipLayout?: boolean): void {
1952 1953 1954 1955
		this.panelHidden = hidden;

		// Adjust CSS
		if (hidden) {
1956
			addClass(this.workbench, 'nopanel');
1957
		} else {
1958
			removeClass(this.workbench, 'nopanel');
1959 1960 1961 1962
		}

		// If panel part becomes hidden, also hide the current active panel if any
		if (hidden && this.panelPart.getActivePanel()) {
1963 1964
			this.panelPart.hideActivePanel();
			this.editorGroupService.activeGroup.focus(); // Pass focus to editor group if panel part is now hidden
1965 1966 1967 1968 1969 1970
		}

		// If panel part becomes visible, show last active panel or default panel
		else if (!hidden && !this.panelPart.getActivePanel()) {
			const panelToOpen = this.panelPart.getLastActivePanelId();
			if (panelToOpen) {
1971
				this.panelPart.openPanel(panelToOpen, true);
1972 1973 1974
			}
		}

1975 1976 1977 1978 1979 1980
		// Remember in settings
		if (!hidden) {
			this.storageService.store(Workbench.panelHiddenStorageKey, 'false', StorageScope.WORKSPACE);
		} else {
			this.storageService.remove(Workbench.panelHiddenStorageKey, StorageScope.WORKSPACE);
		}
1981

S
SteVen Batten 已提交
1982 1983 1984 1985 1986
		// The editor and panel cannot be hiddne at the same time
		if (hidden && this.editorHidden) {
			this.setEditorHidden(false, true);
		}

1987 1988
		// Layout
		if (!skipLayout) {
S
SteVen Batten 已提交
1989
			if (this.workbenchGrid instanceof Grid) {
S
SteVen Batten 已提交
1990
				this.layout();
1991 1992 1993
			} else {
				this.workbenchGrid.layout();
			}
1994
		}
1995 1996 1997
	}

	toggleMaximizedPanel(): void {
S
SteVen Batten 已提交
1998 1999
		if (this.workbenchGrid instanceof Grid) {
			this.workbenchGrid.maximizeViewSize(this.panelPartView);
2000 2001 2002
		} else {
			this.workbenchGrid.layout({ toggleMaximizedPanel: true, source: Parts.PANEL_PART });
		}
2003 2004 2005
	}

	isPanelMaximized(): boolean {
S
SteVen Batten 已提交
2006
		if (this.workbenchGrid instanceof Grid) {
2007
			try {
S
SteVen Batten 已提交
2008
				return this.workbenchGrid.getViewSize2(this.panelPartView).height === this.panelPart.maximumHeight;
2009 2010 2011 2012 2013 2014
			} catch (e) {
				return false;
			}
		} else {
			return this.workbenchGrid.isPanelMaximized();
		}
2015 2016 2017 2018 2019 2020 2021
	}

	getSideBarPosition(): Position {
		return this.sideBarPosition;
	}

	setSideBarPosition(position: Position): void {
2022 2023
		const wasHidden = this.sideBarHidden;

2024
		if (this.sideBarHidden) {
2025
			this.setSideBarHidden(false, true /* Skip Layout */);
2026 2027 2028 2029 2030 2031 2032
		}

		const newPositionValue = (position === Position.LEFT) ? 'left' : 'right';
		const oldPositionValue = (this.sideBarPosition === Position.LEFT) ? 'left' : 'right';
		this.sideBarPosition = position;

		// Adjust CSS
2033 2034 2035 2036
		removeClass(this.activitybarPart.getContainer(), oldPositionValue);
		removeClass(this.sidebarPart.getContainer(), oldPositionValue);
		addClass(this.activitybarPart.getContainer(), newPositionValue);
		addClass(this.sidebarPart.getContainer(), newPositionValue);
2037 2038 2039 2040 2041 2042

		// Update Styles
		this.activitybarPart.updateStyles();
		this.sidebarPart.updateStyles();

		// Layout
S
SteVen Batten 已提交
2043
		if (this.workbenchGrid instanceof Grid) {
2044

S
SteVen Batten 已提交
2045
			if (!wasHidden) {
S
SteVen Batten 已提交
2046
				this.uiState.lastSidebarDimension = this.workbenchGrid.getViewSize(this.sidebarPartView);
2047 2048
			}

S
SteVen Batten 已提交
2049 2050
			this.workbenchGrid.removeView(this.sidebarPartView);
			this.workbenchGrid.removeView(this.activitybarPartView);
S
SteVen Batten 已提交
2051 2052 2053

			if (!this.panelHidden && this.panelPosition === Position.BOTTOM) {
				this.workbenchGrid.removeView(this.panelPartView);
2054 2055
			}

S
SteVen Batten 已提交
2056
			this.layout();
2057 2058 2059
		} else {
			this.workbenchGrid.layout();
		}
2060 2061
	}

S
SteVen Batten 已提交
2062
	setMenubarVisibility(visibility: MenuBarVisibility, skipLayout: boolean): void {
S
SteVen Batten 已提交
2063 2064
		if (this.menubarVisibility !== visibility) {
			this.menubarVisibility = visibility;
2065

2066
			// Layout
S
SteVen Batten 已提交
2067
			if (!skipLayout) {
S
SteVen Batten 已提交
2068
				if (this.workbenchGrid instanceof Grid) {
2069
					const dimensions = getClientArea(this.container);
2070 2071 2072 2073
					this.workbenchGrid.layout(dimensions.width, dimensions.height);
				} else {
					this.workbenchGrid.layout();
				}
S
SteVen Batten 已提交
2074
			}
2075 2076 2077
		}
	}

S
SteVen Batten 已提交
2078 2079 2080 2081
	getMenubarVisibility(): MenuBarVisibility {
		return this.menubarVisibility;
	}

2082 2083 2084 2085
	getPanelPosition(): Position {
		return this.panelPosition;
	}

2086
	setPanelPosition(position: Position): void {
2087 2088
		const wasHidden = this.panelHidden;

2089 2090
		if (this.panelHidden) {
			this.setPanelHidden(false, true /* Skip Layout */);
2091 2092
		} else {
			this.saveLastPanelDimension();
2093
		}
2094

2095 2096 2097 2098
		const newPositionValue = (position === Position.BOTTOM) ? 'bottom' : 'right';
		const oldPositionValue = (this.panelPosition === Position.BOTTOM) ? 'bottom' : 'right';
		this.panelPosition = position;
		this.storageService.store(Workbench.panelPositionStorageKey, PositionToString(this.panelPosition).toLowerCase(), StorageScope.WORKSPACE);
2099

2100
		// Adjust CSS
2101 2102
		removeClass(this.panelPart.getContainer(), oldPositionValue);
		addClass(this.panelPart.getContainer(), newPositionValue);
2103

2104 2105 2106 2107
		// Update Styles
		this.panelPart.updateStyles();

		// Layout
S
SteVen Batten 已提交
2108 2109 2110
		if (this.workbenchGrid instanceof Grid) {
			if (!wasHidden) {
				this.saveLastPanelDimension();
2111
			}
2112

2113
			this.workbenchGrid.removeView(this.panelPartView);
S
SteVen Batten 已提交
2114
			this.layout();
2115 2116 2117 2118
		} else {
			this.workbenchGrid.layout();
		}
	}
2119 2120

	//#endregion
J
Johannes Rieken 已提交
2121
}