workbench.ts 84.2 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, removeClasses } 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 140
import { IProductService } from 'vs/platform/product/common/product';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
import { ITextMateService } from 'vs/workbench/services/textMate/common/textMateService';
141 142

// import@node
143 144 145 146
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';
147
import { getDelayedChannel } from 'vs/base/parts/ipc/node/ipc';
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
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';
166 167
import { AccessibilityService } from 'vs/platform/accessibility/node/accessibilityService';
import { ProductService } from 'vs/platform/product/node/productService';
168 169 170 171 172 173 174 175

// 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';
176
import { DialogService, FileDialogService } from 'vs/workbench/services/dialogs/electron-browser/dialogService';
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 { 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 456 457 458
		const platformClass = isWindows ? 'windows' : isLinux ? 'linux' : 'mac';

		addClasses(this.workbench, 'monaco-workbench', platformClass);
		addClasses(document.body, platformClass); // used by our fonts
459
	}
E
Erich Gamma 已提交
460

B
Benjamin Pasero 已提交
461
	private initServices(serviceCollection: ServiceCollection): void {
462

463
		// Parts
464
		serviceCollection.set(IPartService, this);
E
Erich Gamma 已提交
465

466 467 468
		// Labels
		serviceCollection.set(ILabelService, new SyncDescriptor(LabelService, undefined, true));

469
		// Clipboard
J
Johannes Rieken 已提交
470
		serviceCollection.set(IClipboardService, new SyncDescriptor(ClipboardService));
471

472 473 474 475 476 477 478 479 480 481 482
		// 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);

483 484 485 486
		// Product
		const productService = new ProductService();
		serviceCollection.set(IProductService, productService);

487 488 489 490 491 492 493 494 495 496
		// 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
497
		if (!this.environmentService.isExtensionDevelopment && !this.environmentService.args['disable-telemetry'] && !!productService.enableTelemetry) {
498 499 500
			const channel = getDelayedChannel(sharedProcess.then(c => c.getChannel('telemetryAppender')));
			const config: ITelemetryServiceConfig = {
				appender: combinedAppender(new TelemetryAppenderClient(channel), new LogAppender(this.logService)),
501
				commonProperties: resolveWorkbenchCommonProperties(this.storageService, productService.commit, productService.version, this.configuration.machineId, this.environmentService.installSourcePath),
502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522
				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 已提交
523 524 525 526 527
		this._register(this.lifecycleService.onWillShutdown(event => this._onWillShutdown.fire(event)));
		this._register(this.lifecycleService.onShutdown(() => {
			this._onShutdown.fire();
			this.dispose();
		}));
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 613 614 615 616 617 618 619

		// 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));

620 621 622 623
		// Status bar
		this.statusbarPart = this.instantiationService.createInstance(StatusbarPart, Identifiers.STATUSBAR_PART);
		serviceCollection.set(IStatusbarService, this.statusbarPart);

624 625 626
		// Progress 2
		serviceCollection.set(IProgressService2, new SyncDescriptor(ProgressService2));

627
		// Keybindings
A
Alex Dima 已提交
628
		this.contextKeyService = this.instantiationService.createInstance(ContextKeyService);
629
		serviceCollection.set(IContextKeyService, this.contextKeyService);
630

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

634 635 636
		// List
		serviceCollection.set(IListService, this.instantiationService.createInstance(ListService));

J
Joao Moreno 已提交
637
		// Context view service
B
Benjamin Pasero 已提交
638
		this.contextViewService = this.instantiationService.createInstance(ContextViewService, this.workbench);
J
Joao Moreno 已提交
639 640
		serviceCollection.set(IContextViewService, this.contextViewService);

S
SteVen Batten 已提交
641
		// Use themable context menus when custom titlebar is enabled to match custom menubar
B
Benjamin Pasero 已提交
642
		if (!isMacintosh && this.useCustomTitleBarStyle()) {
J
fix npe  
Johannes Rieken 已提交
643
			serviceCollection.set(IContextMenuService, new SyncDescriptor(HTMLContextMenuService, [null]));
S
SteVen Batten 已提交
644 645 646
		} else {
			serviceCollection.set(IContextMenuService, new SyncDescriptor(NativeContextMenuService));
		}
647

648 649
		// Menus/Actions
		serviceCollection.set(IMenuService, new SyncDescriptor(MenuService));
650

P
Pine Wu 已提交
651
		// Sidebar part
652
		this.sidebarPart = this.instantiationService.createInstance(SidebarPart, Identifiers.SIDEBAR_PART);
P
Pine Wu 已提交
653 654

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

I
isidor 已提交
657
		// Panel service (panel part)
658 659
		this.panelPart = this.instantiationService.createInstance(PanelPart, Identifiers.PANEL_PART);
		serviceCollection.set(IPanelService, this.panelPart);
I
isidor 已提交
660

661 662 663
		// views service
		const viewsService = this.instantiationService.createInstance(ViewsService);
		serviceCollection.set(IViewsService, viewsService);
S
Sandeep Somavarapu 已提交
664

E
Erich Gamma 已提交
665
		// Activity service (activitybar part)
666
		this.activitybarPart = this.instantiationService.createInstance(ActivitybarPart, Identifiers.ACTIVITYBAR_PART);
I
isidor 已提交
667 668
		const activityService = this.instantiationService.createInstance(ActivityService, this.activitybarPart, this.panelPart);
		serviceCollection.set(IActivityService, activityService);
E
Erich Gamma 已提交
669

670 671 672
		// File Service
		this.fileService = this.instantiationService.createInstance(RemoteFileService);
		serviceCollection.set(IFileService, this.fileService);
S
#47154  
Sandeep Somavarapu 已提交
673
		this.configurationService.acquireFileService(this.fileService);
A
Alex Dima 已提交
674
		this.themeService.acquireFileService(this.fileService);
675

676 677
		// Editor and Group services
		const restorePreviousEditorState = !this.hasInitialFilesToOpen;
678
		this.editorPart = this.instantiationService.createInstance(EditorPart, Identifiers.EDITOR_PART, restorePreviousEditorState);
B
Benjamin Pasero 已提交
679
		this.editorGroupService = this.editorPart;
680 681 682
		serviceCollection.set(IEditorGroupsService, this.editorPart);
		this.editorService = this.instantiationService.createInstance(EditorService);
		serviceCollection.set(IEditorService, this.editorService);
E
Erich Gamma 已提交
683

684 685 686
		// Accessibility
		serviceCollection.set(IAccessibilityService, new SyncDescriptor(AccessibilityService, undefined, true));

687 688 689
		// Title bar
		this.titlebarPart = this.instantiationService.createInstance(TitlebarPart, Identifiers.TITLEBAR_PART);
		serviceCollection.set(ITitleService, this.titlebarPart);
B
Benjamin Pasero 已提交
690

691
		// History
692
		serviceCollection.set(IHistoryService, new SyncDescriptor(HistoryService));
693

M
Martin Aeschlimann 已提交
694
		// File Dialogs
695
		serviceCollection.set(IFileDialogService, new SyncDescriptor(FileDialogService));
M
Martin Aeschlimann 已提交
696

697
		// Backup File Service
B
Benjamin Pasero 已提交
698 699
		if (this.configuration.backupPath) {
			this.backupFileService = this.instantiationService.createInstance(BackupFileService, this.configuration.backupPath);
B
Benjamin Pasero 已提交
700 701 702
		} else {
			this.backupFileService = new InMemoryBackupFileService();
		}
703
		serviceCollection.set(IBackupFileService, this.backupFileService);
704

705
		// Text File Service
706
		serviceCollection.set(ITextFileService, new SyncDescriptor(TextFileService));
707

708
		// File Decorations
J
Johannes Rieken 已提交
709
		serviceCollection.set(IDecorationsService, new SyncDescriptor(FileDecorationsService));
710

J
Joao Moreno 已提交
711
		// Inactive extension URL handler
J
Joao Moreno 已提交
712
		serviceCollection.set(IExtensionUrlHandler, new SyncDescriptor(ExtensionUrlHandler));
J
Joao Moreno 已提交
713

B
Benjamin Pasero 已提交
714
		// Text Model Resolver Service
715
		serviceCollection.set(ITextModelService, new SyncDescriptor(TextModelResolverService));
B
Benjamin Pasero 已提交
716

717 718 719 720
		// JSON Editing
		const jsonEditingService = this.instantiationService.createInstance(JSONEditingService);
		serviceCollection.set(IJSONEditingService, jsonEditingService);

721 722 723
		// Workspace Editing
		serviceCollection.set(IWorkspaceEditingService, new SyncDescriptor(WorkspaceEditingService));

724 725 726
		// Keybinding Editing
		serviceCollection.set(IKeybindingEditingService, this.instantiationService.createInstance(KeybindingsEditingService));

727
		// Configuration Resolver
728
		serviceCollection.set(IConfigurationResolverService, new SyncDescriptor(ConfigurationResolverService, [process.env]));
729

E
Erich Gamma 已提交
730
		// Quick open service (quick open controller)
731 732
		this.quickOpen = this.instantiationService.createInstance(QuickOpenController);
		serviceCollection.set(IQuickOpenService, this.quickOpen);
733

C
Christof Marti 已提交
734 735 736 737
		// Quick input service
		this.quickInput = this.instantiationService.createInstance(QuickInputService);
		serviceCollection.set(IQuickInputService, this.quickInput);

S
Sandeep Somavarapu 已提交
738 739 740
		// PreferencesService
		serviceCollection.set(IPreferencesService, this.instantiationService.createInstance(PreferencesService));

B
polish  
Benjamin Pasero 已提交
741
		// Contributed services
B
Benjamin Pasero 已提交
742
		const contributedServices = getServices();
E
Erich Gamma 已提交
743
		for (let contributedService of contributedServices) {
744
			serviceCollection.set(contributedService.id, contributedService.descriptor);
E
Erich Gamma 已提交
745 746 747
		}

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

752
		this.instantiationService.createInstance(DefaultConfigurationExportHelper);
753

B
Benjamin Pasero 已提交
754
		this.configurationService.acquireInstantiationService(this.instantiationService);
E
Erich Gamma 已提交
755 756
	}

757
	//#region event handling
E
Erich Gamma 已提交
758

759
	private registerListeners(): void {
I
isidor 已提交
760

761
		// Storage
762
		this._register(this.storageService.onWillSaveState(e => this.saveState(e)));
763

764
		// Listen to visible editor changes
765
		this._register(this.editorService.onDidVisibleEditorsChange(() => this.onDidVisibleEditorsChange()));
B
Benjamin Pasero 已提交
766

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

770
		// Listen to editor closing (if we run with --wait)
B
Benjamin Pasero 已提交
771
		const filesToWait = this.configuration.filesToWait;
772
		if (filesToWait) {
773
			const resourcesToWaitFor = filesToWait.paths.map(p => p.fileUri);
774
			const waitMarkerFile = URI.file(filesToWait.waitMarkerFilePath);
775
			const listenerDispose = this.editorService.onDidCloseEditor(() => this.onEditorClosed(listenerDispose, resourcesToWaitFor, waitMarkerFile));
I
isidor 已提交
776

777
			this._register(listenerDispose);
778
		}
S
Sanders Lauture 已提交
779

780
		// Configuration changes
781
		this._register(this.configurationService.onDidChangeConfiguration(() => this.onDidUpdateConfiguration()));
I
isidor 已提交
782

783
		// Fullscreen changes
784
		this._register(onDidChangeFullscreen(() => this.onFullscreenChanged()));
B
Benjamin Pasero 已提交
785 786 787 788

		// Group changes
		this._register(this.editorGroupService.onDidAddGroup(() => this.centerEditorLayout(this.shouldCenterLayout)));
		this._register(this.editorGroupService.onDidRemoveGroup(() => this.centerEditorLayout(this.shouldCenterLayout)));
789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814

		// 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();
		}
815
	}
816

817
	private onFullscreenChanged(): void {
S
SrTobi 已提交
818

819
		// Apply as CSS class
820 821
		if (isFullscreen()) {
			addClass(this.workbench, 'fullscreen');
822
		} else {
823
			removeClass(this.workbench, 'fullscreen');
B
Benjamin Pasero 已提交
824

825 826 827 828
			if (this.zenMode.transitionedToFullScreen && this.zenMode.active) {
				this.toggleZenMode();
			}
		}
E
Erich Gamma 已提交
829

830
		// Changing fullscreen state of the window has an impact on custom title bar visibility, so we need to update
B
Benjamin Pasero 已提交
831
		if (this.useCustomTitleBarStyle()) {
832 833 834
			this._onTitleBarVisibilityChange.fire();
			this.layout(); // handle title bar when fullscreen changes
		}
835 836
	}

837 838 839 840
	private onMenubarToggled(visible: boolean) {
		if (visible !== this.menubarToggled) {
			this.menubarToggled = visible;

841
			if (isFullscreen() && (this.menubarVisibility === 'toggle' || this.menubarVisibility === 'default')) {
842
				this._onTitleBarVisibilityChange.fire();
843 844 845 846 847
				this.layout();
			}
		}
	}

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

850 851 852
		// 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.
853
		if (resourcesToWaitFor.every(resource => !this.editorService.isOpen({ resource }))) {
854
			listenerDispose.dispose();
855
			this.fileService.del(waitMarkerFile);
856
		}
E
Erich Gamma 已提交
857 858
	}

