workbench.ts 69.5 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

8 9
import { localize } from 'vs/nls';
import { setFileNameComparer } from 'vs/base/common/comparers';
B
Benjamin Pasero 已提交
10
import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle';
11 12
import { Event, Emitter, setGlobalLeakWarningThreshold } from 'vs/base/common/event';
import { EventType, addDisposableListener, addClasses, addClass, removeClass, isAncestor, getClientArea, position, size, removeClasses } from 'vs/base/browser/dom';
13
import { runWhenIdle, IdleValue } from 'vs/base/common/async';
14 15 16
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';
17
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
18
import { Registry } from 'vs/platform/registry/common/platform';
19
import { isWindows, isLinux, isMacintosh, language } from 'vs/base/common/platform';
20
import { IResourceInput } from 'vs/platform/editor/common/editor';
J
Johannes Rieken 已提交
21
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
22
import { IEditorInputFactoryRegistry, Extensions as EditorExtensions, IUntitledResourceInput, IResourceDiffInput } from 'vs/workbench/common/editor';
J
Johannes Rieken 已提交
23
import { ActivitybarPart } from 'vs/workbench/browser/parts/activitybar/activitybarPart';
24
import { SidebarPart } from 'vs/workbench/browser/parts/sidebar/sidebarPart';
J
Johannes Rieken 已提交
25 26
import { PanelPart } from 'vs/workbench/browser/parts/panel/panelPart';
import { StatusbarPart } from 'vs/workbench/browser/parts/statusbar/statusbarPart';
B
Benjamin Pasero 已提交
27
import { TitlebarPart } from 'vs/workbench/browser/parts/titlebar/titlebarPart';
28
import { EditorPart } from 'vs/workbench/browser/parts/editor/editorPart';
29
import { IActionBarRegistry, Extensions as ActionBarExtensions } from 'vs/workbench/browser/actions';
J
Johannes Rieken 已提交
30
import { PanelRegistry, Extensions as PanelExtensions } from 'vs/workbench/browser/panel';
31
import { ViewletRegistry, Extensions as ViewletExtensions } from 'vs/workbench/browser/viewlet';
J
Johannes Rieken 已提交
32
import { QuickOpenController } from 'vs/workbench/browser/parts/quickopen/quickOpenController';
C
Christof Marti 已提交
33 34
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { QuickInputService } from 'vs/workbench/browser/parts/quickinput/quickInput';
J
Johannes Rieken 已提交
35
import { getServices } from 'vs/platform/instantiation/common/extensions';
36
import { Position, Parts, IPartService, IDimension, PositionToString, ILayoutOptions } from 'vs/workbench/services/part/common/partService';
37
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
38
import { IStorageService, StorageScope, IWillSaveStateEvent, WillSaveStateReason } from 'vs/platform/storage/common/storage';
S
SteVen Batten 已提交
39
import { ContextMenuService as HTMLContextMenuService } from 'vs/platform/contextview/browser/contextMenuService';
J
Johannes Rieken 已提交
40
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
41
import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing';
J
Johannes Rieken 已提交
42
import { ContextKeyService } from 'vs/platform/contextkey/browser/contextKeyService';
43
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
44
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
I
isidor 已提交
45
import { IActivityService } from 'vs/workbench/services/activity/common/activity';
B
Benjamin Pasero 已提交
46
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
J
Johannes Rieken 已提交
47 48
import { IFileService } from 'vs/platform/files/common/files';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
B
Benjamin Pasero 已提交
49
import { ITitleService } from 'vs/workbench/services/title/common/titleService';
J
Johannes Rieken 已提交
50
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
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 { TextModelResolverService } from 'vs/workbench/services/textmodelResolver/common/textModelResolverService';
57
import { ITextModelService } from 'vs/editor/common/services/resolverService';
J
Johannes Rieken 已提交
58
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
B
Benjamin Pasero 已提交
59
import { LifecyclePhase, StartupKind, ILifecycleService, WillShutdownEvent } from 'vs/platform/lifecycle/common/lifecycle';
60
import { IWindowService, IWindowConfiguration, IPath, MenuBarVisibility, getTitleBarStyle, IWindowsService } from 'vs/platform/windows/common/windows';
J
Johannes Rieken 已提交
61
import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar';
S
SteVen Batten 已提交
62
import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';
J
Johannes Rieken 已提交
63
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
I
isidor 已提交
64
import { ActivityService } from 'vs/workbench/services/activity/browser/activityService';
65
import { IViewsService } from 'vs/workbench/common/views';
S
Sandeep Somavarapu 已提交
66
import { ViewsService } from 'vs/workbench/browser/parts/views/views';
67 68
import { INotificationService } from 'vs/platform/notification/common/notification';
import { NotificationService } from 'vs/workbench/services/notification/common/notificationService';
69 70
import { NotificationsCenter } from 'vs/workbench/browser/parts/notifications/notificationsCenter';
import { NotificationsAlerts } from 'vs/workbench/browser/parts/notifications/notificationsAlerts';
71
import { NotificationsStatus } from 'vs/workbench/browser/parts/notifications/notificationsStatus';
72
import { registerNotificationCommands } from 'vs/workbench/browser/parts/notifications/notificationsCommands';
73
import { NotificationsToasts } from 'vs/workbench/browser/parts/notifications/notificationsToasts';
S
Sandeep Somavarapu 已提交
74 75
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
import { PreferencesService } from 'vs/workbench/services/preferences/browser/preferencesService';
76
import { IEditorService, IResourceEditor } from 'vs/workbench/services/editor/common/editorService';
77
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
78
import { EditorService } from 'vs/workbench/services/editor/browser/editorService';
S
SteVen Batten 已提交
79
import { ContextViewService } from 'vs/platform/contextview/browser/contextViewService';
A
Alex Dima 已提交
80
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
81
import { IFileDialogService, IDialogService } from 'vs/platform/dialogs/common/dialogs';
S
SteVen Batten 已提交
82
import { Sizing, Direction, Grid, View } from 'vs/base/browser/ui/grid/grid';
I
isidor 已提交
83
import { IEditor } from 'vs/editor/common/editorCommon';
84
import { WorkbenchLayout } from 'vs/workbench/browser/layout';
85 86 87 88 89 90
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';
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
import { ILabelService } from 'vs/platform/label/common/label';
import { LabelService } from 'vs/workbench/services/label/common/labelService';
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 { 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 { 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 { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
import { ILocalizationsService } from 'vs/platform/localizations/common/localizations';
110
import { HistoryService } from 'vs/workbench/services/history/browser/history';
111
import { WorkbenchThemeService } from 'vs/workbench/services/themes/browser/workbenchThemeService';
112 113
import { IProductService } from 'vs/platform/product/common/product';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
114
import { WorkbenchContextKeysHandler } from 'vs/workbench/browser/contextkeys';
115 116

// import@node
117
import { BackupFileService, InMemoryBackupFileService } from 'vs/workbench/services/backup/node/backupFileService';
118
import { WorkspaceService } from 'vs/workbench/services/configuration/node/configurationService';
119
import { JSONEditingService } from 'vs/workbench/services/configuration/node/jsonEditingService';
120
import { getDelayedChannel } from 'vs/base/parts/ipc/node/ipc';
121 122 123 124 125 126 127 128 129 130 131 132 133
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 { 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 { LocalizationsChannelClient } from 'vs/platform/localizations/node/localizationsIpc';
134 135
import { AccessibilityService } from 'vs/platform/accessibility/node/accessibilityService';
import { ProductService } from 'vs/platform/product/node/productService';
B
Benjamin Pasero 已提交
136
import { TextResourcePropertiesService } from 'vs/workbench/services/textfile/node/textResourcePropertiesService';
137
import { RemoteFileService } from 'vs/workbench/services/files/node/remoteFileService';
138 139

// import@electron-browser
140
import { ContextMenuService as NativeContextMenuService } from 'vs/workbench/services/contextmenu/electron-browser/contextmenuService';
141 142
import { WorkbenchKeybindingService } from 'vs/workbench/services/keybinding/electron-browser/keybindingService';
import { LifecycleService } from 'vs/platform/lifecycle/electron-browser/lifecycleService';
143
import { DialogService, FileDialogService } from 'vs/workbench/services/dialogs/electron-browser/dialogService';
144 145 146 147
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';
B
Benjamin Pasero 已提交
148
import { RequestService } from 'vs/platform/request/electron-browser/requestService';
149

150 151 152 153 154 155 156
enum Identifiers {
	TITLEBAR_PART = 'workbench.parts.titlebar',
	ACTIVITYBAR_PART = 'workbench.parts.activitybar',
	SIDEBAR_PART = 'workbench.parts.sidebar',
	PANEL_PART = 'workbench.parts.panel',
	EDITOR_PART = 'workbench.parts.editor',
	STATUSBAR_PART = 'workbench.parts.statusbar'
I
isidor 已提交
157 158
}

159 160 161 162 163 164 165 166 167 168
enum Settings {
	MENUBAR_VISIBLE = 'window.menuBarVisibility',
	ACTIVITYBAR_VISIBLE = 'workbench.activityBar.visible',
	STATUSBAR_VISIBLE = 'workbench.statusBar.visible',

	SIDEBAR_POSITION = 'workbench.sideBar.location',
	PANEL_POSITION = 'workbench.panel.defaultLocation',

	FONT_ALIASING = 'workbench.fontAliasing',
	ZEN_MODE_RESTORE = 'zenMode.restore'
169
}
170

171
type FontAliasingOption = 'default' | 'antialiased' | 'none' | 'auto';
B
Benjamin Pasero 已提交
172 173
const fontAliasingValues: FontAliasingOption[] = ['antialiased', 'none', 'auto'];

174 175 176 177 178
enum State {
	SIDEBAR_HIDDEN = 'workbench.sidebar.hidden',

	PANEL_HIDDEN = 'workbench.panel.hidden',
	PANEL_POSITION = 'workbench.panel.location',
179

180 181
	ZEN_MODE_ENABLED = 'workbench.zenmode.active',
	CENTERED_LAYOUT_ENABLED = 'workbench.centerededitorlayout.active',
182 183
}

184
export class Workbench extends Disposable implements IPartService {
E
Erich Gamma 已提交
185

B
Benjamin Pasero 已提交
186 187
	_serviceBrand: any;

B
Benjamin Pasero 已提交
188 189 190 191 192 193
	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; }

194
	private previousErrorValue: string;
195
	private previousErrorTime = 0;
196

B
Benjamin Pasero 已提交
197
	private workbench: HTMLElement;
198 199 200

	private restored: boolean;
	private disposed: boolean;
201

202 203
	private editorService: EditorService;
	private editorGroupService: IEditorGroupsService;
J
Joao Moreno 已提交
204
	private contextViewService: ContextViewService;
205
	private keybindingService: IKeybindingService;
206
	private backupFileService: IBackupFileService;
207 208 209 210 211
	private notificationService: NotificationService;
	private themeService: WorkbenchThemeService;
	private telemetryService: ITelemetryService;
	private windowService: IWindowService;
	private lifecycleService: LifecycleService;
212

B
Benjamin Pasero 已提交
213
	private titlebarPart: TitlebarPart;
E
Erich Gamma 已提交
214 215
	private activitybarPart: ActivitybarPart;
	private sidebarPart: SidebarPart;
I
isidor 已提交
216
	private panelPart: PanelPart;
E
Erich Gamma 已提交
217 218
	private editorPart: EditorPart;
	private statusbarPart: StatusbarPart;
S
SteVen Batten 已提交
219

E
Erich Gamma 已提交
220
	private quickOpen: QuickOpenController;
221 222
	private quickInput: QuickInputService;

223
	private notificationsCenter: NotificationsCenter;
224
	private notificationsToasts: NotificationsToasts;
225 226 227

	private fontAliasing: FontAliasingOption;

228
	constructor(
229
		private container: HTMLElement,
J
Joao Moreno 已提交
230
		private configuration: IWindowConfiguration,
B
Benjamin Pasero 已提交
231
		private serviceCollection: ServiceCollection,
232 233
		@IInstantiationService private readonly instantiationService: IInstantiationService,
		@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
B
Benjamin Pasero 已提交
234
		@IStorageService private readonly storageService: IStorageService,
235 236
		@IConfigurationService private readonly configurationService: WorkspaceService,
		@IEnvironmentService private readonly environmentService: IEnvironmentService,
237 238
		@ILogService private readonly logService: ILogService,
		@IWindowsService private readonly windowsService: IWindowsService
239
	) {
240
		super();
E
Erich Gamma 已提交
241

242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
		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));
259 260 261 262 263 264 265 266 267

		// Inform user about loading issues from the loader
		(<any>self).require.config({
			onError: err => {
				if (err.errorCode === 'load') {
					onUnexpectedError(new Error(localize('loaderErrorNative', "Failed to load a required file. Please restart the application to try again. Details: {0}", JSON.stringify(err))));
				}
			}
		});
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
	}

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

293
	startup(): void {
294
		try {
295
			this.doStartup().then(undefined, error => this.logService.error(toErrorMessage(error, true)));
296 297 298 299 300
		} catch (error) {
			this.logService.error(toErrorMessage(error, true));

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

303
	private doStartup(): Promise<void> {
E
Erich Gamma 已提交
304

B
Benjamin Pasero 已提交
305 306 307
		// Logging
		this.logService.trace('workbench configuration', JSON.stringify(this.configuration));

308 309 310 311 312 313 314 315 316 317 318 319
		// Configure emitter leak warning threshold
		setGlobalLeakWarningThreshold(175);

		// Setup Intl for comparers
		setFileNameComparer(new IdleValue(() => {
			const collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' });
			return {
				collator: collator,
				collatorIsNumeric: collator.resolvedOptions().numeric
			};
		}));

320 321 322 323 324 325 326
		// 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()));

B
Benjamin Pasero 已提交
327
		// Create Workbench Container
328
		this.createWorkbench();
E
Erich Gamma 已提交
329

330
		// Services
B
Benjamin Pasero 已提交
331
		this.initServices(this.serviceCollection);
E
Erich Gamma 已提交
332

333
		// Context Keys
334
		this._register(this.instantiationService.createInstance(WorkbenchContextKeysHandler));
J
Joao Moreno 已提交
335

336 337
		// Register Listeners
		this.registerListeners();
E
Erich Gamma 已提交
338

339
		// Settings
340
		this.initState();
E
Erich Gamma 已提交
341

342 343
		// Create Workbench and Parts
		this.renderWorkbench();
344

345 346
		// Workbench Layout
		this.createWorkbenchLayout();
B
polish  
Benjamin Pasero 已提交
347

348 349 350 351
		// Layout
		this.layout();

		// Handle case where workbench is not starting up properly
352
		const timeoutHandle = setTimeout(() => this.logService.warn('Workbench did not finish loading in 10 seconds, that might be a problem that should be reported.'), 10000);
353
		this.lifecycleService.when(LifecyclePhase.Restored).then(() => clearTimeout(timeoutHandle));
354

355
		// Restore Parts
B
Benjamin Pasero 已提交
356 357
		return this.restoreParts();
	}
358

B
Benjamin Pasero 已提交
359
	private createWorkbench(): void {
B
Benjamin Pasero 已提交
360
		this.workbench = document.createElement('div');
361

362 363 364 365
		const platformClass = isWindows ? 'windows' : isLinux ? 'linux' : 'mac';

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

B
Benjamin Pasero 已提交
368
	private initServices(serviceCollection: ServiceCollection): void {
369

370
		// Parts
371
		serviceCollection.set(IPartService, this);
E
Erich Gamma 已提交
372

373 374 375 376 377 378 379 380 381 382 383
		// Labels
		serviceCollection.set(ILabelService, new SyncDescriptor(LabelService, undefined, true));

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

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

384 385 386 387
		// Product
		const productService = new ProductService();
		serviceCollection.set(IProductService, productService);

388 389 390 391 392 393 394 395 396 397
		// 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
398
		if (!this.environmentService.isExtensionDevelopment && !this.environmentService.args['disable-telemetry'] && !!productService.enableTelemetry) {
399 400 401
			const channel = getDelayedChannel(sharedProcess.then(c => c.getChannel('telemetryAppender')));
			const config: ITelemetryServiceConfig = {
				appender: combinedAppender(new TelemetryAppenderClient(channel), new LogAppender(this.logService)),
402
				commonProperties: resolveWorkbenchCommonProperties(this.storageService, productService.commit, productService.version, this.configuration.machineId, this.environmentService.installSourcePath),
403 404 405 406 407 408 409 410 411 412 413 414 415
				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
416
		serviceCollection.set(IDialogService, new SyncDescriptor(DialogService, undefined, true));
417 418 419 420 421

		// Lifecycle
		this.lifecycleService = this.instantiationService.createInstance(LifecycleService);
		serviceCollection.set(ILifecycleService, this.lifecycleService);

B
Benjamin Pasero 已提交
422 423 424 425 426
		this._register(this.lifecycleService.onWillShutdown(event => this._onWillShutdown.fire(event)));
		this._register(this.lifecycleService.onShutdown(() => {
			this._onShutdown.fire();
			this.dispose();
		}));
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455

		// Request Service
		serviceCollection.set(IRequestService, new SyncDescriptor(RequestService, 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
456
		serviceCollection.set(IExtensionEnablementService, new SyncDescriptor(ExtensionEnablementService, undefined, true));
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486

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

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

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

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

487 488 489 490
		// Status bar
		this.statusbarPart = this.instantiationService.createInstance(StatusbarPart, Identifiers.STATUSBAR_PART);
		serviceCollection.set(IStatusbarService, this.statusbarPart);

491
		// Context Keys
492
		serviceCollection.set(IContextKeyService, new SyncDescriptor(ContextKeyService));
493

494
		// Keybindings
B
Benjamin Pasero 已提交
495
		this.keybindingService = this.instantiationService.createInstance(WorkbenchKeybindingService, window);
496
		serviceCollection.set(IKeybindingService, this.keybindingService);
A
Alex Dima 已提交
497

J
Joao Moreno 已提交
498
		// Context view service
B
Benjamin Pasero 已提交
499
		this.contextViewService = this.instantiationService.createInstance(ContextViewService, this.workbench);
J
Joao Moreno 已提交
500 501
		serviceCollection.set(IContextViewService, this.contextViewService);

S
SteVen Batten 已提交
502
		// Use themable context menus when custom titlebar is enabled to match custom menubar
503
		if (!isMacintosh && getTitleBarStyle(this.configurationService, this.environmentService) === 'custom') {
J
fix npe  
Johannes Rieken 已提交
504
			serviceCollection.set(IContextMenuService, new SyncDescriptor(HTMLContextMenuService, [null]));
S
SteVen Batten 已提交
505 506 507
		} else {
			serviceCollection.set(IContextMenuService, new SyncDescriptor(NativeContextMenuService));
		}
508

P
Pine Wu 已提交
509
		// Sidebar part
510
		this.sidebarPart = this.instantiationService.createInstance(SidebarPart, Identifiers.SIDEBAR_PART);
P
Pine Wu 已提交
511 512

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

I
isidor 已提交
515
		// Panel service (panel part)
516 517
		this.panelPart = this.instantiationService.createInstance(PanelPart, Identifiers.PANEL_PART);
		serviceCollection.set(IPanelService, this.panelPart);
I
isidor 已提交
518

519 520
		// Views service
		serviceCollection.set(IViewsService, new SyncDescriptor(ViewsService));
S
Sandeep Somavarapu 已提交
521

E
Erich Gamma 已提交
522
		// Activity service (activitybar part)
523
		this.activitybarPart = this.instantiationService.createInstance(ActivitybarPart, Identifiers.ACTIVITYBAR_PART);
524
		serviceCollection.set(IActivityService, new SyncDescriptor(ActivityService, [this.activitybarPart, this.panelPart], true));
E
Erich Gamma 已提交
525

526
		// File Service
527 528 529 530
		const fileService = this.instantiationService.createInstance(RemoteFileService);
		serviceCollection.set(IFileService, fileService);
		this.configurationService.acquireFileService(fileService);
		this.themeService.acquireFileService(fileService);
531

532
		// Editor and Group services
533
		this.editorPart = this.instantiationService.createInstance(EditorPart, Identifiers.EDITOR_PART, !this.hasInitialFilesToOpen());
B
Benjamin Pasero 已提交
534
		this.editorGroupService = this.editorPart;
535 536 537
		serviceCollection.set(IEditorGroupsService, this.editorPart);
		this.editorService = this.instantiationService.createInstance(EditorService);
		serviceCollection.set(IEditorService, this.editorService);
E
Erich Gamma 已提交
538

539 540 541
		// Accessibility
		serviceCollection.set(IAccessibilityService, new SyncDescriptor(AccessibilityService, undefined, true));

542 543 544
		// Title bar
		this.titlebarPart = this.instantiationService.createInstance(TitlebarPart, Identifiers.TITLEBAR_PART);
		serviceCollection.set(ITitleService, this.titlebarPart);
B
Benjamin Pasero 已提交
545

546
		// History
547
		serviceCollection.set(IHistoryService, new SyncDescriptor(HistoryService));
548

M
Martin Aeschlimann 已提交
549
		// File Dialogs
550
		serviceCollection.set(IFileDialogService, new SyncDescriptor(FileDialogService, undefined, true));
M
Martin Aeschlimann 已提交
551

552
		// Backup File Service
B
Benjamin Pasero 已提交
553 554
		if (this.configuration.backupPath) {
			this.backupFileService = this.instantiationService.createInstance(BackupFileService, this.configuration.backupPath);
B
Benjamin Pasero 已提交
555 556 557
		} else {
			this.backupFileService = new InMemoryBackupFileService();
		}
558
		serviceCollection.set(IBackupFileService, this.backupFileService);
559

560
		// Text File Service
561
		serviceCollection.set(ITextFileService, new SyncDescriptor(TextFileService));
562

B
Benjamin Pasero 已提交
563
		// Text Model Resolver Service
564
		serviceCollection.set(ITextModelService, new SyncDescriptor(TextModelResolverService, undefined, true));
B
Benjamin Pasero 已提交
565

566
		// JSON Editing
567
		serviceCollection.set(IJSONEditingService, new SyncDescriptor(JSONEditingService, undefined, true));
568

E
Erich Gamma 已提交
569
		// Quick open service (quick open controller)
570 571
		this.quickOpen = this.instantiationService.createInstance(QuickOpenController);
		serviceCollection.set(IQuickOpenService, this.quickOpen);
572

C
Christof Marti 已提交
573 574 575 576
		// Quick input service
		this.quickInput = this.instantiationService.createInstance(QuickInputService);
		serviceCollection.set(IQuickInputService, this.quickInput);

S
Sandeep Somavarapu 已提交
577 578 579
		// PreferencesService
		serviceCollection.set(IPreferencesService, this.instantiationService.createInstance(PreferencesService));

B
polish  
Benjamin Pasero 已提交
580
		// Contributed services
B
Benjamin Pasero 已提交
581
		const contributedServices = getServices();
E
Erich Gamma 已提交
582
		for (let contributedService of contributedServices) {
583
			serviceCollection.set(contributedService.id, contributedService.descriptor);
E
Erich Gamma 已提交
584 585 586
		}

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

591
		// TODO@Sandeep debt around cyclic dependencies
B
Benjamin Pasero 已提交
592
		this.configurationService.acquireInstantiationService(this.instantiationService);
E
Erich Gamma 已提交
593 594
	}

595 596 597 598 599 600 601
	private hasInitialFilesToOpen(): boolean {
		return !!(
			(this.configuration.filesToCreate && this.configuration.filesToCreate.length > 0) ||
			(this.configuration.filesToOpen && this.configuration.filesToOpen.length > 0) ||
			(this.configuration.filesToDiff && this.configuration.filesToDiff.length > 0));
	}

602
	//#region event handling
E
Erich Gamma 已提交
603

604
	private registerListeners(): void {
I
isidor 已提交
605

606
		// Storage
607
		this._register(this.storageService.onWillSaveState(e => this.saveState(e)));
608

609
		// Restore editor if hidden and it changes
610 611
		this._register(this.editorService.onDidVisibleEditorsChange(() => this.setEditorHidden(false)));
		this._register(this.editorPart.onDidActivateGroup(() => this.setEditorHidden(false)));
S
Sanders Lauture 已提交
612

613
		// Configuration changes
614
		this._register(this.configurationService.onDidChangeConfiguration(() => this.setFontAliasing()));
615
		this._register(this.configurationService.onDidChangeConfiguration(() => this.onDidUpdateConfiguration()));
I
isidor 已提交
616

617
		// Fullscreen changes
618
		this._register(onDidChangeFullscreen(() => this.onFullscreenChanged()));
B
Benjamin Pasero 已提交
619 620

		// Group changes
621 622
		this._register(this.editorGroupService.onDidAddGroup(() => this.centerEditorLayout(this.state.editor.centered)));
		this._register(this.editorGroupService.onDidRemoveGroup(() => this.centerEditorLayout(this.state.editor.centered)));
623 624

		// Prevent workbench from scrolling #55456
625
		this._register(addDisposableListener(this.workbench, EventType.SCROLL, () => this.workbench.scrollTop = 0));
626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641

		// Menubar visibility changes
		if ((isWindows || isLinux) && getTitleBarStyle(this.configurationService, this.environmentService) === 'custom') {
			this._register(this.titlebarPart.onMenubarVisibilityChange(visible => this.onMenubarToggled(visible)));
		}
	}

	private onMenubarToggled(visible: boolean) {
		if (visible !== this.state.menuBar.toggled) {
			this.state.menuBar.toggled = visible;

			if (isFullscreen() && (this.state.menuBar.visibility === 'toggle' || this.state.menuBar.visibility === 'default')) {
				this._onTitleBarVisibilityChange.fire();
				this.layout();
			}
		}
642
	}
643

644
	private onFullscreenChanged(): void {
S
SrTobi 已提交
645

646
		// Apply as CSS class
647 648
		if (isFullscreen()) {
			addClass(this.workbench, 'fullscreen');
649
		} else {
650
			removeClass(this.workbench, 'fullscreen');
B
Benjamin Pasero 已提交
651

652
			if (this.state.zenMode.transitionedToFullScreen && this.state.zenMode.active) {
653 654 655
				this.toggleZenMode();
			}
		}
E
Erich Gamma 已提交
656

657
		// Changing fullscreen state of the window has an impact on custom title bar visibility, so we need to update
658
		if (getTitleBarStyle(this.configurationService, this.environmentService) === 'custom') {
659 660 661
			this._onTitleBarVisibilityChange.fire();
			this.layout(); // handle title bar when fullscreen changes
		}
662 663
	}

664
	//#endregion
B
Benjamin Pasero 已提交
665

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

669
		// Restore Editorpart
670
		mark('willRestoreEditors');
671
		restorePromises.push(this.editorPart.whenRestored.then(() => {
B
Benjamin Pasero 已提交
672 673 674 675

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

J
Johannes Rieken 已提交
678
				return Promise.resolve(undefined);
B
Benjamin Pasero 已提交
679 680
			}

681 682
			if (Array.isArray(this.state.editor.editorsToOpen)) {
				return openEditors(this.state.editor.editorsToOpen, this.editorService);
B
Benjamin Pasero 已提交
683 684
			}

685
			return this.state.editor.editorsToOpen.then(editors => openEditors(editors, this.editorService));
686
		}).then(() => mark('didRestoreEditors')));
E
Erich Gamma 已提交
687

688
		// Restore Sidebar
689
		if (this.state.sideBar.viewletToRestore) {
690
			mark('willRestoreViewlet');
691
			restorePromises.push(this.sidebarPart.openViewlet(this.state.sideBar.viewletToRestore)
I
isidor 已提交
692
				.then(viewlet => viewlet || this.sidebarPart.openViewlet(this.sidebarPart.getDefaultViewletId()))
693
				.then(() => mark('didRestoreViewlet')));
694 695
		}

696
		// Restore Panel
697
		if (this.state.panel.panelToRestore) {
698
			mark('willRestorePanel');
699
			this.panelPart.openPanel(this.state.panel.panelToRestore, false);
700
			mark('didRestorePanel');
I
isidor 已提交
701 702
		}

703 704
		// Restore Zen Mode
		if (this.state.zenMode.restore) {
I
isidor 已提交
705
			this.toggleZenMode(true, true);
I
isidor 已提交
706 707
		}

708 709
		// Restore Editor Center Mode
		if (this.state.editor.restoreCentered) {
I
isidor 已提交
710
			this.centerEditorLayout(true);
S
SrTobi 已提交
711
		}
712

713 714
		return Promise.all(restorePromises).then(() => this.whenRestored(), error => this.whenRestored(error));
	}
B
Benjamin Pasero 已提交
715

716 717
	private whenRestored(error?: Error): void {
		this.restored = true;
B
Benjamin Pasero 已提交
718

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

722 723 724 725 726 727 728
		// 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);
I
isidor 已提交
729

730 731 732
		if (error) {
			onUnexpectedError(error);
		}
733

734
		this.logStartupTelemetry();
E
Erich Gamma 已提交
735 736
	}

737
	private logStartupTelemetry(): void {
738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767
		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,
768
			customKeybindingsCount: this.keybindingService.customKeybindingsCount(),
769 770
			theme: this.themeService.getColorTheme().id,
			language,
771
			pinnedViewlets: this.activitybarPart.getPinnedViewletIds(),
772
			restoredViewlet: this.state.sideBar.viewletToRestore,
773
			restoredEditors: this.editorService.visibleEditors.length,
774 775 776 777 778 779 780
			startupKind: this.lifecycleService.startupKind
		});

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

E
Erich Gamma 已提交
781 782 783
	private renderWorkbench(): void {

		// Apply sidebar state as CSS class
784
		if (this.state.sideBar.hidden) {
785
			addClass(this.workbench, 'nosidebar');
E
Erich Gamma 已提交
786
		}
B
Benjamin Pasero 已提交
787

788
		if (this.state.panel.hidden) {
789
			addClass(this.workbench, 'nopanel');
790
		}
B
Benjamin Pasero 已提交
791

792
		if (this.state.statusBar.hidden) {
793
			addClass(this.workbench, 'nostatusbar');
794
		}
E
Erich Gamma 已提交
795

B
Benjamin Pasero 已提交
796
		// Apply font aliasing
797
		this.setFontAliasing();
798

799
		// Apply fullscreen state
800 801
		if (isFullscreen()) {
			addClass(this.workbench, 'fullscreen');
B
Benjamin Pasero 已提交
802 803
		}

E
Erich Gamma 已提交
804
		// Create Parts
B
Benjamin Pasero 已提交
805
		this.createTitlebarPart();
E
Erich Gamma 已提交
806 807 808
		this.createActivityBarPart();
		this.createSidebarPart();
		this.createEditorPart();
809
		this.createPanelPart();
E
Erich Gamma 已提交
810 811
		this.createStatusbarPart();

812 813
		// Notification Handlers
		this.createNotificationsHandlers();
814

815 816 817
		// Add Workbench to DOM
		this.container.appendChild(this.workbench);
	}
818

819 820 821 822
	private setFontAliasing() {
		const aliasing = this.configurationService.getValue<FontAliasingOption>(Settings.FONT_ALIASING);
		if (this.fontAliasing === aliasing) {
			return;
823 824
		}

825 826 827 828 829 830 831 832 833
		this.fontAliasing = aliasing;

		// Remove all
		removeClasses(this.workbench, ...fontAliasingValues.map(value => `monaco-font-aliasing-${value}`));

		// Add specific
		if (fontAliasingValues.some(option => option === aliasing)) {
			addClass(this.workbench, `monaco-font-aliasing-${aliasing}`);
		}
E
Erich Gamma 已提交
834 835
	}

B
Benjamin Pasero 已提交
836
	private createTitlebarPart(): void {
837
		const titlebarContainer = this.createPart(Identifiers.TITLEBAR_PART, 'contentinfo', 'titlebar');
B
Benjamin Pasero 已提交
838

B
Benjamin Pasero 已提交
839
		this.titlebarPart.create(titlebarContainer);
B
Benjamin Pasero 已提交
840 841
	}

E
Erich Gamma 已提交
842
	private createActivityBarPart(): void {
843
		const activitybarPartContainer = this.createPart(Identifiers.ACTIVITYBAR_PART, 'navigation', 'activitybar', this.state.sideBar.position === Position.LEFT ? 'left' : 'right');
E
Erich Gamma 已提交
844

B
Benjamin Pasero 已提交
845
		this.activitybarPart.create(activitybarPartContainer);
E
Erich Gamma 已提交
846 847 848
	}

	private createSidebarPart(): void {
849
		const sidebarPartContainer = this.createPart(Identifiers.SIDEBAR_PART, 'complementary', 'sidebar', this.state.sideBar.position === Position.LEFT ? 'left' : 'right');
E
Erich Gamma 已提交
850

B
Benjamin Pasero 已提交
851
		this.sidebarPart.create(sidebarPartContainer);
E
Erich Gamma 已提交
852 853
	}

I
isidor 已提交
854
	private createPanelPart(): void {
855
		const panelPartContainer = this.createPart(Identifiers.PANEL_PART, 'complementary', 'panel', this.state.panel.position === Position.BOTTOM ? 'bottom' : 'right');
I
isidor 已提交
856

B
Benjamin Pasero 已提交
857
		this.panelPart.create(panelPartContainer);
I
isidor 已提交
858 859
	}

E
Erich Gamma 已提交
860
	private createEditorPart(): void {
861
		const editorContainer = this.createPart(Identifiers.EDITOR_PART, 'main', 'editor');
E
Erich Gamma 已提交
862

B
Benjamin Pasero 已提交
863
		this.editorPart.create(editorContainer);
E
Erich Gamma 已提交
864 865 866
	}

	private createStatusbarPart(): void {
867
		const statusbarContainer = this.createPart(Identifiers.STATUSBAR_PART, 'contentinfo', 'statusbar');
B
Benjamin Pasero 已提交
868 869 870 871

		this.statusbarPart.create(statusbarContainer);
	}

872
	private createPart(id: string, role: string, ...classes: string[]): HTMLElement {
B
Benjamin Pasero 已提交
873
		const part = document.createElement('div');
874
		addClasses(part, 'part', ...classes);
B
Benjamin Pasero 已提交
875 876 877
		part.id = id;
		part.setAttribute('role', role);

878 879 880 881 882
		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 已提交
883

B
Benjamin Pasero 已提交
884
		return part;
E
Erich Gamma 已提交
885 886
	}

887 888
	private createNotificationsHandlers(): void {

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

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

895
		// Notifications Alerts
896
		this._register(this.instantiationService.createInstance(NotificationsAlerts, this.notificationService.model));
897 898 899 900

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

901
		// Eventing
902
		this._register(this.notificationsCenter.onDidChangeVisibility(() => {
903 904 905 906 907 908 909 910

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

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

911
		// Register Commands
912
		registerNotificationCommands(this.notificationsCenter, this.notificationsToasts);
913 914
	}

915
	private saveState(e: IWillSaveStateEvent): void {
916 917 918 919

		// Zen Mode
		if (this.state.zenMode.active) {
			this.storageService.store(State.ZEN_MODE_ENABLED, true, StorageScope.WORKSPACE);
920
		} else {
921
			this.storageService.remove(State.ZEN_MODE_ENABLED, StorageScope.WORKSPACE);
922
		}
923

924 925 926
		if (e.reason === WillSaveStateReason.SHUTDOWN && this.state.zenMode.active) {
			if (!this.configurationService.getValue(Settings.ZEN_MODE_RESTORE)) {
				this.toggleZenMode(true); // We will not restore zen mode, need to clear all zen mode state changes
927 928
			}
		}
929 930 931

		// Font info
		saveFontInfo(this.storageService);
932 933
	}

934
	dispose(): void {
935
		super.dispose();
936

937
		this.disposed = true;
938 939 940 941
	}

	//#region IPartService

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

945 946 947
	private readonly _onZenMode: Emitter<boolean> = this._register(new Emitter<boolean>());
	get onZenModeChange(): Event<boolean> { return this._onZenMode.event; }

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

950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971
	private workbenchGrid: Grid<View> | WorkbenchLayout;

	private titleBarPartView: View;
	private activityBarPartView: View;
	private sideBarPartView: View;
	private panelPartView: View;
	private editorPartView: View;
	private statusBarPartView: View;

	private state = {
		menuBar: {
			visibility: undefined as MenuBarVisibility,
			toggled: false
		},

		activityBar: {
			hidden: false
		},

		sideBar: {
			hidden: false,
			position: undefined as Position,
972 973
			width: 300,
			viewletToRestore: undefined as string
974 975 976 977
		},

		editor: {
			hidden: false,
978 979 980
			centered: false,
			restoreCentered: false,
			editorsToOpen: undefined as Promise<IResourceEditor[]> | IResourceEditor[]
981 982 983 984 985 986
		},

		panel: {
			hidden: false,
			position: undefined as Position,
			height: 350,
987 988
			width: 350,
			panelToRestore: undefined as string
989 990 991 992 993 994 995 996
		},

		statusBar: {
			hidden: false
		},

		zenMode: {
			active: false,
997
			restore: false,
998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039
			transitionedToFullScreen: false,
			transitionedToCenteredEditorLayout: false,
			wasSideBarVisible: false,
			wasPanelVisible: false,
			transitionDisposeables: [] as IDisposable[]
		}
	};

	private onDidUpdateConfiguration(skipLayout?: boolean): void {

		// Sidebar Position
		const newSidebarPositionValue = this.configurationService.getValue<string>(Settings.SIDEBAR_POSITION);
		const newSidebarPosition = (newSidebarPositionValue === 'right') ? Position.RIGHT : Position.LEFT;
		if (newSidebarPosition !== this.getSideBarPosition()) {
			this.setSideBarPosition(newSidebarPosition);
		}

		// Panel Position
		this.setPanelPositionFromStorageOrConfig();

		if (!this.state.zenMode.active) {

			// Statusbar Visibility
			const newStatusbarHiddenValue = !this.configurationService.getValue<boolean>(Settings.STATUSBAR_VISIBLE);
			if (newStatusbarHiddenValue !== this.state.statusBar.hidden) {
				this.setStatusBarHidden(newStatusbarHiddenValue, skipLayout);
			}

			// Activitybar Visibility
			const newActivityBarHiddenValue = !this.configurationService.getValue<boolean>(Settings.ACTIVITYBAR_VISIBLE);
			if (newActivityBarHiddenValue !== this.state.activityBar.hidden) {
				this.setActivityBarHidden(newActivityBarHiddenValue, skipLayout);
			}
		}

		// Menubar Visibility
		const newMenubarVisibility = this.configurationService.getValue<MenuBarVisibility>(Settings.MENUBAR_VISIBLE);
		this.setMenubarVisibility(newMenubarVisibility, !!skipLayout);
	}

	private initState(): void {

1040 1041 1042 1043 1044 1045
		// Menubar visibility
		this.state.menuBar.visibility = this.configurationService.getValue<MenuBarVisibility>(Settings.MENUBAR_VISIBLE);

		// Activity bar visibility
		this.state.activityBar.hidden = !this.configurationService.getValue<string>(Settings.ACTIVITYBAR_VISIBLE);

1046 1047 1048
		// Sidebar visibility
		this.state.sideBar.hidden = this.storageService.getBoolean(State.SIDEBAR_HIDDEN, StorageScope.WORKSPACE, this.contextService.getWorkbenchState() === WorkbenchState.EMPTY);

1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068
		// Sidebar position
		this.state.sideBar.position = (this.configurationService.getValue<string>(Settings.SIDEBAR_POSITION) === 'right') ? Position.RIGHT : Position.LEFT;

		// Sidebar viewlet
		if (!this.state.sideBar.hidden) {
			const viewletRegistry = Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets);

			// Only restore last viewlet if window was reloaded or we are in development mode
			let viewletToRestore: string;
			if (!this.environmentService.isBuilt || this.lifecycleService.startupKind === StartupKind.ReloadedWindow) {
				viewletToRestore = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE, viewletRegistry.getDefaultViewletId());
			} else {
				viewletToRestore = viewletRegistry.getDefaultViewletId();
			}

			if (viewletToRestore) {
				this.state.sideBar.viewletToRestore = viewletToRestore;
			} else {
				this.state.sideBar.hidden = true; // we hide sidebar if there is no viewlet to restore
			}
1069 1070
		}

1071 1072
		// Editor centered layout
		this.state.editor.restoreCentered = this.storageService.getBoolean(State.CENTERED_LAYOUT_ENABLED, StorageScope.WORKSPACE, false);
1073

1074 1075 1076 1077 1078 1079 1080
		// Editors to open
		this.state.editor.editorsToOpen = this.resolveEditorsToOpen();

		// Panel visibility
		this.state.panel.hidden = this.storageService.getBoolean(State.PANEL_HIDDEN, StorageScope.WORKSPACE, true);

		// Panel position
1081 1082
		this.setPanelPositionFromStorageOrConfig();

1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097
		// Panel to restore
		if (!this.state.panel.hidden) {
			const panelRegistry = Registry.as<PanelRegistry>(PanelExtensions.Panels);

			let panelToRestore = this.storageService.get(PanelPart.activePanelSettingsKey, StorageScope.WORKSPACE, panelRegistry.getDefaultPanelId());
			if (!panelRegistry.hasPanel(panelToRestore)) {
				panelToRestore = panelRegistry.getDefaultPanelId(); // fallback to default if panel is unknown
			}

			if (panelToRestore) {
				this.state.panel.panelToRestore = panelToRestore;
			} else {
				this.state.panel.hidden = true; // we hide panel if there is no panel to restore
			}
		}
1098 1099 1100 1101 1102

		// Statusbar visibility
		const statusBarVisible = this.configurationService.getValue<string>(Settings.STATUSBAR_VISIBLE);
		this.state.statusBar.hidden = !statusBarVisible;

1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186
		// Zen mode enablement
		const wasZenActive = this.storageService.getBoolean(State.ZEN_MODE_ENABLED, StorageScope.WORKSPACE, false);
		this.state.zenMode.restore = wasZenActive && this.configurationService.getValue(Settings.ZEN_MODE_RESTORE);
	}

	private resolveEditorsToOpen(): Promise<IResourceEditor[]> | IResourceEditor[] {

		// Files to open, diff or create
		if (this.hasInitialFilesToOpen()) {

			// Files to diff is exclusive
			const filesToDiff = this.toInputs(this.configuration.filesToDiff, false);
			if (filesToDiff && filesToDiff.length === 2) {
				return [<IResourceDiffInput>{
					leftResource: filesToDiff[0].resource,
					rightResource: filesToDiff[1].resource,
					options: { pinned: true },
					forceFile: true
				}];
			}

			const filesToCreate = this.toInputs(this.configuration.filesToCreate, true);
			const filesToOpen = this.toInputs(this.configuration.filesToOpen, false);

			// Otherwise: Open/Create files
			return [...filesToOpen, ...filesToCreate];
		}

		// Empty workbench
		else if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY && this.openUntitledFile()) {
			const isEmpty = this.editorGroupService.count === 1 && this.editorGroupService.activeGroup.count === 0;
			if (!isEmpty) {
				return []; // do not open any empty untitled file if we restored editors from previous session
			}

			return this.backupFileService.hasBackups().then(hasBackups => {
				if (hasBackups) {
					return []; // do not open any empty untitled file if we have backups to restore
				}

				return [<IUntitledResourceInput>{}];
			});
		}

		return [];
	}

	private toInputs(paths: IPath[], isNew: boolean): Array<IResourceInput | IUntitledResourceInput> {
		if (!paths || !paths.length) {
			return [];
		}

		return paths.map(p => {
			const resource = p.fileUri;
			let input: IResourceInput | IUntitledResourceInput;
			if (isNew) {
				input = { filePath: resource.fsPath, options: { pinned: true } } as IUntitledResourceInput;
			} else {
				input = { resource, options: { pinned: true }, forceFile: true } as IResourceInput;
			}

			if (!isNew && p.lineNumber) {
				input.options.selection = {
					startLineNumber: p.lineNumber,
					startColumn: p.columnNumber
				};
			}

			return input;
		});
	}

	private openUntitledFile(): boolean {
		const startupEditor = this.configurationService.inspect('workbench.startupEditor');

		// Fallback to previous workbench.welcome.enabled setting in case startupEditor is not defined
		if (!startupEditor.user && !startupEditor.workspace) {
			const welcomeEnabledValue = this.configurationService.getValue('workbench.welcome.enabled');
			if (typeof welcomeEnabledValue === 'boolean') {
				return !welcomeEnabledValue;
			}
		}

		return startupEditor.value === 'newUntitledFile';
1187 1188 1189 1190 1191 1192 1193 1194 1195
	}

	private setPanelPositionFromStorageOrConfig() {
		const defaultPanelPosition = this.configurationService.getValue<string>(Settings.PANEL_POSITION);
		const panelPosition = this.storageService.get(State.PANEL_POSITION, StorageScope.WORKSPACE, defaultPanelPosition);

		this.state.panel.position = (panelPosition === 'right') ? Position.RIGHT : Position.BOTTOM;
	}

B
Benjamin Pasero 已提交
1196
	isRestored(): boolean {
1197
		return this.restored;
1198
	}
1199

1200 1201 1202 1203 1204
	hasFocus(part: Parts): boolean {
		const activeElement = document.activeElement;
		if (!activeElement) {
			return false;
		}
1205

1206
		const container = this.getContainer(part);
1207

1208
		return isAncestor(activeElement, container);
1209
	}
1210

1211
	getContainer(part: Parts): HTMLElement | null {
1212 1213
		switch (part) {
			case Parts.TITLEBAR_PART:
1214
				return this.titlebarPart.getContainer();
1215
			case Parts.ACTIVITYBAR_PART:
1216
				return this.activitybarPart.getContainer();
1217
			case Parts.SIDEBAR_PART:
1218
				return this.sidebarPart.getContainer();
1219
			case Parts.PANEL_PART:
1220
				return this.panelPart.getContainer();
1221
			case Parts.EDITOR_PART:
1222
				return this.editorPart.getContainer();
1223
			case Parts.STATUSBAR_PART:
1224
				return this.statusbarPart.getContainer();
1225
		}
1226

1227
		return null;
1228
	}
1229

1230 1231 1232
	isVisible(part: Parts): boolean {
		switch (part) {
			case Parts.TITLEBAR_PART:
1233
				if (getTitleBarStyle(this.configurationService, this.environmentService) === 'native') {
1234
					return false;
1235
				} else if (!isFullscreen()) {
1236 1237 1238
					return true;
				} else if (isMacintosh) {
					return false;
1239
				} else if (this.state.menuBar.visibility === 'visible') {
1240
					return true;
1241 1242
				} else if (this.state.menuBar.visibility === 'toggle' || this.state.menuBar.visibility === 'default') {
					return this.state.menuBar.toggled;
1243 1244 1245
				}

				return false;
1246
			case Parts.SIDEBAR_PART:
1247
				return !this.state.sideBar.hidden;
1248
			case Parts.PANEL_PART:
1249
				return !this.state.panel.hidden;
1250
			case Parts.STATUSBAR_PART:
1251
				return !this.state.statusBar.hidden;
1252
			case Parts.ACTIVITYBAR_PART:
1253
				return !this.state.activityBar.hidden;
1254
			case Parts.EDITOR_PART:
1255
				return this.workbenchGrid instanceof Grid ? !this.state.editor.hidden : true;
E
Erich Gamma 已提交
1256
		}
1257

1258
		return true; // any other part cannot be hidden
E
Erich Gamma 已提交
1259 1260
	}

1261 1262 1263
	getTitleBarOffset(): number {
		let offset = 0;
		if (this.isVisible(Parts.TITLEBAR_PART)) {
S
SteVen Batten 已提交
1264
			if (this.workbenchGrid instanceof Grid) {
S
SteVen Batten 已提交
1265
				offset = this.titlebarPart.maximumHeight;
S
SteVen Batten 已提交
1266 1267 1268
			} else {
				offset = this.workbenchGrid.partLayoutInfo.titlebar.height;

1269
				if (isMacintosh || this.state.menuBar.visibility === 'hidden') {
B
Benjamin Pasero 已提交
1270 1271
					offset /= getZoomFactor();
				}
1272
			}
E
Erich Gamma 已提交
1273
		}
1274 1275

		return offset;
E
Erich Gamma 已提交
1276
	}
1277

1278 1279
	getWorkbenchElement(): HTMLElement {
		return this.workbench;
1280
	}
1281

I
isidor 已提交
1282
	toggleZenMode(skipLayout?: boolean, restoring = false): void {
1283 1284
		this.state.zenMode.active = !this.state.zenMode.active;
		this.state.zenMode.transitionDisposeables = dispose(this.state.zenMode.transitionDisposeables);
1285

1286 1287
		// 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)
1288
		let toggleFullScreen = false;
I
isidor 已提交
1289 1290 1291 1292 1293 1294 1295 1296
		const setLineNumbers = (lineNumbers: any) => {
			this.editorService.visibleControls.forEach(editor => {
				const control = <IEditor>editor.getControl();
				if (control) {
					control.updateOptions({ lineNumbers });
				}
			});
		};
1297 1298

		// Zen Mode Active
1299 1300 1301 1302 1303 1304 1305 1306 1307
		if (this.state.zenMode.active) {
			const config: {
				fullScreen: boolean;
				centerLayout: boolean;
				hideTabs: boolean;
				hideActivityBar: boolean;
				hideStatusBar: boolean;
				hideLineNumbers: boolean;
			} = this.configurationService.getValue('zenMode');
1308

1309
			toggleFullScreen = !isFullscreen() && config.fullScreen;
1310 1311 1312 1313
			this.state.zenMode.transitionedToFullScreen = restoring ? config.fullScreen : toggleFullScreen;
			this.state.zenMode.transitionedToCenteredEditorLayout = !this.isEditorLayoutCentered() && config.centerLayout;
			this.state.zenMode.wasSideBarVisible = this.isVisible(Parts.SIDEBAR_PART);
			this.state.zenMode.wasPanelVisible = this.isVisible(Parts.PANEL_PART);
1314

1315 1316
			this.setPanelHidden(true, true);
			this.setSideBarHidden(true, true);
I
isidor 已提交
1317

1318 1319 1320
			if (config.hideActivityBar) {
				this.setActivityBarHidden(true, true);
			}
1321

I
isidor 已提交
1322
			if (config.hideStatusBar) {
I
isidor 已提交
1323 1324
				this.setStatusBarHidden(true, true);
			}
1325

I
isidor 已提交
1326 1327
			if (config.hideLineNumbers) {
				setLineNumbers('off');
1328
				this.state.zenMode.transitionDisposeables.push(this.editorService.onDidVisibleEditorsChange(() => setLineNumbers('off')));
I
isidor 已提交
1329 1330
			}

1331
			if (config.hideTabs && this.editorPart.partOptions.showTabs) {
1332
				this.state.zenMode.transitionDisposeables.push(this.editorPart.enforcePartOptions({ showTabs: false }));
I
isidor 已提交
1333
			}
1334 1335 1336 1337

			if (config.centerLayout) {
				this.centerEditorLayout(true, true);
			}
1338 1339 1340 1341
		}

		// Zen Mode Inactive
		else {
1342
			if (this.state.zenMode.wasPanelVisible) {
1343
				this.setPanelHidden(false, true);
1344
			}
1345

1346
			if (this.state.zenMode.wasSideBarVisible) {
1347
				this.setSideBarHidden(false, true);
1348
			}
1349

1350
			if (this.state.zenMode.transitionedToCenteredEditorLayout) {
1351 1352
				this.centerEditorLayout(false, true);
			}
I
isidor 已提交
1353
			setLineNumbers(this.configurationService.getValue('editor.lineNumbers'));
1354

1355 1356
			// Status bar and activity bar visibility come from settings -> update their visibility.
			this.onDidUpdateConfiguration(true);
1357

B
Benjamin Pasero 已提交
1358
			this.editorGroupService.activeGroup.focus();
1359

1360
			toggleFullScreen = this.state.zenMode.transitionedToFullScreen && isFullscreen();
I
isidor 已提交
1361
		}
1362

I
isidor 已提交
1363
		if (!skipLayout) {
1364
			this.layout();
I
isidor 已提交
1365
		}
1366

1367
		if (toggleFullScreen) {
1368
			this.windowService.toggleFullScreen();
1369
		}
1370 1371 1372

		// Event
		this._onZenMode.fire(this.state.zenMode.active);
I
isidor 已提交
1373 1374
	}

1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456
	private setStatusBarHidden(hidden: boolean, skipLayout?: boolean): void {
		this.state.statusBar.hidden = hidden;

		// Adjust CSS
		if (hidden) {
			addClass(this.workbench, 'nostatusbar');
		} else {
			removeClass(this.workbench, 'nostatusbar');
		}

		// Layout
		if (!skipLayout) {
			if (this.workbenchGrid instanceof Grid) {
				this.layout();
			} else {
				this.workbenchGrid.layout();
			}
		}
	}

	private createWorkbenchLayout(): void {
		if (this.configurationService.getValue('workbench.useExperimentalGridLayout')) {

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

			this.workbench.prepend(this.workbenchGrid.element);
		} 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
			);
		}
	}

	layout(options?: ILayoutOptions): void {
		this.contextViewService.layout();

		if (!this.disposed) {
			if (this.workbenchGrid instanceof Grid) {
				const dimensions = getClientArea(this.container);
				position(this.workbench, 0, 0, 0, 0, 'relative');
				size(this.workbench, dimensions.width, dimensions.height);

				// Layout the grid
				this.workbenchGrid.layout(dimensions.width, dimensions.height);

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

				// Layout Grid
				this.layoutGrid();
			} else {
				this.workbenchGrid.layout(options);
			}
		}
	}

	private layoutGrid(): void {
S
SteVen Batten 已提交
1457
		if (!(this.workbenchGrid instanceof Grid)) {
1458 1459 1460
			return;
		}

S
SteVen Batten 已提交
1461
		let panelInGrid = this.workbenchGrid.hasView(this.panelPartView);
1462 1463 1464 1465
		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);
1466

S
SteVen Batten 已提交
1467 1468
		// Add parts to grid
		if (!statusBarInGrid) {
1469
			this.workbenchGrid.addView(this.statusBarPartView, Sizing.Split, this.editorPartView, Direction.Down);
S
SteVen Batten 已提交
1470 1471 1472
			statusBarInGrid = true;
		}

1473 1474
		if (!titlebarInGrid && getTitleBarStyle(this.configurationService, this.environmentService) === 'custom') {
			this.workbenchGrid.addView(this.titleBarPartView, Sizing.Split, this.editorPartView, Direction.Up);
S
SteVen Batten 已提交
1475 1476
			titlebarInGrid = true;
		}
S
SteVen Batten 已提交
1477

S
SteVen Batten 已提交
1478
		if (!activityBarInGrid) {
1479
			this.workbenchGrid.addView(this.activityBarPartView, Sizing.Split, panelInGrid && this.state.sideBar.position === this.state.panel.position ? this.panelPartView : this.editorPartView, this.state.sideBar.position === Position.RIGHT ? Direction.Right : Direction.Left);
S
SteVen Batten 已提交
1480 1481
			activityBarInGrid = true;
		}
S
SteVen Batten 已提交
1482

S
SteVen Batten 已提交
1483
		if (!sidebarInGrid) {
1484
			this.workbenchGrid.addView(this.sideBarPartView, this.state.sideBar.width !== undefined ? this.state.sideBar.width : Sizing.Split, this.activityBarPartView, this.state.sideBar.position === Position.LEFT ? Direction.Right : Direction.Left);
S
SteVen Batten 已提交
1485 1486
			sidebarInGrid = true;
		}
S
SteVen Batten 已提交
1487

S
SteVen Batten 已提交
1488
		if (!panelInGrid) {
1489
			this.workbenchGrid.addView(this.panelPartView, this.getPanelDimension(this.state.panel.position) !== undefined ? this.getPanelDimension(this.state.panel.position) : Sizing.Split, this.editorPartView, this.state.panel.position === Position.BOTTOM ? Direction.Down : Direction.Right);
S
SteVen Batten 已提交
1490
			panelInGrid = true;
S
SteVen Batten 已提交
1491 1492
		}

S
SteVen Batten 已提交
1493
		// Hide parts
1494
		if (this.state.panel.hidden) {
S
SteVen Batten 已提交
1495 1496 1497
			this.panelPartView.hide();
		}

1498 1499
		if (this.state.statusBar.hidden) {
			this.statusBarPartView.hide();
S
SteVen Batten 已提交
1500 1501 1502
		}

		if (!this.isVisible(Parts.TITLEBAR_PART)) {
1503
			this.titleBarPartView.hide();
S
SteVen Batten 已提交
1504 1505
		}

1506 1507
		if (this.state.activityBar.hidden) {
			this.activityBarPartView.hide();
S
SteVen Batten 已提交
1508 1509
		}

1510 1511
		if (this.state.sideBar.hidden) {
			this.sideBarPartView.hide();
S
SteVen Batten 已提交
1512 1513
		}

1514
		if (this.state.editor.hidden) {
S
SteVen Batten 已提交
1515 1516 1517
			this.editorPartView.hide();
		}

S
SteVen Batten 已提交
1518
		// Show visible parts
1519
		if (!this.state.editor.hidden) {
S
SteVen Batten 已提交
1520 1521 1522
			this.editorPartView.show();
		}

1523 1524
		if (!this.state.statusBar.hidden) {
			this.statusBarPartView.show();
S
SteVen Batten 已提交
1525
		}
S
SteVen Batten 已提交
1526

S
SteVen Batten 已提交
1527
		if (this.isVisible(Parts.TITLEBAR_PART)) {
1528
			this.titleBarPartView.show();
S
SteVen Batten 已提交
1529 1530
		}

1531 1532
		if (!this.state.activityBar.hidden) {
			this.activityBarPartView.show();
S
SteVen Batten 已提交
1533
		}
S
SteVen Batten 已提交
1534

1535 1536
		if (!this.state.sideBar.hidden) {
			this.sideBarPartView.show();
S
SteVen Batten 已提交
1537 1538
		}

1539
		if (!this.state.panel.hidden) {
S
SteVen Batten 已提交
1540
			this.panelPartView.show();
S
SteVen Batten 已提交
1541 1542 1543
		}
	}

1544
	isEditorLayoutCentered(): boolean {
1545
		return this.state.editor.centered;
S
SrTobi 已提交
1546 1547
	}

1548
	centerEditorLayout(active: boolean, skipLayout?: boolean): void {
1549 1550 1551
		this.storageService.store(State.CENTERED_LAYOUT_ENABLED, active, StorageScope.WORKSPACE);
		this.state.editor.centered = active;

1552
		let smartActive = active;
1553
		if (this.editorPart.groups.length > 1 && this.configurationService.getValue('workbench.editor.centeredLayoutAutoResize')) {
B
Benjamin Pasero 已提交
1554
			smartActive = false; // Respect the auto resize setting - do not go into centered layout if there is more than 1 group.
1555
		}
B
Benjamin Pasero 已提交
1556

1557
		// Enter Centered Editor Layout
1558 1559
		if (this.editorPart.isLayoutCentered() !== smartActive) {
			this.editorPart.centerLayout(smartActive);
1560

1561 1562 1563
			if (!skipLayout) {
				this.layout();
			}
1564
		}
S
SrTobi 已提交
1565 1566
	}

1567
	resizePart(part: Parts, sizeChange: number): void {
S
SteVen Batten 已提交
1568
		let view: View;
1569 1570
		switch (part) {
			case Parts.SIDEBAR_PART:
1571
				view = this.sideBarPartView;
1572
			case Parts.PANEL_PART:
S
SteVen Batten 已提交
1573
				view = this.panelPartView;
1574
			case Parts.EDITOR_PART:
S
SteVen Batten 已提交
1575 1576
				view = this.editorPartView;
				if (this.workbenchGrid instanceof Grid) {
1577 1578 1579 1580
					this.workbenchGrid.resizeView(view, this.workbenchGrid.getViewSize(view) + sizeChange);
				} else {
					this.workbenchGrid.resizePart(part, sizeChange);
				}
1581 1582
				break;
			default:
B
Benjamin Pasero 已提交
1583
				return; // Cannot resize other parts
1584 1585 1586
		}
	}

1587
	setActivityBarHidden(hidden: boolean, skipLayout?: boolean): void {
1588
		this.state.activityBar.hidden = hidden;
1589

1590 1591
		// Layout
		if (!skipLayout) {
S
SteVen Batten 已提交
1592
			if (this.workbenchGrid instanceof Grid) {
S
SteVen Batten 已提交
1593
				this.layout();
1594 1595 1596
			} else {
				this.workbenchGrid.layout();
			}
1597
		}
1598
	}
1599

S
SteVen Batten 已提交
1600
	setEditorHidden(hidden: boolean, skipLayout?: boolean): void {
1601
		if (!(this.workbenchGrid instanceof Grid) || hidden === this.state.editor.hidden) {
S
SteVen Batten 已提交
1602 1603 1604
			return;
		}

1605
		this.state.editor.hidden = hidden;
S
SteVen Batten 已提交
1606 1607

		// The editor and the panel cannot be hidden at the same time
1608
		if (this.state.editor.hidden && this.state.panel.hidden) {
S
SteVen Batten 已提交
1609 1610 1611 1612 1613 1614 1615 1616
			this.setPanelHidden(false, true);
		}

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

1617
	setSideBarHidden(hidden: boolean, skipLayout?: boolean): void {
1618
		this.state.sideBar.hidden = hidden;
1619 1620 1621

		// Adjust CSS
		if (hidden) {
1622
			addClass(this.workbench, 'nosidebar');
1623
		} else {
1624
			removeClass(this.workbench, 'nosidebar');
1625 1626
		}

1627 1628
		// If sidebar becomes hidden, also hide the current active Viewlet if any
		if (hidden && this.sidebarPart.getActiveViewlet()) {
1629 1630 1631
			this.sidebarPart.hideActiveViewlet();

			// Pass Focus to Editor or Panel if Sidebar is now hidden
1632
			const activePanel = this.panelPart.getActivePanel();
1633 1634 1635 1636 1637
			if (this.hasFocus(Parts.PANEL_PART) && activePanel) {
				activePanel.focus();
			} else {
				this.editorGroupService.activeGroup.focus();
			}
1638 1639 1640 1641 1642 1643
		}

		// 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 已提交
1644
				const viewlet = this.sidebarPart.openViewlet(viewletToOpen, true);
1645
				if (!viewlet) {
I
isidor 已提交
1646
					this.sidebarPart.openViewlet(this.sidebarPart.getDefaultViewletId(), true);
1647
				}
1648
			}
1649 1650
		}

1651 1652 1653
		// Remember in settings
		const defaultHidden = this.contextService.getWorkbenchState() === WorkbenchState.EMPTY;
		if (hidden !== defaultHidden) {
1654
			this.storageService.store(State.SIDEBAR_HIDDEN, hidden ? 'true' : 'false', StorageScope.WORKSPACE);
1655
		} else {
1656
			this.storageService.remove(State.SIDEBAR_HIDDEN, StorageScope.WORKSPACE);
1657
		}
1658

1659 1660
		// Layout
		if (!skipLayout) {
S
SteVen Batten 已提交
1661
			if (this.workbenchGrid instanceof Grid) {
S
SteVen Batten 已提交
1662
				this.layout();
1663 1664 1665
			} else {
				this.workbenchGrid.layout();
			}
1666
		}
1667
	}
1668

1669
	setPanelHidden(hidden: boolean, skipLayout?: boolean): void {
1670
		this.state.panel.hidden = hidden;
1671 1672 1673

		// Adjust CSS
		if (hidden) {
1674
			addClass(this.workbench, 'nopanel');
1675
		} else {
1676
			removeClass(this.workbench, 'nopanel');
1677 1678 1679 1680
		}

		// If panel part becomes hidden, also hide the current active panel if any
		if (hidden && this.panelPart.getActivePanel()) {
1681 1682
			this.panelPart.hideActivePanel();
			this.editorGroupService.activeGroup.focus(); // Pass focus to editor group if panel part is now hidden
1683 1684 1685 1686 1687 1688
		}

		// 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 已提交
1689 1690
				const focus = !skipLayout;
				this.panelPart.openPanel(panelToOpen, focus);
1691 1692 1693
			}
		}

1694 1695
		// Remember in settings
		if (!hidden) {
1696
			this.storageService.store(State.PANEL_HIDDEN, 'false', StorageScope.WORKSPACE);
1697
		} else {
1698
			this.storageService.remove(State.PANEL_HIDDEN, StorageScope.WORKSPACE);
1699
		}
1700

1701 1702
		// The editor and panel cannot be hidden at the same time
		if (hidden && this.state.editor.hidden) {
S
SteVen Batten 已提交
1703 1704 1705
			this.setEditorHidden(false, true);
		}

1706 1707
		// Layout
		if (!skipLayout) {
S
SteVen Batten 已提交
1708
			if (this.workbenchGrid instanceof Grid) {
S
SteVen Batten 已提交
1709
				this.layout();
1710 1711 1712
			} else {
				this.workbenchGrid.layout();
			}
1713
		}
1714 1715 1716
	}

	toggleMaximizedPanel(): void {
S
SteVen Batten 已提交
1717 1718
		if (this.workbenchGrid instanceof Grid) {
			this.workbenchGrid.maximizeViewSize(this.panelPartView);
1719 1720 1721
		} else {
			this.workbenchGrid.layout({ toggleMaximizedPanel: true, source: Parts.PANEL_PART });
		}
1722 1723 1724
	}

	isPanelMaximized(): boolean {
S
SteVen Batten 已提交
1725
		if (this.workbenchGrid instanceof Grid) {
1726
			try {
S
SteVen Batten 已提交
1727
				return this.workbenchGrid.getViewSize2(this.panelPartView).height === this.panelPart.maximumHeight;
1728 1729 1730 1731 1732 1733
			} catch (e) {
				return false;
			}
		} else {
			return this.workbenchGrid.isPanelMaximized();
		}
1734 1735 1736
	}

	getSideBarPosition(): Position {
1737
		return this.state.sideBar.position;
1738 1739
	}

