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

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 } 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';
23
import { SidebarPart } from 'vs/workbench/browser/parts/sidebar/sidebarPart';
J
Johannes Rieken 已提交
24
import { PanelPart } from 'vs/workbench/browser/parts/panel/panelPart';
25
import { IActionBarRegistry, Extensions as ActionBarExtensions } from 'vs/workbench/browser/actions';
J
Johannes Rieken 已提交
26
import { PanelRegistry, Extensions as PanelExtensions } from 'vs/workbench/browser/panel';
27
import { ViewletRegistry, Extensions as ViewletExtensions } from 'vs/workbench/browser/viewlet';
J
Johannes Rieken 已提交
28
import { getServices } from 'vs/platform/instantiation/common/extensions';
29
import { Position, Parts, IWorkbenchLayoutService, ILayoutOptions } from 'vs/workbench/services/layout/browser/layoutService';
30
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
31
import { IStorageService, StorageScope, IWillSaveStateEvent, WillSaveStateReason } from 'vs/platform/storage/common/storage';
S
SteVen Batten 已提交
32
import { ContextMenuService as HTMLContextMenuService } from 'vs/platform/contextview/browser/contextMenuService';
J
Johannes Rieken 已提交
33
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
B
Benjamin Pasero 已提交
34
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
J
Johannes Rieken 已提交
35 36
import { IFileService } from 'vs/platform/files/common/files';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
B
Benjamin Pasero 已提交
37
import { ITitleService } from 'vs/workbench/services/title/common/titleService';
38
import { IInstantiationService, ServicesAccessor, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
J
Johannes Rieken 已提交
39 40
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
B
Benjamin Pasero 已提交
41
import { LifecyclePhase, StartupKind, ILifecycleService, WillShutdownEvent } from 'vs/platform/lifecycle/common/lifecycle';
42
import { IWindowService, IWindowConfiguration, IPath, MenuBarVisibility, getTitleBarStyle, IWindowsService } from 'vs/platform/windows/common/windows';
S
SteVen Batten 已提交
43
import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';
J
Johannes Rieken 已提交
44
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
45 46
import { INotificationService } from 'vs/platform/notification/common/notification';
import { NotificationService } from 'vs/workbench/services/notification/common/notificationService';
47 48
import { NotificationsCenter } from 'vs/workbench/browser/parts/notifications/notificationsCenter';
import { NotificationsAlerts } from 'vs/workbench/browser/parts/notifications/notificationsAlerts';
49
import { NotificationsStatus } from 'vs/workbench/browser/parts/notifications/notificationsStatus';
50
import { registerNotificationCommands } from 'vs/workbench/browser/parts/notifications/notificationsCommands';
51
import { NotificationsToasts } from 'vs/workbench/browser/parts/notifications/notificationsToasts';
52
import { IEditorService, IResourceEditor } from 'vs/workbench/services/editor/common/editorService';
53
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
S
SteVen Batten 已提交
54
import { ContextViewService } from 'vs/platform/contextview/browser/contextViewService';
A
Alex Dima 已提交
55
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
S
SteVen Batten 已提交
56
import { Sizing, Direction, Grid, View } from 'vs/base/browser/ui/grid/grid';
B
Benjamin Pasero 已提交
57
import { WorkbenchLegacyLayout } from 'vs/workbench/browser/legacyLayout';
58 59 60 61 62 63
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';
64 65 66
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';
67
import { combinedAppender, LogAppender, NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
68
import { IExtensionGalleryService, IExtensionManagementServerService, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
69 70
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { ILocalizationsService } from 'vs/platform/localizations/common/localizations';
71
import { IProductService } from 'vs/platform/product/common/product';
72
import { WorkbenchContextKeysHandler } from 'vs/workbench/browser/contextkeys';
73
import { IDimension } from 'vs/platform/layout/browser/layoutService';
74
import { Part } from 'vs/workbench/browser/part';
75 76

// import@node
77
import { getDelayedChannel } from 'vs/base/parts/ipc/node/ipc';
78 79 80 81 82 83 84 85 86 87 88 89 90
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';
91
import { ProductService } from 'vs/platform/product/node/productService';
92 93

// import@electron-browser
94
import { ContextMenuService as NativeContextMenuService } from 'vs/workbench/services/contextmenu/electron-browser/contextmenuService';
95 96 97 98
import { LifecycleService } from 'vs/platform/lifecycle/electron-browser/lifecycleService';
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';
B
Benjamin Pasero 已提交
99
import { RequestService } from 'vs/platform/request/electron-browser/requestService';
100

101 102 103 104 105 106 107 108 109 110
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'
111
}
112

113
enum Storage {
114 115 116 117
	SIDEBAR_HIDDEN = 'workbench.sidebar.hidden',

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

119 120
	ZEN_MODE_ENABLED = 'workbench.zenmode.active',
	CENTERED_LAYOUT_ENABLED = 'workbench.centerededitorlayout.active',
121 122
}

123
export class Workbench extends Disposable implements IWorkbenchLayoutService {
E
Erich Gamma 已提交
124

B
Benjamin Pasero 已提交
125 126
	//#region workbench

127
	_serviceBrand: ServiceIdentifier<any>;
B
Benjamin Pasero 已提交
128

B
Benjamin Pasero 已提交
129 130 131 132 133 134
	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; }

135
	private previousErrorValue: string;
136
	private previousErrorTime = 0;
137

B
Benjamin Pasero 已提交
138
	private workbench: HTMLElement;
139 140 141

	private restored: boolean;
	private disposed: boolean;
142

B
Benjamin Pasero 已提交
143 144 145
	private instantiationService: IInstantiationService;
	private contextService: IWorkspaceContextService;
	private storageService: IStorageService;
B
Benjamin Pasero 已提交
146
	private configurationService: IConfigurationService;
B
Benjamin Pasero 已提交
147 148 149
	private environmentService: IEnvironmentService;
	private logService: ILogService;
	private windowsService: IWindowsService;
150

151 152
	private parts: Map<string, Part> = new Map<string, Part>();

153
	constructor(
154
		private container: HTMLElement,
J
Joao Moreno 已提交
155
		private configuration: IWindowConfiguration,
B
Benjamin Pasero 已提交
156
		private serviceCollection: ServiceCollection,
B
Benjamin Pasero 已提交
157 158 159
		@IInstantiationService instantiationService: IInstantiationService,
		@IWorkspaceContextService contextService: IWorkspaceContextService,
		@IStorageService storageService: IStorageService,
B
Benjamin Pasero 已提交
160
		@IConfigurationService configurationService: IConfigurationService,
B
Benjamin Pasero 已提交
161 162 163
		@IEnvironmentService environmentService: IEnvironmentService,
		@ILogService logService: ILogService,
		@IWindowsService windowsService: IWindowsService
164
	) {
165
		super();
E
Erich Gamma 已提交
166

B
Benjamin Pasero 已提交
167 168 169 170 171 172 173 174
		this.instantiationService = instantiationService;
		this.contextService = contextService;
		this.storageService = storageService;
		this.configurationService = configurationService;
		this.environmentService = environmentService;
		this.logService = logService;
		this.windowsService = windowsService;

175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
		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));
192 193 194 195 196 197 198 199 200

		// 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))));
				}
			}
		});
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
	}

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

221
	startup(): void {
222
		try {
223
			this.doStartup().then(undefined, error => this.logService.error(toErrorMessage(error, true)));
224 225 226 227 228
		} catch (error) {
			this.logService.error(toErrorMessage(error, true));

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

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

B
Benjamin Pasero 已提交
233 234 235
		// Logging
		this.logService.trace('workbench configuration', JSON.stringify(this.configuration));

236 237 238 239 240 241 242 243 244 245 246 247
		// 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
			};
		}));

248 249 250 251 252 253 254
		// 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 已提交
255
		// Create Workbench Container
B
Benjamin Pasero 已提交
256
		this.createWorkbenchContainer();
E
Erich Gamma 已提交
257

258
		// Services
B
Benjamin Pasero 已提交
259
		this.initServices(this.serviceCollection);
E
Erich Gamma 已提交
260

B
Benjamin Pasero 已提交
261 262 263
		// Registries
		this.startRegistries();

264
		// Context Keys
265
		this._register(this.instantiationService.createInstance(WorkbenchContextKeysHandler));