859
	private onDidVisibleEditorsChange(): void {
860
		const visibleEditors = this.editorService.visibleControls;
E
Erich Gamma 已提交
861

862 863 864 865 866 867 868 869 870
		// 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();
			}
		}
871 872 873 874

		if (this.editorHidden) {
			this.setEditorHidden(false);
		}
875 876
	}

877
	private onAllEditorsClosed(): void {
878
		const visibleEditors = this.editorService.visibleControls.length;
879 880
		if (visibleEditors === 0) {
			this.windowService.closeWindow();
E
Erich Gamma 已提交
881 882 883
		}
	}

884 885 886 887 888
	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);
889
		}
E
Erich Gamma 已提交
890

891
		this.setPanelPositionFromStorageOrConfig();
E
Erich Gamma 已提交
892

893 894 895
		const fontAliasing = this.configurationService.getValue<FontAliasingOption>(Workbench.fontAliasingConfigurationKey);
		if (fontAliasing !== this.fontAliasing) {
			this.setFontAliasing(fontAliasing);
896 897
		}

898 899 900 901 902
		if (!this.zenMode.active) {
			const newStatusbarHiddenValue = !this.configurationService.getValue<boolean>(Workbench.statusbarVisibleConfigurationKey);
			if (newStatusbarHiddenValue !== this.statusBarHidden) {
				this.setStatusBarHidden(newStatusbarHiddenValue, skipLayout);
			}
903

904 905 906 907
			const newActivityBarHiddenValue = !this.configurationService.getValue<boolean>(Workbench.activityBarVisibleConfigurationKey);
			if (newActivityBarHiddenValue !== this.activityBarHidden) {
				this.setActivityBarHidden(newActivityBarHiddenValue, skipLayout);
			}
B
Benjamin Pasero 已提交
908
		}