1740 1741
	private setSideBarPosition(position: Position): void {
		const wasHidden = this.state.sideBar.hidden;
1742

1743
		if (this.state.sideBar.hidden) {
1744
			this.setSideBarHidden(false, true /* Skip Layout */);
1745 1746 1747
		}

		const newPositionValue = (position === Position.LEFT) ? 'left' : 'right';
1748 1749
		const oldPositionValue = (this.state.sideBar.position === Position.LEFT) ? 'left' : 'right';
		this.state.sideBar.position = position;
1750 1751

		// Adjust CSS
1752 1753 1754 1755
		removeClass(this.activitybarPart.getContainer(), oldPositionValue);
		removeClass(this.sidebarPart.getContainer(), oldPositionValue);
		addClass(this.activitybarPart.getContainer(), newPositionValue);
		addClass(this.sidebarPart.getContainer(), newPositionValue);
1756 1757 1758 1759 1760 1761

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

		// Layout
S
SteVen Batten 已提交
1762
		if (this.workbenchGrid instanceof Grid) {
S
SteVen Batten 已提交
1763
			if (!wasHidden) {
1764
				this.state.sideBar.width = this.workbenchGrid.getViewSize(this.sideBarPartView);
1765 1766
			}

1767 1768
			this.workbenchGrid.removeView(this.sideBarPartView);
			this.workbenchGrid.removeView(this.activityBarPartView);
S
SteVen Batten 已提交
1769

1770
			if (!this.state.panel.hidden && this.state.panel.position === Position.BOTTOM) {
S
SteVen Batten 已提交
1771
				this.workbenchGrid.removeView(this.panelPartView);
1772 1773
			}

S
SteVen Batten 已提交
1774
			this.layout();
1775 1776 1777
		} else {
			this.workbenchGrid.layout();
		}
1778 1779
	}