J
Joao Moreno 已提交
266

267
		// Register Listeners
B
Benjamin Pasero 已提交
268 269 270 271
		this.instantiationService.invokeFunction(accessor => {
			this.registerListeners(accessor);
			this.registerLayoutListeners(accessor);
		});
E
Erich Gamma 已提交
272

273
		// Layout State
B
Benjamin Pasero 已提交
274
		this.instantiationService.invokeFunction(accessor => this.initLayoutState(accessor));
E
Erich Gamma 已提交
275

276
		// Render Workbench
277
		this.renderWorkbench();
278

279 280
		// Workbench Layout
		this.createWorkbenchLayout();
B
polish  
Benjamin Pasero 已提交
281

282 283 284
		// Layout
		this.layout();

B
Benjamin Pasero 已提交
285
		// Restore
286
		return this.instantiationService.invokeFunction(accessor => this.restoreWorkbench(accessor));
B
Benjamin Pasero 已提交
287
	}
288

B
Benjamin Pasero 已提交
289
	private createWorkbenchContainer(): void {
B
Benjamin Pasero 已提交
290
		this.workbench = document.createElement('div');
291

292 293 294 295
		const platformClass = isWindows ? 'windows' : isLinux ? 'linux' : 'mac';

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

B
Benjamin Pasero 已提交
298
	private initServices(serviceCollection: ServiceCollection): void {
299

300
		// Parts
301
		serviceCollection.set(IWorkbenchLayoutService, this); // TODO@Ben use SyncDescriptor
E
Erich Gamma 已提交
302

303 304 305 306
		// Labels
		serviceCollection.set(ILabelService, new SyncDescriptor(LabelService, undefined, true));

		// Notifications
307
		serviceCollection.set(INotificationService, new SyncDescriptor(NotificationService, undefined, true));
308 309

		// Window
B
Benjamin Pasero 已提交
310
		serviceCollection.set(IWindowService, new SyncDescriptor(WindowService, [this.configuration]));
311

312 313
		// Product
		const productService = new ProductService();
B
Benjamin Pasero 已提交
314
		serviceCollection.set(IProductService, productService); // TODO@Ben use SyncDescriptor
315

316 317 318 319 320 321 322 323 324 325
		// 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
B
Benjamin Pasero 已提交
326
		let telemetryService: ITelemetryService;
327
		if (!this.environmentService.isExtensionDevelopment && !this.environmentService.args['disable-telemetry'] && !!productService.enableTelemetry) {
328 329 330
			const channel = getDelayedChannel(sharedProcess.then(c => c.getChannel('telemetryAppender')));
			const config: ITelemetryServiceConfig = {
				appender: combinedAppender(new TelemetryAppenderClient(channel), new LogAppender(this.logService)),
331
				commonProperties: resolveWorkbenchCommonProperties(this.storageService, productService.commit, productService.version, this.configuration.machineId, this.environmentService.installSourcePath),
332 333 334
				piiPaths: [this.environmentService.appRoot, this.environmentService.extensionsPath]
			};

B
Benjamin Pasero 已提交
335
			telemetryService = this._register(this.instantiationService.createInstance(TelemetryService, config));
336
		} else {
B
Benjamin Pasero 已提交
337
			telemetryService = NullTelemetryService;
338 339
		}

B
Benjamin Pasero 已提交
340
		serviceCollection.set(ITelemetryService, telemetryService); // TODO@Ben use SyncDescriptor
341 342

		// Lifecycle
B
Benjamin Pasero 已提交
343
		serviceCollection.set(ILifecycleService, new SyncDescriptor(LifecycleService));
344 345 346 347 348 349 350 351

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

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

		// Remote Resolver
B
Benjamin Pasero 已提交
352
		serviceCollection.set(IRemoteAuthorityResolverService, new SyncDescriptor(RemoteAuthorityResolverService, undefined, true));
353 354

		// Remote Agent
B
Benjamin Pasero 已提交
355
		serviceCollection.set(IRemoteAgentService, new SyncDescriptor(RemoteAgentService, [this.configuration]));
356 357 358 359 360 361 362 363 364 365 366

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

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

J
Joao Moreno 已提交
367
		// Context view service
B
Benjamin Pasero 已提交
368
		serviceCollection.set(IContextViewService, new SyncDescriptor(ContextViewService, [this.workbench], true));
J
Joao Moreno 已提交
369

S
SteVen Batten 已提交
370
		// Use themable context menus when custom titlebar is enabled to match custom menubar
371
		if (!isMacintosh && getTitleBarStyle(this.configurationService, this.environmentService) === 'custom') {
J
fix npe  
Johannes Rieken 已提交
372
			serviceCollection.set(IContextMenuService, new SyncDescriptor(HTMLContextMenuService, [null]));
S
SteVen Batten 已提交
373 374 375
		} else {
			serviceCollection.set(IContextMenuService, new SyncDescriptor(NativeContextMenuService));
		}
376

B
polish  
Benjamin Pasero 已提交
377
		// Contributed services
B
Benjamin Pasero 已提交
378
		const contributedServices = getServices();
E
Erich Gamma 已提交
379
		for (let contributedService of contributedServices) {
380
			serviceCollection.set(contributedService.id, contributedService.descriptor);
E
Erich Gamma 已提交
381 382
		}

B
Benjamin Pasero 已提交
383
		// TODO@Alex TODO@Sandeep this should move somewhere else
B
Benjamin Pasero 已提交
384 385 386 387 388 389 390 391
		this.instantiationService.invokeFunction(accessor => {
			const remoteAgentConnection = accessor.get(IRemoteAgentService).getConnection();
			if (remoteAgentConnection) {
				remoteAgentConnection.registerChannel('dialog', this.instantiationService.createInstance(DialogChannel));
				remoteAgentConnection.registerChannel('download', new DownloadServiceChannel());
				remoteAgentConnection.registerChannel('loglevel', new LogLevelSetterChannel(this.logService));
			}
		});
392

B
Benjamin Pasero 已提交
393 394 395 396
		// TODO@Sandeep TODO@Martin debt around cyclic dependencies
		this.instantiationService.invokeFunction(accessor => {
			const fileService = accessor.get(IFileService);
			const instantiationService = accessor.get(IInstantiationService);
B
Benjamin Pasero 已提交
397 398
			const configurationService = accessor.get(IConfigurationService) as any;
			const themeService = accessor.get(IWorkbenchThemeService) as any;
B
Benjamin Pasero 已提交
399

B
Benjamin Pasero 已提交
400 401 402 403 404 405 406
			if (typeof configurationService.acquireFileService === 'function') {
				configurationService.acquireFileService(fileService);
			}

			if (typeof configurationService.acquireInstantiationService === 'function') {
				configurationService.acquireInstantiationService(instantiationService);
			}
B
Benjamin Pasero 已提交
407

B
Benjamin Pasero 已提交
408 409 410
			if (typeof themeService.acquireFileService === 'function') {
				themeService.acquireFileService(fileService);
			}
B
Benjamin Pasero 已提交
411
		});
E
Erich Gamma 已提交
412 413
	}

B
Benjamin Pasero 已提交
414 415 416 417 418 419 420 421
	private startRegistries(): void {
		this.instantiationService.invokeFunction(accessor => {
			Registry.as<IActionBarRegistry>(ActionBarExtensions.Actionbar).start(accessor);
			Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).start(accessor);
			Registry.as<IEditorInputFactoryRegistry>(EditorExtensions.EditorInputFactories).start(accessor);
		});
	}

422 423 424 425 426 427 428
	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));
	}

B
Benjamin Pasero 已提交
429 430 431 432 433 434 435 436 437 438 439
	private registerListeners(accessor: ServicesAccessor): void {
		const lifecycleService = accessor.get(ILifecycleService);
		const storageService = accessor.get(IStorageService);
		const configurationService = accessor.get(IConfigurationService);

		// Lifecycle
		this._register(lifecycleService.onWillShutdown(event => this._onWillShutdown.fire(event)));
		this._register(lifecycleService.onShutdown(() => {
			this._onShutdown.fire();
			this.dispose();
		}));
I
isidor 已提交
440

441
		// Storage
B
Benjamin Pasero 已提交
442
		this._register(storageService.onWillSaveState(e => this.saveState(e)));
443

444
		// Configuration changes
B
Benjamin Pasero 已提交
445
		this._register(configurationService.onDidChangeConfiguration(() => this.setFontAliasing()));
446 447
	}