S
SteVen Batten 已提交
909

910
		const newMenubarVisibility = this.configurationService.getValue<MenuBarVisibility>(Workbench.menubarVisibilityConfigurationKey);
911
		this.setMenubarVisibility(newMenubarVisibility, !!skipLayout);
912
	}
B
Benjamin Pasero 已提交
913

914
	//#endregion
B
Benjamin Pasero 已提交
915

916
	private handleContextKeys(): void {
I
isidor 已提交
917 918 919
		IsMacContext.bindTo(this.contextKeyService);
		IsLinuxContext.bindTo(this.contextKeyService);
		IsWindowsContext.bindTo(this.contextKeyService);
920 921 922 923 924 925

		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);

926
		SupportsWorkspacesContext.bindTo(this.contextKeyService);
927 928 929
		SupportsOpenFileFolderContext.bindTo(this.contextKeyService).set(!!this.windowService.getConfiguration().remoteAuthority);

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

931 932
		const sidebarVisibleContextRaw = new RawContextKey<boolean>('sidebarVisible', false);
		this.sideBarVisibleContext = sidebarVisibleContextRaw.bindTo(this.contextKeyService);
933

934
		const activeEditorContext = ActiveEditorContext.bindTo(this.contextKeyService);
935 936
		const editorsVisibleContext = EditorsVisibleContext.bindTo(this.contextKeyService);
		const textCompareEditorVisible = TextCompareEditorVisibleContext.bindTo(this.contextKeyService);
937
		const textCompareEditorActive = TextCompareEditorActiveContext.bindTo(this.contextKeyService);
938 939
		const activeEditorGroupEmpty = ActiveEditorGroupEmptyContext.bindTo(this.contextKeyService);
		const multipleEditorGroups = MultipleEditorGroupsContext.bindTo(this.contextKeyService);
940

941
		const updateEditorContextKeys = () => {
942
			const activeControl = this.editorService.activeControl;
943
			const visibleEditors = this.editorService.visibleControls;
E
Erich Gamma 已提交
944

945
			textCompareEditorActive.set(!!activeControl && activeControl.getId() === TEXT_DIFF_EDITOR_ID);
946
			textCompareEditorVisible.set(visibleEditors.some(control => control.getId() === TEXT_DIFF_EDITOR_ID));
I
isidor 已提交
947

948 949 950 951
			if (visibleEditors.length > 0) {
				editorsVisibleContext.set(true);
			} else {
				editorsVisibleContext.reset();
952
			}
B
Benjamin Pasero 已提交
953

954
			if (!this.editorService.activeEditor) {
955 956 957
				activeEditorGroupEmpty.set(true);
			} else {
				activeEditorGroupEmpty.reset();
958
			}
959

B
Benjamin Pasero 已提交
960
			if (this.editorGroupService.count > 1) {
961 962 963 964
				multipleEditorGroups.set(true);
			} else {
				multipleEditorGroups.reset();
			}
965 966 967 968 969 970

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

973
		this.editorPart.whenRestored.then(() => updateEditorContextKeys());
974 975
		this._register(this.editorService.onDidActiveEditorChange(() => updateEditorContextKeys()));
		this._register(this.editorService.onDidVisibleEditorsChange(() => updateEditorContextKeys()));
B
Benjamin Pasero 已提交
976 977
		this._register(this.editorGroupService.onDidAddGroup(() => updateEditorContextKeys()));
		this._register(this.editorGroupService.onDidRemoveGroup(() => updateEditorContextKeys()));
978

979
		const inputFocused = InputFocusedContext.bindTo(this.contextKeyService);
B
Benjamin Pasero 已提交
980 981

		function activeElementIsInput(): boolean {
982
			return !!document.activeElement && (document.activeElement.tagName === 'INPUT' || document.activeElement.tagName === 'TEXTAREA');
B
Benjamin Pasero 已提交
983 984 985 986 987 988 989
		}

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

			if (isInputFocused) {
990
				const tracker = trackFocus(document.activeElement as HTMLElement);
J
Joao Moreno 已提交
991
				Event.once(tracker.onDidBlur)(() => {
B
Benjamin Pasero 已提交
992 993 994 995 996 997 998
					inputFocused.set(activeElementIsInput());

					tracker.dispose();
				});
			}
		}

999
		this._register(addDisposableListener(window, 'focusin', () => trackInputFocus(), true));
1000 1001 1002 1003 1004 1005

		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 已提交
1006

1007 1008 1009 1010 1011
		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);
		}));
1012

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

1015 1016 1017 1018
		const updateSplitEditorsVerticallyContext = () => {
			const direction = preferredSideBySideGroupDirection(this.configurationService);
			splitEditorsVerticallyContext.set(direction === GroupDirection.DOWN);
		};
S
Sanders Lauture 已提交
1019

1020 1021 1022 1023 1024
		this._register(this.configurationService.onDidChangeConfiguration(e => {
			if (e.affectsConfiguration('workbench.editor.openSideBySideDirection')) {
				updateSplitEditorsVerticallyContext();
			}
		}));
E
Erich Gamma 已提交
1025

1026
		updateSplitEditorsVerticallyContext();
1027
	}
E
Erich Gamma 已提交
1028

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

1032
		// Restore Editorpart
1033
		mark('willRestoreEditors');