S
SteVen Batten 已提交
1780
	setMenubarVisibility(visibility: MenuBarVisibility, skipLayout: boolean): void {
1781 1782
		if (this.state.menuBar.visibility !== visibility) {
			this.state.menuBar.visibility = visibility;
1783

1784
			// Layout
S
SteVen Batten 已提交
1785
			if (!skipLayout) {
S
SteVen Batten 已提交
1786
				if (this.workbenchGrid instanceof Grid) {
1787
					const dimensions = getClientArea(this.container);
1788 1789 1790 1791
					this.workbenchGrid.layout(dimensions.width, dimensions.height);
				} else {
					this.workbenchGrid.layout();
				}
S
SteVen Batten 已提交
1792
			}
1793 1794 1795
		}
	}

S
SteVen Batten 已提交
1796
	getMenubarVisibility(): MenuBarVisibility {
1797
		return this.state.menuBar.visibility;
S
SteVen Batten 已提交
1798 1799
	}

1800
	getPanelPosition(): Position {
1801
		return this.state.panel.position;
1802 1803
	}

1804
	setPanelPosition(position: Position): void {
1805
		const wasHidden = this.state.panel.hidden;
1806

1807
		if (this.state.panel.hidden) {
1808
			this.setPanelHidden(false, true /* Skip Layout */);
1809
		} else {
1810
			this.savePanelDimension();
1811
		}
1812

1813
		const newPositionValue = (position === Position.BOTTOM) ? 'bottom' : 'right';
1814 1815 1816
		const oldPositionValue = (this.state.panel.position === Position.BOTTOM) ? 'bottom' : 'right';
		this.state.panel.position = position;
		this.storageService.store(State.PANEL_POSITION, PositionToString(this.state.panel.position).toLowerCase(), StorageScope.WORKSPACE);
1817

1818
		// Adjust CSS
1819 1820
		removeClass(this.panelPart.getContainer(), oldPositionValue);
		addClass(this.panelPart.getContainer(), newPositionValue);
1821

1822 1823 1824 1825
		// Update Styles
		this.panelPart.updateStyles();

		// Layout
S
SteVen Batten 已提交
1826 1827
		if (this.workbenchGrid instanceof Grid) {
			if (!wasHidden) {
1828
				this.savePanelDimension();
1829
			}
1830

1831
			this.workbenchGrid.removeView(this.panelPartView);
S
SteVen Batten 已提交
1832
			this.layout();
1833 1834 1835 1836
		} else {
			this.workbenchGrid.layout();
		}
	}
1837

1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853
	private getPanelDimension(position: Position): number | undefined {
		return position === Position.BOTTOM ? this.state.panel.height : this.state.panel.width;
	}

	private savePanelDimension(): void {
		if (!(this.workbenchGrid instanceof Grid)) {
			return;
		}

		if (this.state.panel.position === Position.BOTTOM) {
			this.state.panel.height = this.workbenchGrid.getViewSize(this.panelPartView);
		} else {
			this.state.panel.width = this.workbenchGrid.getViewSize(this.panelPartView);
		}
	}

1854
	//#endregion
1855
}