B
Benjamin Pasero 已提交
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466
	private fontAliasing: 'default' | 'antialiased' | 'none' | 'auto';
	private setFontAliasing() {
		const aliasing = this.configurationService.getValue<'default' | 'antialiased' | 'none' | 'auto'>(Settings.FONT_ALIASING);
		if (this.fontAliasing === aliasing) {
			return;
		}

		this.fontAliasing = aliasing;

		// Remove all
		const fontAliasingValues: (typeof aliasing)[] = ['antialiased', 'none', 'auto'];
		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 已提交
467
	private renderWorkbench(): void {
468
		if (this.state.sideBar.hidden) {
469
			addClass(this.workbench, 'nosidebar');
E
Erich Gamma 已提交
470
		}
B
Benjamin Pasero 已提交
471

472
		if (this.state.panel.hidden) {
473
			addClass(this.workbench, 'nopanel');
474
		}
B
Benjamin Pasero 已提交
475

476
		if (this.state.statusBar.hidden) {
477
			addClass(this.workbench, 'nostatusbar');
478
		}
E
Erich Gamma 已提交
479

480
		if (this.state.fullscreen) {
481
			addClass(this.workbench, 'fullscreen');
B
Benjamin Pasero 已提交
482 483
		}

484 485 486
		// Apply font aliasing
		this.setFontAliasing();

E
Erich Gamma 已提交
487
		// Create Parts
B
Benjamin Pasero 已提交
488
		this.createTitlebarPart();
E
Erich Gamma 已提交
489 490 491
		this.createActivityBarPart();
		this.createSidebarPart();
		this.createEditorPart();
492
		this.createPanelPart();
E
Erich Gamma 已提交
493 494
		this.createStatusbarPart();

495
		// Notification Handlers
496
		this.instantiationService.invokeFunction(accessor => this.createNotificationsHandlers(accessor));
497

498 499 500
		// Add Workbench to DOM
		this.container.appendChild(this.workbench);
	}
501

B
Benjamin Pasero 已提交
502
	private createTitlebarPart(): void {
503
		const titlebarContainer = this.createPart(Parts.TITLEBAR_PART, 'contentinfo', 'titlebar');
B
Benjamin Pasero 已提交
504

505
		this.parts.get(Parts.TITLEBAR_PART).create(titlebarContainer);
B
Benjamin Pasero 已提交
506 507
	}

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

511
		this.parts.get(Parts.ACTIVITYBAR_PART).create(activitybarPartContainer);
E
Erich Gamma 已提交
512 513 514
	}

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

517
		this.parts.get(Parts.SIDEBAR_PART).create(sidebarPartContainer);
E
Erich Gamma 已提交
518 519
	}

I
isidor 已提交
520
	private createPanelPart(): void {
521
		const panelPartContainer = this.createPart(Parts.PANEL_PART, 'complementary', 'panel', this.state.panel.position === Position.BOTTOM ? 'bottom' : 'right');
I
isidor 已提交
522

523
		this.parts.get(Parts.PANEL_PART).create(panelPartContainer);
I
isidor 已提交
524 525
	}

E
Erich Gamma 已提交
526
	private createEditorPart(): void {
527
		const editorContainer = this.createPart(Parts.EDITOR_PART, 'main', 'editor');
E
Erich Gamma 已提交
528

529
		this.parts.get(Parts.EDITOR_PART).create(editorContainer, { restorePreviousState: !this.hasInitialFilesToOpen() });
E
Erich Gamma 已提交
530 531 532
	}

	private createStatusbarPart(): void {
533
		const statusbarContainer = this.createPart(Parts.STATUSBAR_PART, 'contentinfo', 'statusbar');
B
Benjamin Pasero 已提交
534

535
		this.parts.get(Parts.STATUSBAR_PART).create(statusbarContainer);
B
Benjamin Pasero 已提交
536 537
	}

538
	private createPart(id: string, role: string, ...classes: string[]): HTMLElement {
B
Benjamin Pasero 已提交
539
		const part = document.createElement('div');
540
		addClasses(part, 'part', ...classes);
B
Benjamin Pasero 已提交
541 542 543
		part.id = id;
		part.setAttribute('role', role);

544 545 546 547 548
		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 已提交
549

B
Benjamin Pasero 已提交
550
		return part;
E
Erich Gamma 已提交
551 552
	}

553 554
	private createNotificationsHandlers(accessor: ServicesAccessor): void {
		const notificationService = accessor.get(INotificationService) as NotificationService;
555

556 557 558
		// Instantiate Notification components
		const notificationsCenter = this._register(this.instantiationService.createInstance(NotificationsCenter, this.workbench, notificationService.model));
		const notificationsToasts = this._register(this.instantiationService.createInstance(NotificationsToasts, this.workbench, notificationService.model));
559 560
		this._register(this.instantiationService.createInstance(NotificationsAlerts, notificationService.model));
		const notificationsStatus = this.instantiationService.createInstance(NotificationsStatus, notificationService.model);
561

562 563 564 565 566
		// Visibility
		this._register(notificationsCenter.onDidChangeVisibility(() => {
			notificationsStatus.update(notificationsCenter.isVisible);
			notificationsToasts.update(notificationsCenter.isVisible);
		}));
567

568 569 570 571
		// Layout
		this._register(this.onLayout(dimension => {
			notificationsCenter.layout(dimension);
			notificationsToasts.layout(dimension);
572 573
		}));

574
		// Register Commands
575
		registerNotificationCommands(notificationsCenter, notificationsToasts);
576 577
	}

578 579 580 581 582 583 584
	private restoreWorkbench(accessor: ServicesAccessor): Promise<void> {
		const editorService = accessor.get(IEditorService);
		const editorGroupService = accessor.get(IEditorGroupsService);
		const viewletService = accessor.get(IViewletService);
		const panelService = accessor.get(IPanelService);
		const logService = accessor.get(ILogService);

B
Benjamin Pasero 已提交
585 586 587 588
		const restorePromises: Promise<any>[] = [];

		// Restore editors
		mark('willRestoreEditors');
589
		restorePromises.push(editorGroupService.whenRestored.then(() => {
B
Benjamin Pasero 已提交
590 591 592 593 594 595 596 597 598 599

			function openEditors(editors: IResourceEditor[], editorService: IEditorService) {
				if (editors.length) {
					return editorService.openEditors(editors);
				}

				return Promise.resolve(undefined);
			}

			if (Array.isArray(this.state.editor.editorsToOpen)) {
600
				return openEditors(this.state.editor.editorsToOpen, editorService);
B
Benjamin Pasero 已提交
601 602
			}

603
			return this.state.editor.editorsToOpen.then(editors => openEditors(editors, editorService));
B
Benjamin Pasero 已提交
604 605 606 607 608
		}).then(() => mark('didRestoreEditors')));

		// Restore Sidebar
		if (this.state.sideBar.viewletToRestore) {
			mark('willRestoreViewlet');
609
			restorePromises.push(viewletService.openViewlet(this.state.sideBar.viewletToRestore)
B
Benjamin Pasero 已提交
610 611
				.then(viewlet => {
					if (!viewlet) {
612
						return viewletService.openViewlet(viewletService.getDefaultViewletId()); // fallback to default viewlet as needed
B
Benjamin Pasero 已提交
613 614 615 616
					}

					return viewlet;
				})
B
Benjamin Pasero 已提交
617 618 619 620 621 622
				.then(() => mark('didRestoreViewlet')));
		}

		// Restore Panel
		if (this.state.panel.panelToRestore) {
			mark('willRestorePanel');
623
			panelService.openPanel(this.state.panel.panelToRestore);
B
Benjamin Pasero 已提交
624 625 626 627 628 629 630 631 632 633 634 635 636
			mark('didRestorePanel');
		}

		// Restore Zen Mode
		if (this.state.zenMode.restore) {
			this.toggleZenMode(true, true);
		}

		// Restore Editor Center Mode
		if (this.state.editor.restoreCentered) {
			this.centerEditorLayout(true);
		}

637
		// Emit a warning after 10s if restore does not complete
638
		const restoreTimeoutHandle = setTimeout(() => logService.warn('Workbench did not finish loading in 10 seconds, that might be a problem that should be reported.'), 10000);
639

B
Benjamin Pasero 已提交
640 641 642 643 644 645
		let error: Error;
		return Promise.all(restorePromises)
			.then(() => clearTimeout(restoreTimeoutHandle))
			.catch(err => error = err)
			.finally(() => this.instantiationService.invokeFunction(accessor => this.whenRestored(accessor, error)));

B
Benjamin Pasero 已提交
646 647
	}