1034
		restorePromises.push(this.editorPart.whenRestored.then(() => {
B
Benjamin Pasero 已提交
1035 1036 1037 1038

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

J
Johannes Rieken 已提交
1041
				return Promise.resolve(undefined);
B
Benjamin Pasero 已提交
1042 1043 1044 1045 1046 1047 1048 1049 1050
			}

			const editorsToOpen = this.resolveEditorsToOpen();

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

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

1053
		// Restore Sidebar
1054
		let viewletIdToRestore: string | undefined;
1055 1056
		if (!this.sideBarHidden) {
			this.sideBarVisibleContext.set(true);
1057

1058
			if (this.shouldRestoreLastOpenedViewlet()) {
1059
				viewletIdToRestore = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE);
1060
			}
1061

1062
			if (!viewletIdToRestore) {
I
isidor 已提交
1063
				viewletIdToRestore = this.sidebarPart.getDefaultViewletId();
1064
			}
E
Erich Gamma 已提交
1065

1066
			mark('willRestoreViewlet');
I
isidor 已提交
1067 1068
			restorePromises.push(this.sidebarPart.openViewlet(viewletIdToRestore)
				.then(viewlet => viewlet || this.sidebarPart.openViewlet(this.sidebarPart.getDefaultViewletId()))
1069
				.then(() => mark('didRestoreViewlet')));
1070 1071
		}

1072 1073
		// Restore Panel
		const panelRegistry = Registry.as<PanelRegistry>(PanelExtensions.Panels);
1074
		const panelId = this.storageService.get(PanelPart.activePanelSettingsKey, StorageScope.WORKSPACE, panelRegistry.getDefaultPanelId());
1075
		if (!this.panelHidden && !!panelId) {
1076
			mark('willRestorePanel');
1077
			const isPanelToRestoreEnabled = !!this.panelPart.getPanels().filter(p => p.id === panelId).length;
1078
			const panelIdToRestore = isPanelToRestoreEnabled ? panelId : panelRegistry.getDefaultPanelId();
1079
			this.panelPart.openPanel(panelIdToRestore, false);
1080
			mark('didRestorePanel');
I
isidor 已提交
1081 1082
		}

1083 1084 1085
		// 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);
1086
		if (wasZenActive && zenConfig.restore) {
I
isidor 已提交
1087
			this.toggleZenMode(true, true);
I
isidor 已提交
1088 1089
		}

B
Benjamin Pasero 已提交
1090
		// Restore Forced Editor Center Mode
1091
		if (this.storageService.getBoolean(Workbench.centeredEditorLayoutActiveStorageKey, StorageScope.WORKSPACE, false)) {
I
isidor 已提交
1092
			this.centerEditorLayout(true);
S
SrTobi 已提交
1093
		}
1094

1095
		const onRestored = (error?: Error): void => {
B
Benjamin Pasero 已提交
1096 1097 1098 1099 1100
			this.workbenchRestored = true;

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

1101 1102 1103 1104 1105 1106 1107
			// 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);
1108

1109
			if (error) {
1110
				onUnexpectedError(error);
1111
			}
I
isidor 已提交
1112

1113
			this.logStartupTelemetry({
1114
				customKeybindingsCount: this.keybindingService.customKeybindingsCount(),
P
Pine Wu 已提交
1115
				pinnedViewlets: this.activitybarPart.getPinnedViewletIds(),
1116
				restoredViewlet: viewletIdToRestore,
1117
				restoredEditorsCount: this.editorService.visibleEditors.length
1118
			});
1119
		};
1120

B
Benjamin Pasero 已提交
1121
		return Promise.all(restorePromises).then(() => onRestored(), error => onRestored(error));
E
Erich Gamma 已提交
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 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167
	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');
	}

1168 1169 1170
	private shouldRestoreLastOpenedViewlet(): boolean {
		if (!this.environmentService.isBuilt) {
			return true; // always restore sidebar when we are in development mode
E
Erich Gamma 已提交
1171 1172
		}

1173 1174
		// always restore sidebar when the window was reloaded
		return this.lifecycleService.startupKind === StartupKind.ReloadedWindow;
E
Erich Gamma 已提交
1175 1176
	}

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

B
Benjamin Pasero 已提交
1179
		// Files to open, diff or create
1180
		if (this.hasInitialFilesToOpen) {
I
isidor 已提交
1181

B
Benjamin Pasero 已提交
1182
			// Files to diff is exclusive
B
Benjamin Pasero 已提交
1183
			const filesToDiff = this.toInputs(this.configuration.filesToDiff, false);
1184
			if (filesToDiff && filesToDiff.length === 2) {
B
Benjamin Pasero 已提交
1185
				return [<IResourceDiffInput>{
1186 1187
					leftResource: filesToDiff[0].resource,
					rightResource: filesToDiff[1].resource,
B
Benjamin Pasero 已提交
1188
					options: { pinned: true },
B
Benjamin Pasero 已提交
1189
					forceFile: true
B
Benjamin Pasero 已提交
1190
				}];
B
Benjamin Pasero 已提交
1191
			}
I
isidor 已提交
1192

B
Benjamin Pasero 已提交
1193 1194
			const filesToCreate = this.toInputs(this.configuration.filesToCreate, true);
			const filesToOpen = this.toInputs(this.configuration.filesToOpen, false);
I
isidor 已提交
1195

1196
			// Otherwise: Open/Create files
B
Benjamin Pasero 已提交
1197
			return [...filesToOpen, ...filesToCreate];
B
Benjamin Pasero 已提交
1198
		}
I
isidor 已提交
1199

1200
		// Empty workbench
1201
		else if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY && this.openUntitledFile()) {
B
Benjamin Pasero 已提交
1202
			const isEmpty = this.editorGroupService.count === 1 && this.editorGroupService.activeGroup.count === 0;
1203
			if (!isEmpty) {
B
Benjamin Pasero 已提交
1204
				return []; // do not open any empty untitled file if we restored editors from previous session
1205
			}
B
Benjamin Pasero 已提交
1206

1207 1208
			return this.backupFileService.hasBackups().then(hasBackups => {
				if (hasBackups) {
B
Benjamin Pasero 已提交
1209
					return []; // do not open any empty untitled file if we have backups to restore
1210
				}
B
Benjamin Pasero 已提交
1211

B
Benjamin Pasero 已提交
1212
				return [<IUntitledResourceInput>{}];
1213
			});
1214
		}
1215

B
Benjamin Pasero 已提交
1216
		return [];
B
Benjamin Pasero 已提交
1217
	}
1218

1219
	private toInputs(paths: IPath[], isNew: boolean): Array<IResourceInput | IUntitledResourceInput> {
B
Benjamin Pasero 已提交
1220 1221
		if (!paths || !paths.length) {
			return [];
1222
		}
I
isidor 已提交
1223

B
Benjamin Pasero 已提交
1224
		return paths.map(p => {
1225
			const resource = p.fileUri;
1226 1227 1228 1229
			let input: IResourceInput | IUntitledResourceInput;
			if (isNew) {
				input = { filePath: resource.fsPath, options: { pinned: true } } as IUntitledResourceInput;
			} else {
B
Benjamin Pasero 已提交
1230
				input = { resource, options: { pinned: true }, forceFile: true } as IResourceInput;
1231
			}
E
Erich Gamma 已提交
1232

1233
			if (!isNew && p.lineNumber) {
B
Benjamin Pasero 已提交
1234 1235 1236 1237 1238
				input.options.selection = {
					startLineNumber: p.lineNumber,
					startColumn: p.columnNumber
				};
			}
1239

B
Benjamin Pasero 已提交
1240 1241
			return input;
		});
1242 1243
	}

1244
	private openUntitledFile() {
1245
		const startupEditor = this.configurationService.inspect('workbench.startupEditor');
B
Benjamin Pasero 已提交
1246 1247

		// Fallback to previous workbench.welcome.enabled setting in case startupEditor is not defined
1248
		if (!startupEditor.user && !startupEditor.workspace) {
1249 1250 1251
			const welcomeEnabledValue = this.configurationService.getValue('workbench.welcome.enabled');
			if (typeof welcomeEnabledValue === 'boolean') {
				return !welcomeEnabledValue;
1252
			}
1253
		}
E
Erich Gamma 已提交
1254

1255
		return startupEditor.value === 'newUntitledFile';
1256
	}
E
Erich Gamma 已提交
1257 1258

	private initSettings(): void {
1259

S
SteVen Batten 已提交
1260 1261 1262
		// Editor visiblity
		this.editorHidden = false;

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

I
isidor 已提交
1266
		// Panel part visibility
1267
		const panelRegistry = Registry.as<PanelRegistry>(PanelExtensions.Panels);
1268
		this.panelHidden = this.storageService.getBoolean(Workbench.panelHiddenStorageKey, StorageScope.WORKSPACE, true);
1269 1270
		if (!panelRegistry.getDefaultPanelId()) {
			this.panelHidden = true; // we hide panel part if there is no default panel
1271 1272
		}

E
Erich Gamma 已提交
1273
		// Sidebar position
1274
		const sideBarPosition = this.configurationService.getValue<string>(Workbench.sidebarPositionConfigurationKey);
1275
		this.sideBarPosition = (sideBarPosition === 'right') ? Position.RIGHT : Position.LEFT;
1276

I
isidor 已提交
1277
		// Panel position
1278
		this.setPanelPositionFromStorageOrConfig();
1279

1280
		// Menubar visibility
1281
		const menuBarVisibility = this.configurationService.getValue<MenuBarVisibility>(Workbench.menubarVisibilityConfigurationKey);
S
SteVen Batten 已提交
1282
		this.setMenubarVisibility(menuBarVisibility, true);
1283

B
Benjamin Pasero 已提交
1284
		// Statusbar visibility
1285
		const statusBarVisible = this.configurationService.getValue<string>(Workbench.statusbarVisibleConfigurationKey);
1286
		this.statusBarHidden = !statusBarVisible;
1287

S
Sanders Lauture 已提交
1288
		// Activity bar visibility
1289
		const activityBarVisible = this.configurationService.getValue<string>(Workbench.activityBarVisibleConfigurationKey);
S
Sanders Lauture 已提交
1290
		this.activityBarHidden = !activityBarVisible;
1291

1292
		// Font aliasing
1293
		this.fontAliasing = this.configurationService.getValue<FontAliasingOption>(Workbench.fontAliasingConfigurationKey);
1294

I
isidor 已提交
1295 1296
		// Zen mode
		this.zenMode = {
I
isidor 已提交
1297
			active: false,
1298
			transitionedToFullScreen: false,
1299
			transitionedToCenteredEditorLayout: false,
1300
			wasSideBarVisible: false,
1301 1302
			wasPanelVisible: false,
			transitionDisposeables: []
I
isidor 已提交
1303
		};
E
Erich Gamma 已提交
1304 1305
	}

1306 1307
	private setPanelPositionFromStorageOrConfig() {
		const defaultPanelPosition = this.configurationService.getValue<string>(Workbench.defaultPanelPositionStorageKey);
1308
		const panelPosition = this.storageService.get(Workbench.panelPositionStorageKey, StorageScope.WORKSPACE, defaultPanelPosition);
1309

1310 1311
		this.panelPosition = (panelPosition === 'right') ? Position.RIGHT : Position.BOTTOM;
	}
1312

B
Benjamin Pasero 已提交
1313 1314
	private useCustomTitleBarStyle(): boolean {
		return getTitleBarStyle(this.configurationService, this.environmentService) === 'custom';
B
Benjamin Pasero 已提交
1315 1316
	}

1317
	private saveLastPanelDimension(): void {
S
SteVen Batten 已提交
1318
		if (!(this.workbenchGrid instanceof Grid)) {
1319 1320 1321 1322
			return;
		}

		if (this.panelPosition === Position.BOTTOM) {
S
SteVen Batten 已提交
1323
			this.uiState.lastPanelHeight = this.workbenchGrid.getViewSize(this.panelPartView);
1324
		} else {
S
SteVen Batten 已提交
1325
			this.uiState.lastPanelWidth = this.workbenchGrid.getViewSize(this.panelPartView);
1326 1327 1328 1329 1330 1331 1332
		}
	}

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

1333 1334
	private setStatusBarHidden(hidden: boolean, skipLayout?: boolean): void {
		this.statusBarHidden = hidden;
B
Benjamin Pasero 已提交
1335

1336 1337
		// Adjust CSS
		if (hidden) {
1338
			addClass(this.workbench, 'nostatusbar');
E
Erich Gamma 已提交
1339
		} else {
1340
			removeClass(this.workbench, 'nostatusbar');
E
Erich Gamma 已提交
1341 1342
		}

1343 1344
		// Layout
		if (!skipLayout) {
S
SteVen Batten 已提交
1345
			if (this.workbenchGrid instanceof Grid) {
S
SteVen Batten 已提交
1346
				this.layout();
1347 1348 1349
			} else {
				this.workbenchGrid.layout();
			}
1350 1351 1352
		}
	}

1353
	private setFontAliasing(aliasing: FontAliasingOption) {
1354
		this.fontAliasing = aliasing;
S
Sanders Lauture 已提交
1355

B
Benjamin Pasero 已提交
1356
		// Remove all
1357
		removeClasses(this.workbench, ...fontAliasingValues.map(value => `monaco-font-aliasing-${value}`));
B
Benjamin Pasero 已提交
1358 1359 1360

		// Add specific
		if (fontAliasingValues.some(option => option === aliasing)) {
1361
			addClass(this.workbench, `monaco-font-aliasing-${aliasing}`);
S
Sanders Lauture 已提交
1362
		}
1363 1364
	}

E
Erich Gamma 已提交
1365
	private createWorkbenchLayout(): void {
1366
		if (this.configurationService.getValue('workbench.useExperimentalGridLayout')) {
1367

S
SteVen Batten 已提交
1368 1369 1370 1371 1372 1373 1374 1375 1376
			// 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 });
1377

1378
			this.workbench.prepend(this.workbenchGrid.element);
1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397
		} 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 已提交
1398 1399 1400 1401 1402 1403
	}

	private renderWorkbench(): void {

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

1407
		if (this.panelHidden) {
1408
			addClass(this.workbench, 'nopanel');
1409
		}
B
Benjamin Pasero 已提交
1410

1411
		if (this.statusBarHidden) {
1412
			addClass(this.workbench, 'nostatusbar');
1413
		}
E
Erich Gamma 已提交
1414

B
Benjamin Pasero 已提交
1415
		// Apply font aliasing
1416 1417
		this.setFontAliasing(this.fontAliasing);

1418
		// Apply fullscreen state
1419 1420
		if (isFullscreen()) {
			addClass(this.workbench, 'fullscreen');
B
Benjamin Pasero 已提交
1421 1422
		}

E
Erich Gamma 已提交
1423
		// Create Parts
B
Benjamin Pasero 已提交
1424
		this.createTitlebarPart();
E
Erich Gamma 已提交
1425 1426 1427
		this.createActivityBarPart();
		this.createSidebarPart();
		this.createEditorPart();
1428
		this.createPanelPart();
E
Erich Gamma 已提交
1429 1430
		this.createStatusbarPart();

1431 1432
		// Notification Handlers
		this.createNotificationsHandlers();
1433

1434 1435

		// Menubar visibility changes
B
Benjamin Pasero 已提交
1436
		if ((isWindows || isLinux) && this.useCustomTitleBarStyle()) {
1437 1438 1439
			this.titlebarPart.onMenubarVisibilityChange()(e => this.onMenubarToggled(e));
		}

E
Erich Gamma 已提交
1440
		// Add Workbench to DOM
B
Benjamin Pasero 已提交
1441
		this.container.appendChild(this.workbench);
E
Erich Gamma 已提交
1442 1443
	}

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

B
Benjamin Pasero 已提交
1447
		this.titlebarPart.create(titlebarContainer);
B
Benjamin Pasero 已提交
1448 1449
	}

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

B
Benjamin Pasero 已提交
1453
		this.activitybarPart.create(activitybarPartContainer);
E
Erich Gamma 已提交
1454 1455 1456
	}

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

B
Benjamin Pasero 已提交
1459
		this.sidebarPart.create(sidebarPartContainer);
E
Erich Gamma 已提交
1460 1461
	}

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

B
Benjamin Pasero 已提交
1465
		this.panelPart.create(panelPartContainer);
I
isidor 已提交
1466 1467
	}

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