B
Benjamin Pasero 已提交
648
	private whenRestored(accessor: ServicesAccessor, error?: Error): void {
B
Benjamin Pasero 已提交
649
		const lifecycleService = accessor.get(ILifecycleService);
B
Benjamin Pasero 已提交
650

B
Benjamin Pasero 已提交
651 652 653
		this.restored = true;

		// Set lifecycle phase to `Restored`
B
Benjamin Pasero 已提交
654
		lifecycleService.phase = LifecyclePhase.Restored;
B
Benjamin Pasero 已提交
655 656 657 658 659

		// Set lifecycle phase to `Eventually` after a short delay and when
		// idle (min 2.5sec, max 5sec)
		setTimeout(() => {
			this._register(runWhenIdle(() => {
B
Benjamin Pasero 已提交
660
				lifecycleService.phase = LifecyclePhase.Eventually;
B
Benjamin Pasero 已提交
661 662 663 664 665 666 667 668 669 670 671
			}, 2500));
		}, 2500);

		if (error) {
			onUnexpectedError(error);
		}

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

672
	private saveState(e: IWillSaveStateEvent): void {
673 674 675

		// Font info
		saveFontInfo(this.storageService);
676 677
	}

678
	dispose(): void {
679
		super.dispose();
680

681
		this.disposed = true;
682 683
	}

B
Benjamin Pasero 已提交
684 685
	//#endregion

686
	//#region ILayoutService
687

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

691 692 693
	private readonly _onZenMode: Emitter<boolean> = this._register(new Emitter<boolean>());
	get onZenModeChange(): Event<boolean> { return this._onZenMode.event; }

694 695 696 697 698 699
	private readonly _onLayout = this._register(new Emitter<IDimension>());
	get onLayout(): Event<IDimension> { return this._onLayout.event; }

	private _dimension: IDimension;
	get dimension(): IDimension { return this._dimension; }

B
Benjamin Pasero 已提交
700
	private workbenchGrid: Grid<View> | WorkbenchLegacyLayout;
701 702 703 704 705 706 707 708

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

B
Benjamin Pasero 已提交
709
	private windowService: IWindowService;
710 711
	private editorService: IEditorService;
	private editorGroupService: IEditorGroupsService;
712
	private panelService: IPanelService;
713
	private viewletService: IViewletService;
B
Benjamin Pasero 已提交
714

715 716 717
	private readonly state = {
		fullscreen: false,

718 719 720 721 722 723 724 725 726 727 728 729
		menuBar: {
			visibility: undefined as MenuBarVisibility,
			toggled: false
		},

		activityBar: {
			hidden: false
		},

		sideBar: {
			hidden: false,
			position: undefined as Position,
730 731
			width: 300,
			viewletToRestore: undefined as string
732 733 734 735
		},

		editor: {
			hidden: false,
736 737 738
			centered: false,
			restoreCentered: false,
			editorsToOpen: undefined as Promise<IResourceEditor[]> | IResourceEditor[]
739 740 741 742 743 744
		},

		panel: {
			hidden: false,
			position: undefined as Position,
			height: 350,
745 746
			width: 350,
			panelToRestore: undefined as string
747 748 749 750 751 752 753 754
		},

		statusBar: {
			hidden: false
		},

		zenMode: {
			active: false,
755
			restore: false,
756 757 758 759 760 761 762 763
			transitionedToFullScreen: false,
			transitionedToCenteredEditorLayout: false,
			wasSideBarVisible: false,
			wasPanelVisible: false,
			transitionDisposeables: [] as IDisposable[]
		}
	};

764 765 766 767
	registerPart(part: Part): void {
		this.parts.set(part.getId(), part);
	}

B
Benjamin Pasero 已提交
768 769 770 771 772 773 774
	private registerLayoutListeners(accessor: ServicesAccessor): void {
		const storageService = accessor.get(IStorageService);
		const editorService = accessor.get(IEditorService);
		const configurationService = accessor.get(IConfigurationService);
		const editorGroupService = accessor.get(IEditorGroupsService);
		const titleService = accessor.get(ITitleService);
		const environmentService = accessor.get(IEnvironmentService);
775 776

		// Storage
B
Benjamin Pasero 已提交
777
		this._register(storageService.onWillSaveState(e => this.saveLayoutState(e)));
778 779

		// Restore editor if hidden and it changes
B
Benjamin Pasero 已提交
780 781
		this._register(editorService.onDidVisibleEditorsChange(() => this.setEditorHidden(false)));
		this._register(editorGroupService.onDidActivateGroup(() => this.setEditorHidden(false)));
782 783

		// Configuration changes
B
Benjamin Pasero 已提交
784
		this._register(configurationService.onDidChangeConfiguration(() => this.doUpdateLayoutConfiguration()));
785 786 787 788 789

		// Fullscreen changes
		this._register(onDidChangeFullscreen(() => this.onFullscreenChanged()));

		// Group changes
B
Benjamin Pasero 已提交
790 791
		this._register(editorGroupService.onDidAddGroup(() => this.centerEditorLayout(this.state.editor.centered)));
		this._register(editorGroupService.onDidRemoveGroup(() => this.centerEditorLayout(this.state.editor.centered)));
792 793 794 795 796

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

		// Menubar visibility changes
B
Benjamin Pasero 已提交
797 798
		if ((isWindows || isLinux) && getTitleBarStyle(configurationService, environmentService) === 'custom') {
			this._register(titleService.onMenubarVisibilityChange(visible => this.onMenubarToggled(visible)));
799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834
		}
	}

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

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

	private onFullscreenChanged(): void {
		this.state.fullscreen = isFullscreen();

		// Apply as CSS class
		if (this.state.fullscreen) {
			addClass(this.workbench, 'fullscreen');
		} else {
			removeClass(this.workbench, 'fullscreen');

			if (this.state.zenMode.transitionedToFullScreen && this.state.zenMode.active) {
				this.toggleZenMode();
			}
		}

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

	private doUpdateLayoutConfiguration(skipLayout?: boolean): void {
835

B
Benjamin Pasero 已提交
836
		// Sidebar position
837 838 839 840 841 842
		const newSidebarPositionValue = this.configurationService.getValue<string>(Settings.SIDEBAR_POSITION);
		const newSidebarPosition = (newSidebarPositionValue === 'right') ? Position.RIGHT : Position.LEFT;
		if (newSidebarPosition !== this.getSideBarPosition()) {
			this.setSideBarPosition(newSidebarPosition);
		}

B
Benjamin Pasero 已提交
843 844
		// Panel position
		this.updatePanelPosition();
845 846 847

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

B
Benjamin Pasero 已提交
848
			// Statusbar visibility
849 850 851 852 853
			const newStatusbarHiddenValue = !this.configurationService.getValue<boolean>(Settings.STATUSBAR_VISIBLE);
			if (newStatusbarHiddenValue !== this.state.statusBar.hidden) {
				this.setStatusBarHidden(newStatusbarHiddenValue, skipLayout);
			}

B
Benjamin Pasero 已提交
854
			// Activitybar visibility
855 856 857 858 859 860
			const newActivityBarHiddenValue = !this.configurationService.getValue<boolean>(Settings.ACTIVITYBAR_VISIBLE);
			if (newActivityBarHiddenValue !== this.state.activityBar.hidden) {
				this.setActivityBarHidden(newActivityBarHiddenValue, skipLayout);
			}
		}

B
Benjamin Pasero 已提交
861
		// Menubar visibility
862 863 864 865
		const newMenubarVisibility = this.configurationService.getValue<MenuBarVisibility>(Settings.MENUBAR_VISIBLE);
		this.setMenubarVisibility(newMenubarVisibility, !!skipLayout);
	}

B
Benjamin Pasero 已提交
866
	private setSideBarPosition(position: Position): void {
867
		const activityBar = this.parts.get(Parts.ACTIVITYBAR_PART);
868
		const sideBar = this.parts.get(Parts.SIDEBAR_PART);
B
Benjamin Pasero 已提交
869 870 871 872 873 874 875 876 877 878 879
		const wasHidden = this.state.sideBar.hidden;

		if (this.state.sideBar.hidden) {
			this.setSideBarHidden(false, true /* Skip Layout */);
		}

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

		// Adjust CSS
880
		removeClass(activityBar.getContainer(), oldPositionValue);
881
		removeClass(sideBar.getContainer(), oldPositionValue);
882
		addClass(activityBar.getContainer(), newPositionValue);
883
		addClass(sideBar.getContainer(), newPositionValue);
B
Benjamin Pasero 已提交
884 885

		// Update Styles
886
		activityBar.updateStyles();
887
		sideBar.updateStyles();
B
Benjamin Pasero 已提交
888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907

		// Layout
		if (this.workbenchGrid instanceof Grid) {
			if (!wasHidden) {
				this.state.sideBar.width = this.workbenchGrid.getViewSize(this.sideBarPartView);
			}

			this.workbenchGrid.removeView(this.sideBarPartView);
			this.workbenchGrid.removeView(this.activityBarPartView);

			if (!this.state.panel.hidden && this.state.panel.position === Position.BOTTOM) {
				this.workbenchGrid.removeView(this.panelPartView);
			}

			this.layout();
		} else {
			this.workbenchGrid.layout();
		}
	}

B
Benjamin Pasero 已提交
908 909 910 911 912 913
	private initLayoutState(accessor: ServicesAccessor): void {
		const configurationService = accessor.get(IConfigurationService);
		const storageService = accessor.get(IStorageService);
		const lifecycleService = accessor.get(ILifecycleService);
		const contextService = accessor.get(IWorkspaceContextService);
		const environmentService = accessor.get(IEnvironmentService);
914

B
Benjamin Pasero 已提交
915
		this.windowService = accessor.get(IWindowService);
916 917
		this.editorService = accessor.get(IEditorService);
		this.editorGroupService = accessor.get(IEditorGroupsService);
918
		this.panelService = accessor.get(IPanelService);
B
Benjamin Pasero 已提交
919

920 921
		// Fullscreen
		this.state.fullscreen = isFullscreen();
922

923
		// Menubar visibility
B
Benjamin Pasero 已提交
924
		this.state.menuBar.visibility = configurationService.getValue<MenuBarVisibility>(Settings.MENUBAR_VISIBLE);
925 926

		// Activity bar visibility
B
Benjamin Pasero 已提交
927
		this.state.activityBar.hidden = !configurationService.getValue<string>(Settings.ACTIVITYBAR_VISIBLE);
928

929
		// Sidebar visibility
B
Benjamin Pasero 已提交
930
		this.state.sideBar.hidden = storageService.getBoolean(Storage.SIDEBAR_HIDDEN, StorageScope.WORKSPACE, contextService.getWorkbenchState() === WorkbenchState.EMPTY);
931

932
		// Sidebar position
B
Benjamin Pasero 已提交
933
		this.state.sideBar.position = (configurationService.getValue<string>(Settings.SIDEBAR_POSITION) === 'right') ? Position.RIGHT : Position.LEFT;
934 935 936 937 938 939 940

		// 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;
B
Benjamin Pasero 已提交
941 942
			if (!environmentService.isBuilt || lifecycleService.startupKind === StartupKind.ReloadedWindow) {
				viewletToRestore = storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE, viewletRegistry.getDefaultViewletId());
943 944 945 946 947 948 949 950 951
			} 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
			}