B
Benjamin Pasero 已提交
1471
		this.editorPart.create(editorContainer);
E
Erich Gamma 已提交
1472 1473 1474
	}

	private createStatusbarPart(): void {
B
Benjamin Pasero 已提交
1475 1476 1477 1478 1479 1480 1481
		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');
1482
		classes.forEach(clazz => addClass(part, clazz));
B
Benjamin Pasero 已提交
1483 1484 1485
		part.id = id;
		part.setAttribute('role', role);

1486 1487 1488 1489 1490
		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 已提交
1491

B
Benjamin Pasero 已提交
1492
		return part;
E
Erich Gamma 已提交
1493 1494
	}

1495 1496
	private createNotificationsHandlers(): void {

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

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

1503
		// Notifications Alerts
1504
		this._register(this.instantiationService.createInstance(NotificationsAlerts, this.notificationService.model));
1505 1506 1507 1508

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

1509
		// Eventing
1510
		this._register(this.notificationsCenter.onDidChangeVisibility(() => {
1511 1512 1513 1514 1515 1516 1517 1518

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

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

1519
		// Register Commands
1520
		registerNotificationCommands(this.notificationsCenter, this.notificationsToasts);
1521 1522
	}

1523
	private saveState(e: IWillSaveStateEvent): void {
1524
		if (this.zenMode.active) {
B
Benjamin Pasero 已提交
1525
			this.storageService.store(Workbench.zenModeActiveStorageKey, true, StorageScope.WORKSPACE);
1526
		} else {
B
Benjamin Pasero 已提交
1527
			this.storageService.remove(Workbench.zenModeActiveStorageKey, StorageScope.WORKSPACE);
1528
		}
1529 1530 1531 1532 1533 1534 1535 1536

		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);
			}
		}
1537 1538
	}

1539
	dispose(): void {
1540
		super.dispose();
1541 1542 1543 1544 1545 1546

		this.workbenchShutdown = true;
	}

	//#region IPartService

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

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

B
Benjamin Pasero 已提交
1552 1553
	isRestored(): boolean {
		return !!(this.workbenchRestored && this.workbenchStarted);
1554
	}
1555

1556 1557 1558 1559 1560
	hasFocus(part: Parts): boolean {
		const activeElement = document.activeElement;
		if (!activeElement) {
			return false;
		}
1561

1562
		const container = this.getContainer(part);
1563
		return isAncestor(activeElement, container);
1564
	}
1565

1566
	getContainer(part: Parts): HTMLElement | null {
1567 1568
		switch (part) {
			case Parts.TITLEBAR_PART:
1569
				return this.titlebarPart.getContainer();
1570
			case Parts.ACTIVITYBAR_PART:
1571
				return this.activitybarPart.getContainer();
1572
			case Parts.SIDEBAR_PART:
1573
				return this.sidebarPart.getContainer();
1574
			case Parts.PANEL_PART:
1575
				return this.panelPart.getContainer();
1576
			case Parts.EDITOR_PART:
1577
				return this.editorPart.getContainer();
1578
			case Parts.STATUSBAR_PART:
1579
				return this.statusbarPart.getContainer();
1580
		}
1581

1582
		return null;
1583
	}
1584

1585 1586 1587
	isVisible(part: Parts): boolean {
		switch (part) {
			case Parts.TITLEBAR_PART:
B
Benjamin Pasero 已提交
1588
				if (!this.useCustomTitleBarStyle()) {
1589
					return false;
1590
				} else if (!isFullscreen()) {
1591 1592 1593 1594 1595 1596 1597 1598 1599 1600
					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;
1601 1602 1603 1604 1605 1606 1607 1608
			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;
1609 1610
			case Parts.EDITOR_PART:
				return this.workbenchGrid instanceof Grid ? !this.editorHidden : true;
E
Erich Gamma 已提交
1611
		}
1612

1613
		return true; // any other part cannot be hidden
E
Erich Gamma 已提交
1614 1615
	}

1616 1617 1618
	getTitleBarOffset(): number {
		let offset = 0;
		if (this.isVisible(Parts.TITLEBAR_PART)) {
S
SteVen Batten 已提交
1619
			if (this.workbenchGrid instanceof Grid) {
S
SteVen Batten 已提交
1620
				offset = this.titlebarPart.maximumHeight;
S
SteVen Batten 已提交
1621 1622 1623
			} else {
				offset = this.workbenchGrid.partLayoutInfo.titlebar.height;

B
Benjamin Pasero 已提交
1624 1625 1626
				if (isMacintosh || this.menubarVisibility === 'hidden') {
					offset /= getZoomFactor();
				}
1627
			}
E
Erich Gamma 已提交
1628
		}
1629 1630

		return offset;
E
Erich Gamma 已提交
1631
	}
1632

1633 1634
	getWorkbenchElement(): HTMLElement {
		return this.workbench;
1635
	}
1636

I
isidor 已提交
1637
	toggleZenMode(skipLayout?: boolean, restoring = false): void {
I
isidor 已提交
1638
		this.zenMode.active = !this.zenMode.active;
1639
		this.zenMode.transitionDisposeables = dispose(this.zenMode.transitionDisposeables);
1640

1641 1642
		// 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)
1643
		let toggleFullScreen = false;
I
isidor 已提交
1644 1645 1646 1647 1648 1649 1650 1651
		const setLineNumbers = (lineNumbers: any) => {
			this.editorService.visibleControls.forEach(editor => {
				const control = <IEditor>editor.getControl();
				if (control) {
					control.updateOptions({ lineNumbers });
				}
			});
		};
1652 1653

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

1657
			toggleFullScreen = !isFullscreen() && config.fullScreen;
I
isidor 已提交
1658
			this.zenMode.transitionedToFullScreen = restoring ? config.fullScreen : toggleFullScreen;
1659
			this.zenMode.transitionedToCenteredEditorLayout = !this.isEditorLayoutCentered() && config.centerLayout;
1660 1661
			this.zenMode.wasSideBarVisible = this.isVisible(Parts.SIDEBAR_PART);
			this.zenMode.wasPanelVisible = this.isVisible(Parts.PANEL_PART);
1662

1663 1664
			this.setPanelHidden(true, true);
			this.setSideBarHidden(true, true);
I
isidor 已提交
1665

1666 1667 1668
			if (config.hideActivityBar) {
				this.setActivityBarHidden(true, true);
			}
1669

I
isidor 已提交
1670
			if (config.hideStatusBar) {
I
isidor 已提交
1671 1672
				this.setStatusBarHidden(true, true);
			}
1673

I
isidor 已提交
1674 1675 1676 1677 1678
			if (config.hideLineNumbers) {
				setLineNumbers('off');
				this.zenMode.transitionDisposeables.push(this.editorService.onDidVisibleEditorsChange(() => setLineNumbers('off')));
			}

1679 1680
			if (config.hideTabs && this.editorPart.partOptions.showTabs) {
				this.zenMode.transitionDisposeables.push(this.editorPart.enforcePartOptions({ showTabs: false }));
I
isidor 已提交
1681
			}
1682 1683 1684 1685

			if (config.centerLayout) {
				this.centerEditorLayout(true, true);
			}
1686 1687 1688 1689
		}

		// Zen Mode Inactive
		else {
1690
			if (this.zenMode.wasPanelVisible) {
1691
				this.setPanelHidden(false, true);
1692
			}
1693

1694
			if (this.zenMode.wasSideBarVisible) {
1695
				this.setSideBarHidden(false, true);
1696
			}
1697

1698 1699 1700
			if (this.zenMode.transitionedToCenteredEditorLayout) {
				this.centerEditorLayout(false, true);
			}
I
isidor 已提交
1701
			setLineNumbers(this.configurationService.getValue('editor.lineNumbers'));
1702

1703 1704
			// Status bar and activity bar visibility come from settings -> update their visibility.
			this.onDidUpdateConfiguration(true);
1705

B
Benjamin Pasero 已提交
1706
			this.editorGroupService.activeGroup.focus();
1707

1708
			toggleFullScreen = this.zenMode.transitionedToFullScreen && isFullscreen();
I
isidor 已提交
1709
		}
1710

1711
		this.inZenMode.set(this.zenMode.active);
I
isidor 已提交
1712

I
isidor 已提交
1713
		if (!skipLayout) {
1714
			this.layout();
I
isidor 已提交
1715
		}
1716

1717
		if (toggleFullScreen) {
1718
			this.windowService.toggleFullScreen();
1719
		}
I
isidor 已提交
1720 1721
	}