952 953
		}

954
		// Editor centered layout
B
Benjamin Pasero 已提交
955
		this.state.editor.restoreCentered = storageService.getBoolean(Storage.CENTERED_LAYOUT_ENABLED, StorageScope.WORKSPACE, false);
956

957
		// Editors to open
B
Benjamin Pasero 已提交
958
		this.state.editor.editorsToOpen = this.resolveEditorsToOpen(accessor);
959 960

		// Panel visibility
B
Benjamin Pasero 已提交
961
		this.state.panel.hidden = storageService.getBoolean(Storage.PANEL_HIDDEN, StorageScope.WORKSPACE, true);
962 963

		// Panel position
B
Benjamin Pasero 已提交
964
		this.updatePanelPosition();
965

966 967 968 969
		// Panel to restore
		if (!this.state.panel.hidden) {
			const panelRegistry = Registry.as<PanelRegistry>(PanelExtensions.Panels);

B
Benjamin Pasero 已提交
970
			let panelToRestore = storageService.get(PanelPart.activePanelSettingsKey, StorageScope.WORKSPACE, panelRegistry.getDefaultPanelId());
971 972 973 974 975 976 977 978 979 980
			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
			}
		}
981 982

		// Statusbar visibility
B
Benjamin Pasero 已提交
983
		this.state.statusBar.hidden = !configurationService.getValue<string>(Settings.STATUSBAR_VISIBLE);
984

985
		// Zen mode enablement
B
Benjamin Pasero 已提交
986
		this.state.zenMode.restore = storageService.getBoolean(Storage.ZEN_MODE_ENABLED, StorageScope.WORKSPACE, false) && configurationService.getValue(Settings.ZEN_MODE_RESTORE);
987 988
	}