S
SteVen Batten 已提交
1722
	private updateGrid(): void {
S
SteVen Batten 已提交
1723
		if (!(this.workbenchGrid instanceof Grid)) {
1724 1725 1726
			return;
		}

S
SteVen Batten 已提交
1727 1728 1729 1730 1731
		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);
1732

S
SteVen Batten 已提交
1733 1734 1735
		// Add parts to grid
		if (!statusBarInGrid) {
			this.workbenchGrid.addView(this.statusbarPartView, Sizing.Split, this.editorPartView, Direction.Down);
S
SteVen Batten 已提交
1736 1737 1738
			statusBarInGrid = true;
		}

1739
		if (!titlebarInGrid && this.useCustomTitleBarStyle()) {
S
SteVen Batten 已提交
1740 1741 1742
			this.workbenchGrid.addView(this.titlebarPartView, Sizing.Split, this.editorPartView, Direction.Up);
			titlebarInGrid = true;
		}
S
SteVen Batten 已提交
1743

S
SteVen Batten 已提交
1744 1745 1746 1747
		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 已提交
1748

S
SteVen Batten 已提交
1749 1750 1751 1752
		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 已提交
1753

S
SteVen Batten 已提交
1754 1755 1756
		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 已提交
1757 1758
		}

S
SteVen Batten 已提交
1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783
		// 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 已提交
1784
		// Show visible parts
S
SteVen Batten 已提交
1785 1786 1787 1788
		if (!this.editorHidden) {
			this.editorPartView.show();
		}

S
SteVen Batten 已提交
1789 1790 1791
		if (!this.statusBarHidden) {
			this.statusbarPartView.show();
		}
S
SteVen Batten 已提交
1792

S
SteVen Batten 已提交
1793 1794
		if (this.isVisible(Parts.TITLEBAR_PART)) {
			this.titlebarPartView.show();
S
SteVen Batten 已提交
1795 1796
		}

S
SteVen Batten 已提交
1797 1798 1799
		if (!this.activityBarHidden) {
			this.activitybarPartView.show();
		}
S
SteVen Batten 已提交
1800

S
SteVen Batten 已提交
1801 1802
		if (!this.sideBarHidden) {
			this.sidebarPartView.show();
S
SteVen Batten 已提交
1803 1804
		}

S
SteVen Batten 已提交
1805 1806
		if (!this.panelHidden) {
			this.panelPartView.show();
S
SteVen Batten 已提交
1807 1808 1809
		}
	}

1810
	private layout(options?: ILayoutOptions): void {
S
SteVen Batten 已提交
1811 1812 1813
		this.contextViewService.layout();

		if (this.workbenchStarted && !this.workbenchShutdown) {
S
SteVen Batten 已提交
1814
			if (this.workbenchGrid instanceof Grid) {
1815 1816 1817
				const dimensions = getClientArea(this.container);
				position(this.workbench, 0, 0, 0, 0, 'relative');
				size(this.workbench, dimensions.width, dimensions.height);
S
SteVen Batten 已提交
1818

S
SteVen Batten 已提交
1819
				// Layout the grid
S
SteVen Batten 已提交
1820
				this.workbenchGrid.layout(dimensions.width, dimensions.height);
S
SteVen Batten 已提交
1821 1822 1823 1824 1825 1826 1827 1828

				// 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
1829
				this.updateGrid();
S
SteVen Batten 已提交
1830 1831
			} else {
				this.workbenchGrid.layout(options);
1832
			}
1833 1834 1835
		}
	}

1836
	isEditorLayoutCentered(): boolean {
1837
		return this.shouldCenterLayout;
S
SrTobi 已提交
1838 1839
	}

1840
	centerEditorLayout(active: boolean, skipLayout?: boolean): void {
B
Benjamin Pasero 已提交
1841
		this.storageService.store(Workbench.centeredEditorLayoutActiveStorageKey, active, StorageScope.WORKSPACE);
1842 1843
		this.shouldCenterLayout = active;
		let smartActive = active;
1844
		if (this.editorPart.groups.length > 1 && this.configurationService.getValue('workbench.editor.centeredLayoutAutoResize')) {
B
Benjamin Pasero 已提交
1845
			smartActive = false; // Respect the auto resize setting - do not go into centered layout if there is more than 1 group.
1846
		}
B
Benjamin Pasero 已提交
1847

1848
		// Enter Centered Editor Layout
1849 1850
		if (this.editorPart.isLayoutCentered() !== smartActive) {
			this.editorPart.centerLayout(smartActive);
1851

1852 1853 1854
			if (!skipLayout) {
				this.layout();
			}
1855
		}
S
SrTobi 已提交
1856 1857
	}

1858
	resizePart(part: Parts, sizeChange: number): void {
S
SteVen Batten 已提交
1859
		let view: View;
1860 1861
		switch (part) {
			case Parts.SIDEBAR_PART:
S
SteVen Batten 已提交
1862
				view = this.sidebarPartView;
1863
			case Parts.PANEL_PART:
S
SteVen Batten 已提交
1864
				view = this.panelPartView;
1865
			case Parts.EDITOR_PART:
S
SteVen Batten 已提交
1866 1867
				view = this.editorPartView;
				if (this.workbenchGrid instanceof Grid) {
1868 1869 1870 1871
					this.workbenchGrid.resizeView(view, this.workbenchGrid.getViewSize(view) + sizeChange);
				} else {
					this.workbenchGrid.resizePart(part, sizeChange);
				}
1872 1873
				break;
			default:
B
Benjamin Pasero 已提交
1874
				return; // Cannot resize other parts
1875 1876 1877
		}
	}

1878 1879
	setActivityBarHidden(hidden: boolean, skipLayout?: boolean): void {
		this.activityBarHidden = hidden;
1880

1881 1882
		// Layout
		if (!skipLayout) {
S
SteVen Batten 已提交
1883
			if (this.workbenchGrid instanceof Grid) {
S
SteVen Batten 已提交
1884
				this.layout();
1885 1886 1887
			} else {
				this.workbenchGrid.layout();
			}
1888
		}
1889
	}
1890

S
SteVen Batten 已提交
1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907
	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();
		}
	}

1908
	setSideBarHidden(hidden: boolean, skipLayout?: boolean): void {
1909 1910 1911 1912 1913
		this.sideBarHidden = hidden;
		this.sideBarVisibleContext.set(!hidden);

		// Adjust CSS
		if (hidden) {
1914
			addClass(this.workbench, 'nosidebar');
1915
		} else {
1916
			removeClass(this.workbench, 'nosidebar');
1917 1918
		}

1919 1920
		// If sidebar becomes hidden, also hide the current active Viewlet if any
		if (hidden && this.sidebarPart.getActiveViewlet()) {
1921 1922 1923 1924 1925 1926 1927 1928 1929
			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();
			}
1930 1931 1932 1933 1934 1935
		}

		// 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 已提交
1936
				const viewlet = this.sidebarPart.openViewlet(viewletToOpen, true);
1937
				if (!viewlet) {
I
isidor 已提交
1938
					this.sidebarPart.openViewlet(this.sidebarPart.getDefaultViewletId(), true);
1939
				}
1940
			}
1941 1942
		}

1943 1944 1945 1946 1947 1948 1949
		// 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);
		}
1950

1951 1952
		// Layout
		if (!skipLayout) {
S
SteVen Batten 已提交
1953
			if (this.workbenchGrid instanceof Grid) {
S
SteVen Batten 已提交
1954
				this.layout();
1955 1956 1957
			} else {
				this.workbenchGrid.layout();
			}
1958
		}
1959
	}
1960

1961
	setPanelHidden(hidden: boolean, skipLayout?: boolean): void {
1962 1963 1964 1965
		this.panelHidden = hidden;

		// Adjust CSS
		if (hidden) {
1966
			addClass(this.workbench, 'nopanel');
1967
		} else {
1968
			removeClass(this.workbench, 'nopanel');
1969 1970 1971 1972
		}

		// If panel part becomes hidden, also hide the current active panel if any
		if (hidden && this.panelPart.getActivePanel()) {
1973 1974
			this.panelPart.hideActivePanel();
			this.editorGroupService.activeGroup.focus(); // Pass focus to editor group if panel part is now hidden
1975 1976 1977 1978 1979 1980
		}

		// 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) {
I
isidor 已提交
1981 1982
				const focus = !skipLayout;
				this.panelPart.openPanel(panelToOpen, focus);
1983 1984 1985
			}
		}

1986 1987 1988 1989 1990 1991
		// Remember in settings
		if (!hidden) {
			this.storageService.store(Workbench.panelHiddenStorageKey, 'false', StorageScope.WORKSPACE);
		} else {
			this.storageService.remove(Workbench.panelHiddenStorageKey, StorageScope.WORKSPACE);
		}
1992

S
SteVen Batten 已提交
1993 1994 1995 1996 1997
		// The editor and panel cannot be hiddne at the same time
		if (hidden && this.editorHidden) {
			this.setEditorHidden(false, true);
		}

1998 1999
		// Layout
		if (!skipLayout) {
S
SteVen Batten 已提交
2000
			if (this.workbenchGrid instanceof Grid) {
S
SteVen Batten 已提交
2001
				this.layout();
2002 2003 2004
			} else {
				this.workbenchGrid.layout();
			}
2005
		}
2006 2007 2008
	}

	toggleMaximizedPanel(): void {
S
SteVen Batten 已提交
2009 2010
		if (this.workbenchGrid instanceof Grid) {
			this.workbenchGrid.maximizeViewSize(this.panelPartView);
2011 2012 2013
		} else {
			this.workbenchGrid.layout({ toggleMaximizedPanel: true, source: Parts.PANEL_PART });
		}
2014 2015 2016
	}

	isPanelMaximized(): boolean {
S
SteVen Batten 已提交
2017
		if (this.workbenchGrid instanceof Grid) {
2018
			try {
S
SteVen Batten 已提交
2019
				return this.workbenchGrid.getViewSize2(this.panelPartView).height === this.panelPart.maximumHeight;
2020 2021 2022 2023 2024 2025
			} catch (e) {
				return false;
			}
		} else {
			return this.workbenchGrid.isPanelMaximized();
		}
2026 2027 2028 2029 2030 2031 2032
	}

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

	setSideBarPosition(position: Position): void {
2033 2034
		const wasHidden = this.sideBarHidden;

2035
		if (this.sideBarHidden) {
2036
			this.setSideBarHidden(false, true /* Skip Layout */);
2037 2038 2039 2040 2041 2042 2043
		}

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

		// Adjust CSS
2044 2045 2046 2047
		removeClass(this.activitybarPart.getContainer(), oldPositionValue);
		removeClass(this.sidebarPart.getContainer(), oldPositionValue);
		addClass(this.activitybarPart.getContainer(), newPositionValue);
		addClass(this.sidebarPart.getContainer(), newPositionValue);
2048 2049 2050 2051 2052 2053

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

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

S
SteVen Batten 已提交
2056
			if (!wasHidden) {
S
SteVen Batten 已提交
2057
				this.uiState.lastSidebarDimension = this.workbenchGrid.getViewSize(this.sidebarPartView);
2058 2059
			}

S
SteVen Batten 已提交
2060 2061
			this.workbenchGrid.removeView(this.sidebarPartView);
			this.workbenchGrid.removeView(this.activitybarPartView);
S
SteVen Batten 已提交
2062 2063 2064

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

S
SteVen Batten 已提交
2067
			this.layout();
2068 2069 2070
		} else {
			this.workbenchGrid.layout();
		}
2071 2072
	}

S
SteVen Batten 已提交
2073
	setMenubarVisibility(visibility: MenuBarVisibility, skipLayout: boolean): void {
S
SteVen Batten 已提交
2074 2075
		if (this.menubarVisibility !== visibility) {
			this.menubarVisibility = visibility;
2076

2077
			// Layout
S
SteVen Batten 已提交
2078
			if (!skipLayout) {
S
SteVen Batten 已提交
2079
				if (this.workbenchGrid instanceof Grid) {
2080
					const dimensions = getClientArea(this.container);
2081 2082 2083 2084
					this.workbenchGrid.layout(dimensions.width, dimensions.height);
				} else {
					this.workbenchGrid.layout();
				}
S
SteVen Batten 已提交
2085
			}
2086 2087 2088
		}
	}

S
SteVen Batten 已提交
2089 2090 2091 2092
	getMenubarVisibility(): MenuBarVisibility {
		return this.menubarVisibility;
	}

2093 2094 2095 2096
	getPanelPosition(): Position {
		return this.panelPosition;
	}

2097
	setPanelPosition(position: Position): void {
2098 2099
		const wasHidden = this.panelHidden;

2100 2101
		if (this.panelHidden) {
			this.setPanelHidden(false, true /* Skip Layout */);
2102 2103
		} else {
			this.saveLastPanelDimension();
2104
		}
2105

2106 2107 2108 2109
		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);
2110

2111
		// Adjust CSS
2112 2113
		removeClass(this.panelPart.getContainer(), oldPositionValue);
		addClass(this.panelPart.getContainer(), newPositionValue);
2114

2115 2116 2117 2118
		// Update Styles
		this.panelPart.updateStyles();

		// Layout
S
SteVen Batten 已提交
2119 2120 2121
		if (this.workbenchGrid instanceof Grid) {
			if (!wasHidden) {
				this.saveLastPanelDimension();
2122
			}
2123

2124
			this.workbenchGrid.removeView(this.panelPartView);
S
SteVen Batten 已提交
2125
			this.layout();
2126 2127 2128 2129
		} else {
			this.workbenchGrid.layout();
		}
	}
2130 2131

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