B
Benjamin Pasero 已提交
989 990 991 992 993 994
	private resolveEditorsToOpen(accessor: ServicesAccessor): Promise<IResourceEditor[]> | IResourceEditor[] {
		const configuration = accessor.get(IWindowService).getConfiguration();
		const configurationService = accessor.get(IConfigurationService);
		const contextService = accessor.get(IWorkspaceContextService);
		const editorGroupService = accessor.get(IEditorGroupsService);
		const backupFileService = accessor.get(IBackupFileService);
995 996 997 998 999

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

			// Files to diff is exclusive
B
Benjamin Pasero 已提交
1000
			const filesToDiff = this.toInputs(configuration.filesToDiff, false);
1001 1002 1003 1004 1005 1006 1007 1008 1009
			if (filesToDiff && filesToDiff.length === 2) {
				return [<IResourceDiffInput>{
					leftResource: filesToDiff[0].resource,
					rightResource: filesToDiff[1].resource,
					options: { pinned: true },
					forceFile: true
				}];
			}

B
Benjamin Pasero 已提交
1010 1011
			const filesToCreate = this.toInputs(configuration.filesToCreate, true);
			const filesToOpen = this.toInputs(configuration.filesToOpen, false);
1012 1013 1014 1015 1016 1017

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

		// Empty workbench
B
Benjamin Pasero 已提交
1018 1019
		else if (contextService.getWorkbenchState() === WorkbenchState.EMPTY && configurationService.inspect('workbench.startupEditor').value === 'newUntitledFile') {
			const isEmpty = editorGroupService.count === 1 && editorGroupService.activeGroup.count === 0;
1020 1021 1022 1023
			if (!isEmpty) {
				return []; // do not open any empty untitled file if we restored editors from previous session
			}

B
Benjamin Pasero 已提交
1024
			return backupFileService.hasBackups().then(hasBackups => {
1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035
				if (hasBackups) {
					return []; // do not open any empty untitled file if we have backups to restore
				}

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

		return [];
	}

1036
	private toInputs(paths: IPath[] | undefined, isNew: boolean): Array<IResourceInput | IUntitledResourceInput> {
1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060
		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;
		});
	}

B
Benjamin Pasero 已提交
1061
	private updatePanelPosition() {
1062
		const defaultPanelPosition = this.configurationService.getValue<string>(Settings.PANEL_POSITION);
1063
		const panelPosition = this.storageService.get(Storage.PANEL_POSITION, StorageScope.WORKSPACE, defaultPanelPosition);
1064 1065 1066 1067

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

B
Benjamin Pasero 已提交
1068
	isRestored(): boolean {
1069
		return this.restored;
1070
	}
1071

1072 1073 1074 1075 1076
	hasFocus(part: Parts): boolean {
		const activeElement = document.activeElement;
		if (!activeElement) {
			return false;
		}
1077

1078
		const container = this.getContainer(part);
1079

1080
		return isAncestor(activeElement, container);
1081
	}
1082

1083
	getContainer(part: Parts): HTMLElement | null {
1084 1085
		switch (part) {
			case Parts.TITLEBAR_PART:
1086
				return this.parts.get(Parts.TITLEBAR_PART).getContainer();
1087
			case Parts.ACTIVITYBAR_PART:
1088
				return this.parts.get(Parts.ACTIVITYBAR_PART).getContainer();
1089
			case Parts.SIDEBAR_PART:
1090
				return this.parts.get(Parts.SIDEBAR_PART).getContainer();
1091
			case Parts.PANEL_PART:
1092
				return this.parts.get(Parts.PANEL_PART).getContainer();
1093
			case Parts.EDITOR_PART:
1094
				return this.parts.get(Parts.EDITOR_PART).getContainer();
1095
			case Parts.STATUSBAR_PART:
1096
				return this.parts.get(Parts.STATUSBAR_PART).getContainer();
1097
		}
1098

1099
		return null;
1100
	}
1101

1102 1103 1104
	isVisible(part: Parts): boolean {
		switch (part) {
			case Parts.TITLEBAR_PART:
1105
				if (getTitleBarStyle(this.configurationService, this.environmentService) === 'native') {
1106
					return false;
1107
				} else if (!this.state.fullscreen) {
1108 1109 1110
					return true;
				} else if (isMacintosh) {
					return false;
1111
				} else if (this.state.menuBar.visibility === 'visible') {
1112
					return true;
1113 1114
				} else if (this.state.menuBar.visibility === 'toggle' || this.state.menuBar.visibility === 'default') {
					return this.state.menuBar.toggled;
1115 1116 1117
				}

				return false;
1118
			case Parts.SIDEBAR_PART:
1119
				return !this.state.sideBar.hidden;
1120
			case Parts.PANEL_PART:
1121
				return !this.state.panel.hidden;
1122
			case Parts.STATUSBAR_PART:
1123
				return !this.state.statusBar.hidden;
1124
			case Parts.ACTIVITYBAR_PART:
1125
				return !this.state.activityBar.hidden;
1126
			case Parts.EDITOR_PART:
1127
				return this.workbenchGrid instanceof Grid ? !this.state.editor.hidden : true;
E
Erich Gamma 已提交
1128
		}
1129

1130
		return true; // any other part cannot be hidden
E
Erich Gamma 已提交
1131 1132
	}

1133 1134 1135
	getTitleBarOffset(): number {
		let offset = 0;
		if (this.isVisible(Parts.TITLEBAR_PART)) {
S
SteVen Batten 已提交
1136
			if (this.workbenchGrid instanceof Grid) {
1137
				offset = this.parts.get(Parts.TITLEBAR_PART).maximumHeight;
S
SteVen Batten 已提交
1138 1139 1140
			} else {
				offset = this.workbenchGrid.partLayoutInfo.titlebar.height;

1141
				if (isMacintosh || this.state.menuBar.visibility === 'hidden') {
B
Benjamin Pasero 已提交
1142 1143
					offset /= getZoomFactor();
				}
1144
			}
E
Erich Gamma 已提交
1145
		}
1146 1147

		return offset;
E
Erich Gamma 已提交
1148
	}
1149

1150 1151
	getWorkbenchElement(): HTMLElement {
		return this.workbench;
1152
	}
1153

I
isidor 已提交
1154
	toggleZenMode(skipLayout?: boolean, restoring = false): void {
1155 1156
		this.state.zenMode.active = !this.state.zenMode.active;
		this.state.zenMode.transitionDisposeables = dispose(this.state.zenMode.transitionDisposeables);
1157

B
Benjamin Pasero 已提交
1158 1159
		const setLineNumbers = (lineNumbers: any) => this.editorService.visibleTextEditorWidgets.forEach(editor => editor.updateOptions({ lineNumbers }));

1160 1161
		// 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)
1162
		let toggleFullScreen = false;
1163 1164

		// Zen Mode Active
1165 1166 1167 1168 1169 1170 1171 1172 1173
		if (this.state.zenMode.active) {
			const config: {
				fullScreen: boolean;
				centerLayout: boolean;
				hideTabs: boolean;
				hideActivityBar: boolean;
				hideStatusBar: boolean;
				hideLineNumbers: boolean;
			} = this.configurationService.getValue('zenMode');
1174

1175
			toggleFullScreen = !this.state.fullscreen && config.fullScreen;
B
Benjamin Pasero 已提交
1176

1177 1178 1179 1180
			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);
1181

1182 1183
			this.setPanelHidden(true, true);
			this.setSideBarHidden(true, true);
I
isidor 已提交
1184

1185 1186 1187
			if (config.hideActivityBar) {
				this.setActivityBarHidden(true, true);
			}
1188

I
isidor 已提交
1189
			if (config.hideStatusBar) {
I
isidor 已提交
1190 1191
				this.setStatusBarHidden(true, true);
			}
1192

I
isidor 已提交
1193 1194
			if (config.hideLineNumbers) {
				setLineNumbers('off');
1195
				this.state.zenMode.transitionDisposeables.push(this.editorService.onDidVisibleEditorsChange(() => setLineNumbers('off')));
I
isidor 已提交
1196 1197
			}

1198 1199
			if (config.hideTabs && this.editorGroupService.partOptions.showTabs) {
				this.state.zenMode.transitionDisposeables.push(this.editorGroupService.enforcePartOptions({ showTabs: false }));
I
isidor 已提交
1200
			}
1201 1202 1203 1204

			if (config.centerLayout) {
				this.centerEditorLayout(true, true);
			}
1205 1206 1207 1208
		}

		// Zen Mode Inactive
		else {
1209
			if (this.state.zenMode.wasPanelVisible) {
1210
				this.setPanelHidden(false, true);
1211
			}
1212

1213
			if (this.state.zenMode.wasSideBarVisible) {
1214
				this.setSideBarHidden(false, true);
1215
			}
1216

1217
			if (this.state.zenMode.transitionedToCenteredEditorLayout) {
1218 1219
				this.centerEditorLayout(false, true);
			}
B
Benjamin Pasero 已提交
1220

I
isidor 已提交
1221
			setLineNumbers(this.configurationService.getValue('editor.lineNumbers'));
1222

1223
			// Status bar and activity bar visibility come from settings -> update their visibility.
1224
			this.doUpdateLayoutConfiguration(true);
1225

B
Benjamin Pasero 已提交
1226
			this.editorGroupService.activeGroup.focus();
1227

1228
			toggleFullScreen = this.state.zenMode.transitionedToFullScreen && this.state.fullscreen;
I
isidor 已提交
1229
		}
1230

I
isidor 已提交
1231
		if (!skipLayout) {
1232
			this.layout();
I
isidor 已提交
1233
		}
1234

1235
		if (toggleFullScreen) {
1236
			this.windowService.toggleFullScreen();
1237
		}
1238 1239 1240

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

1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263
	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 {
1264
		const titleBar = this.parts.get(Parts.TITLEBAR_PART);
1265
		const editorPart = this.parts.get(Parts.EDITOR_PART);
1266
		const activityBar = this.parts.get(Parts.ACTIVITYBAR_PART);
1267
		const panelPart = this.parts.get(Parts.PANEL_PART);
1268
		const sideBar = this.parts.get(Parts.SIDEBAR_PART);
1269
		const statusBar = this.parts.get(Parts.STATUSBAR_PART);
1270

1271 1272 1273
		if (this.configurationService.getValue('workbench.useExperimentalGridLayout')) {

			// Create view wrappers for all parts
1274 1275
			this.titleBarPartView = new View(titleBar);
			this.sideBarPartView = new View(sideBar);
1276
			this.activityBarPartView = new View(activityBar);
1277
			this.editorPartView = new View(editorPart);
1278
			this.panelPartView = new View(panelPart);
1279
			this.statusBarPartView = new View(statusBar);
1280 1281 1282 1283 1284 1285

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

			this.workbench.prepend(this.workbenchGrid.element);
		} else {
			this.workbenchGrid = this.instantiationService.createInstance(
B
Benjamin Pasero 已提交
1286
				WorkbenchLegacyLayout,
1287 1288 1289
				this.container,
				this.workbench,
				{
1290
					titlebar: titleBar,
1291
					activitybar: activityBar,
1292
					editor: editorPart,
1293
					sidebar: sideBar,
1294
					panel: panelPart,
1295
					statusbar: statusBar,
1296
				}
1297 1298 1299 1300 1301 1302
			);
		}
	}

	layout(options?: ILayoutOptions): void {
		if (!this.disposed) {
1303 1304
			this._dimension = getClientArea(this.container);

1305 1306
			if (this.workbenchGrid instanceof Grid) {
				position(this.workbench, 0, 0, 0, 0, 'relative');
1307
				size(this.workbench, this._dimension.width, this._dimension.height);
1308

1309 1310
				// Layout the grid widget
				this.workbenchGrid.layout(this._dimension.width, this._dimension.height);
1311

1312
				// Layout grid views
1313 1314 1315 1316
				this.layoutGrid();
			} else {
				this.workbenchGrid.layout(options);
			}
1317 1318 1319

			// Emit as event
			this._onLayout.fire(this._dimension);
1320 1321 1322 1323
		}
	}

	private layoutGrid(): void {
S
SteVen Batten 已提交
1324
		if (!(this.workbenchGrid instanceof Grid)) {
1325 1326 1327
			return;
		}

S
SteVen Batten 已提交
1328
		let panelInGrid = this.workbenchGrid.hasView(this.panelPartView);
1329 1330 1331 1332
		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);
1333

S
SteVen Batten 已提交
1334 1335
		// Add parts to grid
		if (!statusBarInGrid) {
1336
			this.workbenchGrid.addView(this.statusBarPartView, Sizing.Split, this.editorPartView, Direction.Down);
S
SteVen Batten 已提交
1337 1338 1339
			statusBarInGrid = true;
		}

1340 1341
		if (!titlebarInGrid && getTitleBarStyle(this.configurationService, this.environmentService) === 'custom') {
			this.workbenchGrid.addView(this.titleBarPartView, Sizing.Split, this.editorPartView, Direction.Up);
S
SteVen Batten 已提交
1342 1343
			titlebarInGrid = true;
		}
S
SteVen Batten 已提交
1344

S
SteVen Batten 已提交
1345
		if (!activityBarInGrid) {
1346
			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 已提交
1347 1348
			activityBarInGrid = true;
		}
S
SteVen Batten 已提交
1349

S
SteVen Batten 已提交
1350
		if (!sidebarInGrid) {
1351
			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 已提交
1352 1353
			sidebarInGrid = true;
		}
S
SteVen Batten 已提交
1354

S
SteVen Batten 已提交
1355
		if (!panelInGrid) {
1356
			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 已提交
1357
			panelInGrid = true;
S
SteVen Batten 已提交
1358 1359
		}

S
SteVen Batten 已提交
1360
		// Hide parts
1361
		if (this.state.panel.hidden) {
S
SteVen Batten 已提交
1362 1363 1364
			this.panelPartView.hide();
		}

1365 1366
		if (this.state.statusBar.hidden) {
			this.statusBarPartView.hide();
S
SteVen Batten 已提交
1367 1368 1369
		}

		if (!this.isVisible(Parts.TITLEBAR_PART)) {
1370
			this.titleBarPartView.hide();
S
SteVen Batten 已提交
1371 1372
		}

1373 1374
		if (this.state.activityBar.hidden) {
			this.activityBarPartView.hide();
S
SteVen Batten 已提交
1375 1376
		}

1377 1378
		if (this.state.sideBar.hidden) {
			this.sideBarPartView.hide();
S
SteVen Batten 已提交
1379 1380
		}

1381
		if (this.state.editor.hidden) {
S
SteVen Batten 已提交
1382 1383 1384
			this.editorPartView.hide();
		}

S
SteVen Batten 已提交
1385
		// Show visible parts
1386
		if (!this.state.editor.hidden) {
S
SteVen Batten 已提交
1387 1388 1389
			this.editorPartView.show();
		}

1390 1391
		if (!this.state.statusBar.hidden) {
			this.statusBarPartView.show();
S
SteVen Batten 已提交
1392
		}
S
SteVen Batten 已提交
1393

S
SteVen Batten 已提交
1394
		if (this.isVisible(Parts.TITLEBAR_PART)) {
1395
			this.titleBarPartView.show();
S
SteVen Batten 已提交
1396 1397
		}

1398 1399
		if (!this.state.activityBar.hidden) {
			this.activityBarPartView.show();
S
SteVen Batten 已提交
1400
		}
S
SteVen Batten 已提交
1401

1402 1403
		if (!this.state.sideBar.hidden) {
			this.sideBarPartView.show();
S
SteVen Batten 已提交
1404 1405
		}

1406
		if (!this.state.panel.hidden) {
S
SteVen Batten 已提交
1407
			this.panelPartView.show();
S
SteVen Batten 已提交
1408 1409 1410
		}
	}

B
Benjamin Pasero 已提交
1411 1412 1413 1414
	private getPanelDimension(position: Position): number | undefined {
		return position === Position.BOTTOM ? this.state.panel.height : this.state.panel.width;
	}

1415
	isEditorLayoutCentered(): boolean {
1416
		return this.state.editor.centered;
S
SrTobi 已提交
1417 1418
	}

1419
	centerEditorLayout(active: boolean, skipLayout?: boolean): void {
1420 1421
		this.state.editor.centered = active;

B
Benjamin Pasero 已提交
1422 1423
		this.storageService.store(Storage.CENTERED_LAYOUT_ENABLED, active, StorageScope.WORKSPACE);

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

1429
		// Enter Centered Editor Layout
1430 1431
		if (this.editorGroupService.isLayoutCentered() !== smartActive) {
			this.editorGroupService.centerLayout(smartActive);
1432

1433 1434 1435
			if (!skipLayout) {
				this.layout();
			}
1436
		}
S
SrTobi 已提交
1437 1438
	}

1439
	resizePart(part: Parts, sizeChange: number): void {
S
SteVen Batten 已提交
1440
		let view: View;
1441 1442
		switch (part) {
			case Parts.SIDEBAR_PART:
1443
				view = this.sideBarPartView;
1444
			case Parts.PANEL_PART:
S
SteVen Batten 已提交
1445
				view = this.panelPartView;
1446
			case Parts.EDITOR_PART:
S
SteVen Batten 已提交
1447 1448
				view = this.editorPartView;
				if (this.workbenchGrid instanceof Grid) {
1449 1450 1451 1452
					this.workbenchGrid.resizeView(view, this.workbenchGrid.getViewSize(view) + sizeChange);
				} else {
					this.workbenchGrid.resizePart(part, sizeChange);
				}
1453 1454
				break;
			default:
B
Benjamin Pasero 已提交
1455
				return; // Cannot resize other parts
1456 1457 1458
		}
	}

1459
	setActivityBarHidden(hidden: boolean, skipLayout?: boolean): void {
1460
		this.state.activityBar.hidden = hidden;
1461

1462 1463
		// Layout
		if (!skipLayout) {
S
SteVen Batten 已提交
1464
			if (this.workbenchGrid instanceof Grid) {
S
SteVen Batten 已提交
1465
				this.layout();
1466 1467 1468
			} else {
				this.workbenchGrid.layout();
			}
1469
		}
1470
	}
1471

S
SteVen Batten 已提交
1472
	setEditorHidden(hidden: boolean, skipLayout?: boolean): void {
1473
		if (!(this.workbenchGrid instanceof Grid) || hidden === this.state.editor.hidden) {
S
SteVen Batten 已提交
1474 1475 1476
			return;
		}

1477
		this.state.editor.hidden = hidden;
S
SteVen Batten 已提交
1478 1479

		// The editor and the panel cannot be hidden at the same time
1480
		if (this.state.editor.hidden && this.state.panel.hidden) {
S
SteVen Batten 已提交
1481 1482 1483 1484 1485 1486 1487 1488
			this.setPanelHidden(false, true);
		}

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

1489
	setSideBarHidden(hidden: boolean, skipLayout?: boolean): void {
1490
		this.state.sideBar.hidden = hidden;
1491 1492 1493

		// Adjust CSS
		if (hidden) {
1494
			addClass(this.workbench, 'nosidebar');
1495
		} else {
1496
			removeClass(this.workbench, 'nosidebar');
1497 1498
		}

1499
		// If sidebar becomes hidden, also hide the current active Viewlet if any
1500 1501
		if (hidden && this.viewletService.getActiveViewlet()) {
			this.viewletService.hideActiveViewlet();
1502 1503

			// Pass Focus to Editor or Panel if Sidebar is now hidden
1504
			const activePanel = this.panelService.getActivePanel();
1505 1506 1507 1508 1509
			if (this.hasFocus(Parts.PANEL_PART) && activePanel) {
				activePanel.focus();
			} else {
				this.editorGroupService.activeGroup.focus();
			}
1510 1511 1512
		}

		// If sidebar becomes visible, show last active Viewlet or default viewlet
1513 1514
		else if (!hidden && !this.viewletService.getActiveViewlet()) {
			const viewletToOpen = this.viewletService.getLastActiveViewletId();
1515
			if (viewletToOpen) {
1516
				const viewlet = this.viewletService.openViewlet(viewletToOpen, true);
1517
				if (!viewlet) {
1518
					this.viewletService.openViewlet(this.viewletService.getDefaultViewletId(), true);
1519
				}
1520
			}
1521 1522
		}

1523 1524 1525
		// Remember in settings
		const defaultHidden = this.contextService.getWorkbenchState() === WorkbenchState.EMPTY;
		if (hidden !== defaultHidden) {
1526
			this.storageService.store(Storage.SIDEBAR_HIDDEN, hidden ? 'true' : 'false', StorageScope.WORKSPACE);
1527
		} else {
1528
			this.storageService.remove(Storage.SIDEBAR_HIDDEN, StorageScope.WORKSPACE);
1529
		}
1530

1531 1532
		// Layout
		if (!skipLayout) {
S
SteVen Batten 已提交
1533
			if (this.workbenchGrid instanceof Grid) {
S
SteVen Batten 已提交
1534
				this.layout();
1535 1536 1537
			} else {
				this.workbenchGrid.layout();
			}
1538
		}
1539
	}
1540

1541
	setPanelHidden(hidden: boolean, skipLayout?: boolean): void {
1542
		this.state.panel.hidden = hidden;
1543 1544 1545

		// Adjust CSS
		if (hidden) {
1546
			addClass(this.workbench, 'nopanel');
1547
		} else {
1548
			removeClass(this.workbench, 'nopanel');
1549 1550 1551
		}

		// If panel part becomes hidden, also hide the current active panel if any
1552 1553
		if (hidden && this.panelService.getActivePanel()) {
			this.panelService.hideActivePanel();
1554
			this.editorGroupService.activeGroup.focus(); // Pass focus to editor group if panel part is now hidden
1555 1556 1557
		}

		// If panel part becomes visible, show last active panel or default panel
1558 1559
		else if (!hidden && !this.panelService.getActivePanel()) {
			const panelToOpen = this.panelService.getLastActivePanelId();
1560
			if (panelToOpen) {
I
isidor 已提交
1561
				const focus = !skipLayout;
1562
				this.panelService.openPanel(panelToOpen, focus);
1563 1564 1565
			}
		}

1566 1567
		// Remember in settings
		if (!hidden) {
1568
			this.storageService.store(Storage.PANEL_HIDDEN, 'false', StorageScope.WORKSPACE);
1569
		} else {
1570
			this.storageService.remove(Storage.PANEL_HIDDEN, StorageScope.WORKSPACE);
1571
		}
1572

1573 1574
		// The editor and panel cannot be hidden at the same time
		if (hidden && this.state.editor.hidden) {
S
SteVen Batten 已提交
1575 1576 1577
			this.setEditorHidden(false, true);
		}

1578 1579
		// Layout
		if (!skipLayout) {
S
SteVen Batten 已提交
1580
			if (this.workbenchGrid instanceof Grid) {
S
SteVen Batten 已提交
1581
				this.layout();
1582 1583 1584
			} else {
				this.workbenchGrid.layout();
			}
1585
		}
1586 1587 1588
	}

	toggleMaximizedPanel(): void {
S
SteVen Batten 已提交
1589 1590
		if (this.workbenchGrid instanceof Grid) {
			this.workbenchGrid.maximizeViewSize(this.panelPartView);
1591 1592 1593
		} else {
			this.workbenchGrid.layout({ toggleMaximizedPanel: true, source: Parts.PANEL_PART });
		}
1594 1595 1596
	}

	isPanelMaximized(): boolean {
S
SteVen Batten 已提交
1597
		if (this.workbenchGrid instanceof Grid) {
1598
			try {
1599
				return this.workbenchGrid.getViewSize2(this.panelPartView).height === this.parts.get(Parts.PANEL_PART).maximumHeight;
1600 1601 1602 1603 1604 1605
			} catch (e) {
				return false;
			}
		} else {
			return this.workbenchGrid.isPanelMaximized();
		}
1606 1607 1608
	}

	getSideBarPosition(): Position {
1609
		return this.state.sideBar.position;
1610 1611
	}

S
SteVen Batten 已提交
1612
	setMenubarVisibility(visibility: MenuBarVisibility, skipLayout: boolean): void {
1613 1614
		if (this.state.menuBar.visibility !== visibility) {
			this.state.menuBar.visibility = visibility;
1615

1616
			// Layout
S
SteVen Batten 已提交
1617
			if (!skipLayout) {
S
SteVen Batten 已提交
1618
				if (this.workbenchGrid instanceof Grid) {
1619
					const dimensions = getClientArea(this.container);
1620 1621 1622 1623
					this.workbenchGrid.layout(dimensions.width, dimensions.height);
				} else {
					this.workbenchGrid.layout();
				}
S
SteVen Batten 已提交
1624
			}
1625 1626 1627
		}
	}

S
SteVen Batten 已提交
1628
	getMenubarVisibility(): MenuBarVisibility {
1629
		return this.state.menuBar.visibility;
S
SteVen Batten 已提交
1630 1631
	}

1632
	getPanelPosition(): Position {
1633
		return this.state.panel.position;
1634 1635
	}

1636
	setPanelPosition(position: Position): void {
1637
		const panelPart = this.parts.get(Parts.PANEL_PART);
1638
		const wasHidden = this.state.panel.hidden;
1639

1640
		if (this.state.panel.hidden) {
1641
			this.setPanelHidden(false, true /* Skip Layout */);
1642
		} else {
1643
			this.savePanelDimension();
1644
		}
1645

1646
		const newPositionValue = (position === Position.BOTTOM) ? 'bottom' : 'right';
1647 1648
		const oldPositionValue = (this.state.panel.position === Position.BOTTOM) ? 'bottom' : 'right';
		this.state.panel.position = position;
B
Benjamin Pasero 已提交
1649 1650 1651 1652 1653 1654 1655 1656 1657 1658

		function positionToString(position: Position): string {
			switch (position) {
				case Position.LEFT: return 'left';
				case Position.RIGHT: return 'right';
				case Position.BOTTOM: return 'bottom';
			}
		}

		this.storageService.store(Storage.PANEL_POSITION, positionToString(this.state.panel.position), StorageScope.WORKSPACE);
1659

1660
		// Adjust CSS
1661 1662
		removeClass(panelPart.getContainer(), oldPositionValue);
		addClass(panelPart.getContainer(), newPositionValue);
1663

1664
		// Update Styles
1665
		panelPart.updateStyles();
1666 1667

		// Layout
S
SteVen Batten 已提交
1668 1669
		if (this.workbenchGrid instanceof Grid) {
			if (!wasHidden) {
1670
				this.savePanelDimension();
1671
			}
1672

1673
			this.workbenchGrid.removeView(this.panelPartView);
S
SteVen Batten 已提交
1674
			this.layout();
1675 1676 1677 1678
		} else {
			this.workbenchGrid.layout();
		}
	}
1679

1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691
	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);
		}
	}

1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707
	private saveLayoutState(e: IWillSaveStateEvent): void {

		// Zen Mode
		if (this.state.zenMode.active) {
			this.storageService.store(Storage.ZEN_MODE_ENABLED, true, StorageScope.WORKSPACE);
		} else {
			this.storageService.remove(Storage.ZEN_MODE_ENABLED, StorageScope.WORKSPACE);
		}

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

1708
	//#endregion
1709
}