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

'use strict';

import 'vs/css!./media/workbench';
9

10
import { localize } from 'vs/nls';
11
import { TPromise } from 'vs/base/common/winjs.base';
12
import { IDisposable, dispose, toDisposable, Disposable } from 'vs/base/common/lifecycle';
M
Matt Bierner 已提交
13
import { Event, Emitter } from 'vs/base/common/event';
14
import * as DOM from 'vs/base/browser/dom';
B
Benjamin Pasero 已提交
15
import { Builder, $ } from 'vs/base/browser/builder';
16
import { RunOnceScheduler } from 'vs/base/common/async';
17
import * as browser from 'vs/base/browser/browser';
J
Johannes Rieken 已提交
18
import * as perf from 'vs/base/common/performance';
19
import * as errors from 'vs/base/common/errors';
20
import { BackupFileService } from 'vs/workbench/services/backup/node/backupFileService';
21
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
22
import { Registry } from 'vs/platform/registry/common/platform';
B
Benjamin Pasero 已提交
23
import { isWindows, isLinux, isMacintosh } from 'vs/base/common/platform';
B
Benjamin Pasero 已提交
24
import { Position as EditorPosition, IResourceDiffInput, IUntitledResourceInput, IEditor, IResourceInput } from 'vs/platform/editor/common/editor';
J
Johannes Rieken 已提交
25
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
26
import { IEditorInputFactoryRegistry, Extensions as EditorExtensions, TextCompareEditorVisibleContext, TEXT_DIFF_EDITOR_ID, EditorsVisibleContext, InEditorZenModeContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext } from 'vs/workbench/common/editor';
27
import { HistoryService } from 'vs/workbench/services/history/electron-browser/history';
J
Johannes Rieken 已提交
28 29 30 31
import { ActivitybarPart } from 'vs/workbench/browser/parts/activitybar/activitybarPart';
import { SidebarPart } from 'vs/workbench/browser/parts/sidebar/sidebarPart';
import { PanelPart } from 'vs/workbench/browser/parts/panel/panelPart';
import { StatusbarPart } from 'vs/workbench/browser/parts/statusbar/statusbarPart';
B
Benjamin Pasero 已提交
32 33
import { TitlebarPart } from 'vs/workbench/browser/parts/titlebar/titlebarPart';
import { WorkbenchLayout } from 'vs/workbench/browser/layout';
34
import { IActionBarRegistry, Extensions as ActionBarExtensions } from 'vs/workbench/browser/actions';
J
Johannes Rieken 已提交
35 36
import { PanelRegistry, Extensions as PanelExtensions } from 'vs/workbench/browser/panel';
import { QuickOpenController } from 'vs/workbench/browser/parts/quickopen/quickOpenController';
C
Christof Marti 已提交
37 38
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { QuickInputService } from 'vs/workbench/browser/parts/quickinput/quickInput';
J
Johannes Rieken 已提交
39
import { getServices } from 'vs/platform/instantiation/common/extensions';
40
import { Position, Parts, IPartService, ILayoutOptions, IDimension } from 'vs/workbench/services/part/common/partService';
41
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
J
Johannes Rieken 已提交
42 43 44 45
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { ContextMenuService } from 'vs/workbench/services/contextview/electron-browser/contextmenuService';
import { WorkbenchKeybindingService } from 'vs/workbench/services/keybinding/electron-browser/keybindingService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
46
import { WorkspaceService, DefaultConfigurationExportHelper } from 'vs/workbench/services/configuration/node/configurationService';
47 48
import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing';
import { JSONEditingService } from 'vs/workbench/services/configuration/node/jsonEditingService';
J
Johannes Rieken 已提交
49 50
import { ContextKeyService } from 'vs/platform/contextkey/browser/contextKeyService';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
51
import { IKeybindingEditingService, KeybindingsEditingService } from 'vs/workbench/services/keybinding/common/keybindingEditing';
52
import { RawContextKey, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
I
isidor 已提交
53
import { IActivityService } from 'vs/workbench/services/activity/common/activity';
B
Benjamin Pasero 已提交
54
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
P
Pine Wu 已提交
55
import { ViewletService } from 'vs/workbench/services/viewlet/browser/viewletService';
56
import { RemoteFileService } from 'vs/workbench/services/files/electron-browser/remoteFileService';
J
Johannes Rieken 已提交
57 58
import { IFileService } from 'vs/platform/files/common/files';
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
59
import { ConfigurationResolverService } from 'vs/workbench/services/configurationResolver/electron-browser/configurationResolverService';
J
Johannes Rieken 已提交
60
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
B
Benjamin Pasero 已提交
61
import { ITitleService } from 'vs/workbench/services/title/common/titleService';
62
import { IWorkbenchEditorService, IResourceInputType, WorkbenchEditorService, NoOpEditorPart } from 'vs/workbench/services/editor/common/editorService';
J
Johannes Rieken 已提交
63
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
64 65
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { ClipboardService } from 'vs/platform/clipboard/electron-browser/clipboardService';
J
Johannes Rieken 已提交
66 67 68 69 70 71
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
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';
import { TextFileService } from 'vs/workbench/services/textfile/electron-browser/textFileService';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
J
Joao Moreno 已提交
72 73
import { ISCMService } from 'vs/workbench/services/scm/common/scm';
import { SCMService } from 'vs/workbench/services/scm/common/scmService';
74 75
import { IProgressService2 } from 'vs/platform/progress/common/progress';
import { ProgressService2 } from 'vs/workbench/services/progress/browser/progressService2';
76
import { TextModelResolverService } from 'vs/workbench/services/textmodelResolver/common/textModelResolverService';
77
import { ITextModelService } from 'vs/editor/common/services/resolverService';
J
Johannes Rieken 已提交
78
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
B
Benjamin Pasero 已提交
79
import { ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle';
80
import { LifecycleService } from 'vs/platform/lifecycle/electron-browser/lifecycleService';
B
Benjamin Pasero 已提交
81
import { IWindowService, IWindowConfiguration as IWindowSettings, IWindowConfiguration, IPath } from 'vs/platform/windows/common/windows';
J
Johannes Rieken 已提交
82
import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar';
83
import { IMenuService, SyncActionDescriptor } from 'vs/platform/actions/common/actions';
84
import { MenuService } from 'vs/workbench/services/actions/common/menuService';
J
Johannes Rieken 已提交
85 86
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
B
Benjamin Pasero 已提交
87
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
88
import { OpenRecentAction, ToggleDevToolsAction, ReloadWindowAction, ShowPreviousWindowTab, MoveWindowTabToNewWindow, MergeAllWindowTabs, ShowNextWindowTab, ToggleWindowTabsBar, ReloadWindowWithExtensionsDisabledAction } from 'vs/workbench/electron-browser/actions';
89
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
90
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
B
Benjamin Pasero 已提交
91
import { WorkspaceEditingService } from 'vs/workbench/services/workspace/node/workspaceEditingService';
92
import { FileDecorationsService } from 'vs/workbench/services/decorations/browser/decorationsService';
J
Johannes Rieken 已提交
93
import { IDecorationsService } from 'vs/workbench/services/decorations/browser/decorations';
I
isidor 已提交
94
import { ActivityService } from 'vs/workbench/services/activity/browser/activityService';
B
Benjamin Pasero 已提交
95
import URI from 'vs/base/common/uri';
J
Joao Moreno 已提交
96
import { IListService, ListService } from 'vs/platform/list/browser/listService';
J
Joao Moreno 已提交
97
import { InputFocusedContext } from 'vs/platform/workbench/common/contextkeys';
98
import { IViewsService } from 'vs/workbench/common/views';
S
Sandeep Somavarapu 已提交
99
import { CustomViewsService } from 'vs/workbench/browser/parts/views/customView';
100 101
import { INotificationService } from 'vs/platform/notification/common/notification';
import { NotificationService } from 'vs/workbench/services/notification/common/notificationService';
102 103
import { NotificationsCenter } from 'vs/workbench/browser/parts/notifications/notificationsCenter';
import { NotificationsAlerts } from 'vs/workbench/browser/parts/notifications/notificationsAlerts';
104
import { NotificationsStatus } from 'vs/workbench/browser/parts/notifications/notificationsStatus';
105
import { registerNotificationCommands } from 'vs/workbench/browser/parts/notifications/notificationsCommands';
106
import { NotificationsToasts } from 'vs/workbench/browser/parts/notifications/notificationsToasts';
J
Joao Moreno 已提交
107 108
import { IPCClient } from 'vs/base/parts/ipc/common/ipc';
import { registerWindowDriver } from 'vs/platform/driver/electron-browser/driver';
S
Sandeep Somavarapu 已提交
109 110
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
import { PreferencesService } from 'vs/workbench/services/preferences/browser/preferencesService';
111
import { INextEditorService } from 'vs/workbench/services/editor/common/nextEditorService';
112
import { NextEditorPart } from 'vs/workbench/browser/parts/editor2/nextEditorPart';
113
import { INextEditorGroupsService, GroupDirection } from 'vs/workbench/services/editor/common/nextEditorGroupsService';
114
import { NextEditorService } from 'vs/workbench/services/editor/browser/nextEditorService';
J
Joao Moreno 已提交
115
import { IExtensionUrlHandler, ExtensionUrlHandler } from 'vs/platform/url/electron-browser/inactiveExtensionUrlHandler';
116

E
Erich Gamma 已提交
117
interface WorkbenchParams {
118
	configuration: IWindowConfiguration;
119
	serviceCollection: ServiceCollection;
E
Erich Gamma 已提交
120 121
}

I
isidor 已提交
122 123
interface IZenModeSettings {
	fullScreen: boolean;
124
	centerLayout: boolean;
I
isidor 已提交
125
	hideTabs: boolean;
126
	hideActivityBar: boolean;
I
isidor 已提交
127
	hideStatusBar: boolean;
I
isidor 已提交
128
	restore: boolean;
I
isidor 已提交
129 130
}

131 132 133
export interface IWorkbenchStartedInfo {
	customKeybindingsCount: number;
	pinnedViewlets: string[];
134 135
	restoredViewlet: string;
	restoredEditors: string[];
136 137
}

138 139
type FontAliasingOption = 'default' | 'antialiased' | 'none' | 'auto';

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

142 143
const Identifiers = {
	WORKBENCH_CONTAINER: 'workbench.main.container',
B
Benjamin Pasero 已提交
144
	TITLEBAR_PART: 'workbench.parts.titlebar',
145 146 147 148 149 150 151
	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'
};

J
Joao Moreno 已提交
152 153 154 155 156 157 158 159
function getWorkbenchStateString(state: WorkbenchState): string {
	switch (state) {
		case WorkbenchState.EMPTY: return 'empty';
		case WorkbenchState.FOLDER: return 'folder';
		case WorkbenchState.WORKSPACE: return 'workspace';
	}
}

160 161 162 163 164 165 166 167 168 169
interface IZenMode {
	active: boolean;
	transitionedToFullScreen: boolean;
	transitionedToCenteredEditorLayout: boolean;
	transitionDisposeables: IDisposable[];
	wasSideBarVisible: boolean;
	wasPanelVisible: boolean;
}

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

171 172 173 174
	private static readonly sidebarHiddenStorageKey = 'workbench.sidebar.hidden';
	private static readonly sidebarRestoreStorageKey = 'workbench.sidebar.restore';
	private static readonly panelHiddenStorageKey = 'workbench.panel.hidden';
	private static readonly zenModeActiveStorageKey = 'workbench.zenmode.active';
175
	private static readonly centeredEditorLayoutActiveStorageKey = 'workbench.centerededitorlayout.active';
176
	private static readonly panelPositionStorageKey = 'workbench.panel.location';
177
	private static readonly defaultPanelPositionStorageKey = 'workbench.panel.defaultLocation';
178 179 180 181 182
	private static readonly sidebarPositionConfigurationKey = 'workbench.sideBar.location';
	private static readonly statusbarVisibleConfigurationKey = 'workbench.statusBar.visible';
	private static readonly activityBarVisibleConfigurationKey = 'workbench.activityBar.visible';
	private static readonly closeWhenEmptyConfigurationKey = 'window.closeWhenEmpty';
	private static readonly fontAliasingConfigurationKey = 'workbench.fontAliasing';
183

184
	_serviceBrand: any;
E
Erich Gamma 已提交
185 186 187 188 189 190

	private workbenchParams: WorkbenchParams;
	private workbenchContainer: Builder;
	private workbench: Builder;
	private workbenchStarted: boolean;
	private workbenchCreated: boolean;
191 192
	private workbenchShutdown: boolean;

193 194
	private nextEditorService: INextEditorService;
	private nextEditorGroupsService: INextEditorGroupsService;
195
	private legacyEditorService: IWorkbenchEditorService;
P
Pine Wu 已提交
196
	private viewletService: IViewletService;
197
	private contextKeyService: IContextKeyService;
198
	private keybindingService: IKeybindingService;
199
	private backupFileService: IBackupFileService;
200
	private fileService: IFileService;
201 202 203 204
	private quickInput: QuickInputService;

	private workbenchLayout: WorkbenchLayout;

B
Benjamin Pasero 已提交
205
	private titlebarPart: TitlebarPart;
E
Erich Gamma 已提交
206 207
	private activitybarPart: ActivitybarPart;
	private sidebarPart: SidebarPart;
I
isidor 已提交
208
	private panelPart: PanelPart;
209
	private noOpEditorPart: NoOpEditorPart; // TODO@grid adopt methods in next editor part
210
	private editorPart: NextEditorPart;
E
Erich Gamma 已提交
211 212
	private statusbarPart: StatusbarPart;
	private quickOpen: QuickOpenController;
213
	private notificationsCenter: NotificationsCenter;
214
	private notificationsToasts: NotificationsToasts;
215

E
Erich Gamma 已提交
216
	private sideBarHidden: boolean;
217
	private statusBarHidden: boolean;
S
Sanders Lauture 已提交
218
	private activityBarHidden: boolean;
E
Erich Gamma 已提交
219
	private sideBarPosition: Position;
I
isidor 已提交
220
	private panelPosition: Position;
I
isidor 已提交
221
	private panelHidden: boolean;
222 223 224 225 226 227
	private zenMode: IZenMode;
	private centeredEditorLayoutActive: boolean;
	private fontAliasing: FontAliasingOption;
	private hasFilesToCreateOpenOrDiff: boolean;

	private inZenMode: IContextKey<boolean>;
228
	private sideBarVisibleContext: IContextKey<boolean>;
229 230 231 232 233 234 235

	private closeEmptyWindowScheduler: RunOnceScheduler = new RunOnceScheduler(() => this.onAllEditorsClosed(), 50);

	private _onTitleBarVisibilityChange: Emitter<void> = new Emitter<void>();
	get onTitleBarVisibilityChange(): Event<void> { return this._onTitleBarVisibilityChange.event; }

	get onEditorLayout(): Event<IDimension> { return this.editorPart.onDidLayout; }
E
Erich Gamma 已提交
236

237
	constructor(
238 239
		private parent: HTMLElement,
		private container: HTMLElement,
J
Joao Moreno 已提交
240
		private configuration: IWindowConfiguration,
241
		serviceCollection: ServiceCollection,
242
		private lifecycleService: LifecycleService,
J
Joao Moreno 已提交
243
		private mainProcessClient: IPCClient,
244
		@IInstantiationService private instantiationService: IInstantiationService,
245
		@IWorkspaceContextService private contextService: IWorkspaceContextService,
246
		@IStorageService private storageService: IStorageService,
247
		@IConfigurationService private configurationService: WorkspaceService,
I
isidor 已提交
248
		@IEnvironmentService private environmentService: IEnvironmentService,
249 250
		@IWindowService private windowService: IWindowService,
		@INotificationService private notificationService: NotificationService
251
	) {
252
		super();
E
Erich Gamma 已提交
253 254

		this.workbenchParams = {
255
			configuration,
256
			serviceCollection
E
Erich Gamma 已提交
257 258
		};

259
		this.hasFilesToCreateOpenOrDiff =
B
Benjamin Pasero 已提交
260 261 262
			(configuration.filesToCreate && configuration.filesToCreate.length > 0) ||
			(configuration.filesToOpen && configuration.filesToOpen.length > 0) ||
			(configuration.filesToDiff && configuration.filesToDiff.length > 0);
263 264
	}

265
	startup(): TPromise<IWorkbenchStartedInfo> {
266
		this.workbenchStarted = true;
E
Erich Gamma 已提交
267

B
Benjamin Pasero 已提交
268
		// Create Workbench Container
269
		this.createWorkbench();
E
Erich Gamma 已提交
270

271 272
		// Install some global actions
		this.createGlobalActions();
273

274 275
		// Services
		this.initServices();
E
Erich Gamma 已提交
276

277 278
		// Context Keys
		this.handleContextKeys();
J
Joao Moreno 已提交
279

280 281
		// Register Listeners
		this.registerListeners();
E
Erich Gamma 已提交
282

283 284
		// Settings
		this.initSettings();
E
Erich Gamma 已提交
285

286 287
		// Create Workbench and Parts
		this.renderWorkbench();
288

289 290
		// Workbench Layout
		this.createWorkbenchLayout();
B
polish  
Benjamin Pasero 已提交
291

J
Joao Moreno 已提交
292 293
		// Driver
		if (this.environmentService.driverHandle) {
294
			registerWindowDriver(this.mainProcessClient, this.configuration.windowId, this.instantiationService).then(disposable => this._register(disposable));
J
Joao Moreno 已提交
295 296
		}

297
		// Restore Parts
B
Benjamin Pasero 已提交
298 299
		return this.restoreParts();
	}
300

301
	private handleContextKeys(): void {
302 303 304 305
		this.inZenMode = InEditorZenModeContext.bindTo(this.contextKeyService);

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

307 308 309 310 311 312
		const editorsVisibleContext = EditorsVisibleContext.bindTo(this.contextKeyService);
		const textCompareEditorVisible = TextCompareEditorVisibleContext.bindTo(this.contextKeyService);
		const activeEditorGroupEmpty = ActiveEditorGroupEmptyContext.bindTo(this.contextKeyService);
		const multipleEditorGroups = MultipleEditorGroupsContext.bindTo(this.contextKeyService);

		const updateEditorContextKeys = () => {
313 314
			const visibleEditors = this.nextEditorService.visibleControls;

315 316 317 318
			textCompareEditorVisible.set(visibleEditors.some(control => control.getId() === TEXT_DIFF_EDITOR_ID));

			if (visibleEditors.length > 0) {
				editorsVisibleContext.set(true);
319
			} else {
320
				editorsVisibleContext.reset();
321
			}
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339

			if (!this.nextEditorService.activeEditor) {
				activeEditorGroupEmpty.set(true);
			} else {
				activeEditorGroupEmpty.reset();
			}

			if (this.nextEditorGroupsService.count > 1) {
				multipleEditorGroups.set(true);
			} else {
				multipleEditorGroups.reset();
			}
		};

		this._register(this.nextEditorService.onDidActiveEditorChange(() => updateEditorContextKeys()));
		this._register(this.nextEditorService.onDidVisibleEditorsChange(() => updateEditorContextKeys()));
		this._register(this.nextEditorGroupsService.onDidAddGroup(() => updateEditorContextKeys()));
		this._register(this.nextEditorGroupsService.onDidRemoveGroup(() => updateEditorContextKeys()));
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358

		const inputFocused = InputFocusedContext.bindTo(this.contextKeyService);
		this._register(DOM.addDisposableListener(window, 'focusin', () => {
			inputFocused.set(document.activeElement && (document.activeElement.tagName === 'INPUT' || document.activeElement.tagName === 'TEXTAREA'));
		}, true));

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

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

359 360
	private registerListeners(): void {

361
		// Listen to visible editor changes
362
		this._register(this.nextEditorService.onDidVisibleEditorsChange(() => this.onDidVisibleEditorsChange()));
363 364 365 366 367 368

		// Listen to editor closing (if we run with --wait)
		const filesToWait = this.workbenchParams.configuration.filesToWait;
		if (filesToWait) {
			const resourcesToWaitFor = filesToWait.paths.map(p => URI.file(p.filePath));
			const waitMarkerFile = URI.file(filesToWait.waitMarkerFilePath);
369
			const listenerDispose = this.nextEditorService.onDidCloseEditor(() => this.onEditorClosed(listenerDispose, resourcesToWaitFor, waitMarkerFile));
370

371
			this._register(listenerDispose);
372 373 374
		}

		// Configuration changes
375
		this._register(this.configurationService.onDidChangeConfiguration(() => this.onDidUpdateConfiguration()));
376 377

		// Fullscreen changes
378
		this._register(browser.onDidChangeFullscreen(() => this.onFullscreenChanged()));
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
	}

	private onFullscreenChanged(): void {
		if (!this.isCreated) {
			return; // we need to be ready
		}

		// Apply as CSS class
		const isFullscreen = browser.isFullscreen();
		if (isFullscreen) {
			this.workbench.addClass('fullscreen');
		} else {
			this.workbench.removeClass('fullscreen');
			if (this.zenMode.transitionedToFullScreen && this.zenMode.active) {
				this.toggleZenMode();
			}
		}

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

	private onEditorClosed(listenerDispose: IDisposable, resourcesToWaitFor: URI[], waitMarkerFile: URI): void {

		// In wait mode, listen to changes to the editors and wait until the files
		// are closed that the user wants to wait for. When this happens we delete
		// the wait marker file to signal to the outside that editing is done.
410
		if (resourcesToWaitFor.every(resource => !this.nextEditorService.isOpen({ resource }))) {
411 412 413 414 415
			listenerDispose.dispose();
			this.fileService.del(waitMarkerFile).done(null, errors.onUnexpectedError);
		}
	}

416 417
	private onDidVisibleEditorsChange(): void {
		const visibleEditors = this.nextEditorService.visibleControls;
418 419 420 421 422 423 424 425 426 427 428 429 430

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

	private onAllEditorsClosed(): void {
431
		const visibleEditors = this.nextEditorService.visibleControls.length;
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463
		if (visibleEditors === 0) {
			this.windowService.closeWindow();
		}
	}

	private onDidUpdateConfiguration(skipLayout?: boolean): void {
		const newSidebarPositionValue = this.configurationService.getValue<string>(Workbench.sidebarPositionConfigurationKey);
		const newSidebarPosition = (newSidebarPositionValue === 'right') ? Position.RIGHT : Position.LEFT;
		if (newSidebarPosition !== this.getSideBarPosition()) {
			this.setSideBarPosition(newSidebarPosition);
		}

		this.setPanelPositionFromStorageOrConfig();

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

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

			const newActivityBarHiddenValue = !this.configurationService.getValue<boolean>(Workbench.activityBarVisibleConfigurationKey);
			if (newActivityBarHiddenValue !== this.activityBarHidden) {
				this.setActivityBarHidden(newActivityBarHiddenValue, skipLayout);
			}
		}
	}

B
Benjamin Pasero 已提交
464 465 466 467 468 469
	private createWorkbench(): void {
		this.workbenchContainer = $('.monaco-workbench-container');
		this.workbench = $().div({
			'class': `monaco-workbench ${isWindows ? 'windows' : isLinux ? 'linux' : 'mac'}`,
			id: Identifiers.WORKBENCH_CONTAINER
		}).appendTo(this.workbenchContainer);
470
	}
E
Erich Gamma 已提交
471

472 473 474 475
	private restoreParts(): TPromise<IWorkbenchStartedInfo> {
		const restorePromises: TPromise<any>[] = [];

		// Restore Editors
J
Johannes Rieken 已提交
476
		perf.mark('willRestoreEditors');
477 478 479 480
		const restoredEditors: string[] = [];
		restorePromises.push(this.resolveEditorsToOpen().then(inputs => {
			let editorOpenPromise: TPromise<IEditor[]>;
			if (inputs.length) {
481
				editorOpenPromise = this.legacyEditorService.openEditors(inputs.map(input => { return { input, position: EditorPosition.ONE }; }));
482
			} else {
483
				editorOpenPromise = this.noOpEditorPart.restoreEditors();
484 485
			}

B
Benjamin Pasero 已提交
486
			return editorOpenPromise.then(editors => {
J
Johannes Rieken 已提交
487
				perf.mark('didRestoreEditors');
488

489 490 491 492 493 494
				for (const editor of editors) {
					if (editor) {
						if (editor.input) {
							restoredEditors.push(editor.input.getName());
						} else {
							restoredEditors.push(`other:${editor.getId()}`);
495 496
						}
					}
497
				}
B
Benjamin Pasero 已提交
498
			});
499
		}));
E
Erich Gamma 已提交
500

501 502 503 504
		// Restore Sidebar
		let viewletIdToRestore: string;
		if (!this.sideBarHidden) {
			this.sideBarVisibleContext.set(true);
I
isidor 已提交
505

506 507 508
			if (this.shouldRestoreLastOpenedViewlet()) {
				viewletIdToRestore = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE);
			}
509

510 511 512
			if (!viewletIdToRestore) {
				viewletIdToRestore = this.viewletService.getDefaultViewletId();
			}
513

J
Johannes Rieken 已提交
514
			perf.mark('willRestoreViewlet');
515
			restorePromises.push(this.viewletService.openViewlet(viewletIdToRestore).then(() => {
J
Johannes Rieken 已提交
516
				perf.mark('didRestoreViewlet');
517 518
			}));
		}
E
Erich Gamma 已提交
519

520 521 522 523 524 525
		// Restore Panel
		const panelRegistry = Registry.as<PanelRegistry>(PanelExtensions.Panels);
		const panelId = this.storageService.get(PanelPart.activePanelSettingsKey, StorageScope.WORKSPACE, panelRegistry.getDefaultPanelId());
		if (!this.panelHidden && !!panelId) {
			restorePromises.push(this.panelPart.openPanel(panelId, false));
		}
E
Erich Gamma 已提交
526

527
		// Restore Zen Mode if active
I
isidor 已提交
528
		if (this.storageService.getBoolean(Workbench.zenModeActiveStorageKey, StorageScope.WORKSPACE, false)) {
529
			this.toggleZenMode(true);
E
Erich Gamma 已提交
530
		}
531

B
Benjamin Pasero 已提交
532 533 534
		// Restore Forced Editor Center Mode
		if (this.storageService.getBoolean(Workbench.centeredEditorLayoutActiveStorageKey, StorageScope.GLOBAL, false)) {
			this.centeredEditorLayoutActive = true;
S
SrTobi 已提交
535 536
		}

537
		const onRestored = (error?: Error): IWorkbenchStartedInfo => {
B
Benjamin Pasero 已提交
538 539
			this.workbenchCreated = true;

540 541 542 543 544 545 546 547 548 549 550 551 552
			if (error) {
				errors.onUnexpectedError(error);
			}

			return {
				customKeybindingsCount: this.keybindingService.customKeybindingsCount(),
				pinnedViewlets: this.activitybarPart.getPinned(),
				restoredViewlet: viewletIdToRestore,
				restoredEditors
			};
		};

		return TPromise.join(restorePromises).then(() => onRestored(), error => onRestored(error));
E
Erich Gamma 已提交
553 554
	}

555 556 557 558 559 560 561 562 563 564 565 566 567
	private shouldRestoreLastOpenedViewlet(): boolean {
		if (!this.environmentService.isBuilt) {
			return true; // always restore sidebar when we are in development mode
		}

		const restore = this.storageService.getBoolean(Workbench.sidebarRestoreStorageKey, StorageScope.WORKSPACE);
		if (restore) {
			this.storageService.remove(Workbench.sidebarRestoreStorageKey, StorageScope.WORKSPACE); // only support once
		}

		return restore;
	}

568
	private createGlobalActions(): void {
B
Benjamin Pasero 已提交
569
		const isDeveloping = !this.environmentService.isBuilt || this.environmentService.isExtensionDevelopment;
570

B
Benjamin Pasero 已提交
571
		// Actions registered here to adjust for developing vs built workbench
572 573
		const workbenchActionsRegistry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
		workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ReloadWindowAction, ReloadWindowAction.ID, ReloadWindowAction.LABEL, isDeveloping ? { primary: KeyMod.CtrlCmd | KeyCode.KEY_R } : void 0), 'Reload Window');
B
Benjamin Pasero 已提交
574
		workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleDevToolsAction, ToggleDevToolsAction.ID, ToggleDevToolsAction.LABEL, isDeveloping ? { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_I, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_I } } : void 0), 'Developer: Toggle Developer Tools', localize('developer', "Developer"));
B
Benjamin Pasero 已提交
575
		workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenRecentAction, OpenRecentAction.ID, OpenRecentAction.LABEL, { primary: isDeveloping ? null : KeyMod.CtrlCmd | KeyCode.KEY_R, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_R } }), 'File: Open Recent...', localize('file', "File"));
576
		workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ReloadWindowWithExtensionsDisabledAction, ReloadWindowWithExtensionsDisabledAction.ID, ReloadWindowWithExtensionsDisabledAction.LABEL), 'Reload Window Without Extensions');
577

578
		// Actions for macOS native tabs management (only when enabled)
579
		const windowConfig = this.configurationService.getValue<IWindowConfiguration>();
580 581 582 583 584 585 586
		if (windowConfig && windowConfig.window && windowConfig.window.nativeTabs) {
			workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ShowPreviousWindowTab, ShowPreviousWindowTab.ID, ShowPreviousWindowTab.LABEL), 'Show Previous Window Tab');
			workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ShowNextWindowTab, ShowNextWindowTab.ID, ShowNextWindowTab.LABEL), 'Show Next Window Tab');
			workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(MoveWindowTabToNewWindow, MoveWindowTabToNewWindow.ID, MoveWindowTabToNewWindow.LABEL), 'Move Window Tab to New Window');
			workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(MergeAllWindowTabs, MergeAllWindowTabs.ID, MergeAllWindowTabs.LABEL), 'Merge All Windows');
			workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleWindowTabsBar, ToggleWindowTabsBar.ID, ToggleWindowTabsBar.LABEL), 'Toggle Window Tabs Bar');
		}
587 588
	}

589
	private resolveEditorsToOpen(): TPromise<IResourceInputType[]> {
590
		const config = this.workbenchParams.configuration;
B
Benjamin Pasero 已提交
591 592

		// Files to open, diff or create
593
		if (this.hasFilesToCreateOpenOrDiff) {
B
Benjamin Pasero 已提交
594 595

			// Files to diff is exclusive
596
			const filesToDiff = this.toInputs(config.filesToDiff, false);
597
			if (filesToDiff && filesToDiff.length === 2) {
598 599 600 601 602
				return TPromise.as([<IResourceDiffInput>{
					leftResource: filesToDiff[0].resource,
					rightResource: filesToDiff[1].resource,
					options: { pinned: true }
				}]);
B
Benjamin Pasero 已提交
603 604
			}

605 606
			const filesToCreate = this.toInputs(config.filesToCreate, true);
			const filesToOpen = this.toInputs(config.filesToOpen, false);
607

608 609
			// Otherwise: Open/Create files
			return TPromise.as([...filesToOpen, ...filesToCreate]);
B
Benjamin Pasero 已提交
610 611
		}

612
		// Empty workbench
613
		else if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY && this.openUntitledFile()) {
614
			if (this.noOpEditorPart.hasEditorsToRestore()) {
615 616 617
				return TPromise.as([]); // do not open any empty untitled file if we have editors to restore
			}

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

623
				return TPromise.as([<IUntitledResourceInput>{}]);
624
			});
B
Benjamin Pasero 已提交
625 626 627 628 629
		}

		return TPromise.as([]);
	}

630
	private toInputs(paths: IPath[], isNew: boolean): (IResourceInput | IUntitledResourceInput)[] {
B
Benjamin Pasero 已提交
631 632 633 634 635
		if (!paths || !paths.length) {
			return [];
		}

		return paths.map(p => {
636 637 638 639 640 641 642
			const resource = URI.file(p.filePath);
			let input: IResourceInput | IUntitledResourceInput;
			if (isNew) {
				input = { filePath: resource.fsPath, options: { pinned: true } } as IUntitledResourceInput;
			} else {
				input = { resource, options: { pinned: true } } as IResourceInput;
			}
B
Benjamin Pasero 已提交
643

644
			if (!isNew && p.lineNumber) {
B
Benjamin Pasero 已提交
645 646 647 648 649 650 651 652 653 654
				input.options.selection = {
					startLineNumber: p.lineNumber,
					startColumn: p.columnNumber
				};
			}

			return input;
		});
	}

655
	private openUntitledFile() {
656
		const startupEditor = this.configurationService.inspect('workbench.startupEditor');
B
Benjamin Pasero 已提交
657 658

		// Fallback to previous workbench.welcome.enabled setting in case startupEditor is not defined
659
		if (!startupEditor.user && !startupEditor.workspace) {
660 661 662
			const welcomeEnabledValue = this.configurationService.getValue('workbench.welcome.enabled');
			if (typeof welcomeEnabledValue === 'boolean') {
				return !welcomeEnabledValue;
663 664
			}
		}
B
Benjamin Pasero 已提交
665

666
		return startupEditor.value === 'newUntitledFile';
667 668
	}

E
Erich Gamma 已提交
669
	private initServices(): void {
B
Benjamin Pasero 已提交
670
		const { serviceCollection } = this.workbenchParams;
671

E
Erich Gamma 已提交
672
		// Services we contribute
673
		serviceCollection.set(IPartService, this);
E
Erich Gamma 已提交
674

675 676 677
		// Clipboard
		serviceCollection.set(IClipboardService, new ClipboardService());

678 679
		// Status bar
		this.statusbarPart = this.instantiationService.createInstance(StatusbarPart, Identifiers.STATUSBAR_PART);
680
		this._register(toDisposable(() => this.statusbarPart.shutdown()));
681 682
		serviceCollection.set(IStatusbarService, this.statusbarPart);

683 684 685
		// Progress 2
		serviceCollection.set(IProgressService2, new SyncDescriptor(ProgressService2));

686
		// Keybindings
A
Alex Dima 已提交
687
		this.contextKeyService = this.instantiationService.createInstance(ContextKeyService);
688
		serviceCollection.set(IContextKeyService, this.contextKeyService);
689

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

693 694 695
		// List
		serviceCollection.set(IListService, this.instantiationService.createInstance(ListService));

696
		// Context Menu
697
		serviceCollection.set(IContextMenuService, new SyncDescriptor(ContextMenuService));
698

699 700
		// Menus/Actions
		serviceCollection.set(IMenuService, new SyncDescriptor(MenuService));
701

P
Pine Wu 已提交
702
		// Sidebar part
703
		this.sidebarPart = this.instantiationService.createInstance(SidebarPart, Identifiers.SIDEBAR_PART);
704
		this._register(toDisposable(() => this.sidebarPart.shutdown()));
P
Pine Wu 已提交
705 706 707 708

		// Viewlet service
		this.viewletService = this.instantiationService.createInstance(ViewletService, this.sidebarPart);
		serviceCollection.set(IViewletService, this.viewletService);
E
Erich Gamma 已提交
709

I
isidor 已提交
710
		// Panel service (panel part)
711
		this.panelPart = this.instantiationService.createInstance(PanelPart, Identifiers.PANEL_PART);
712
		this._register(toDisposable(() => this.panelPart.shutdown()));
713
		serviceCollection.set(IPanelService, this.panelPart);
I
isidor 已提交
714

S
Sandeep Somavarapu 已提交
715 716
		// Custom views service
		const customViewsService = this.instantiationService.createInstance(CustomViewsService);
717
		serviceCollection.set(IViewsService, customViewsService);
S
Sandeep Somavarapu 已提交
718

E
Erich Gamma 已提交
719
		// Activity service (activitybar part)
720
		this.activitybarPart = this.instantiationService.createInstance(ActivitybarPart, Identifiers.ACTIVITYBAR_PART);
721
		this._register(toDisposable(() => this.activitybarPart.shutdown()));
I
isidor 已提交
722 723
		const activityService = this.instantiationService.createInstance(ActivityService, this.activitybarPart, this.panelPart);
		serviceCollection.set(IActivityService, activityService);
E
Erich Gamma 已提交
724

725 726 727
		// File Service
		this.fileService = this.instantiationService.createInstance(RemoteFileService);
		serviceCollection.set(IFileService, this.fileService);
S
#47154  
Sandeep Somavarapu 已提交
728
		this.configurationService.acquireFileService(this.fileService);
729

730 731
		// Editor service (next editor part)
		this.editorPart = this.instantiationService.createInstance(NextEditorPart, Identifiers.EDITOR_PART /*, !this.hasFilesToCreateOpenOrDiff*/);
732
		this._register(toDisposable(() => this.editorPart.shutdown()));
733
		this.nextEditorGroupsService = this.editorPart;
734
		serviceCollection.set(INextEditorGroupsService, this.editorPart);
735 736
		this.nextEditorService = this.instantiationService.createInstance(NextEditorService);
		serviceCollection.set(INextEditorService, this.nextEditorService);
737 738 739

		// Legacy Editor Services
		this.noOpEditorPart = new NoOpEditorPart(this.instantiationService);
740 741
		this.legacyEditorService = this.instantiationService.createInstance(WorkbenchEditorService, this.noOpEditorPart);
		serviceCollection.set(IWorkbenchEditorService, this.legacyEditorService);
742
		serviceCollection.set(IEditorGroupService, this.noOpEditorPart);
E
Erich Gamma 已提交
743

744 745
		// Title bar
		this.titlebarPart = this.instantiationService.createInstance(TitlebarPart, Identifiers.TITLEBAR_PART);
746
		this._register(toDisposable(() => this.titlebarPart.shutdown()));
747 748
		serviceCollection.set(ITitleService, this.titlebarPart);

749
		// History
750
		serviceCollection.set(IHistoryService, new SyncDescriptor(HistoryService));
751

752
		// Backup File Service
753
		this.backupFileService = this.instantiationService.createInstance(BackupFileService, this.workbenchParams.configuration.backupPath);
754
		serviceCollection.set(IBackupFileService, this.backupFileService);
755

756
		// Text File Service
757
		serviceCollection.set(ITextFileService, new SyncDescriptor(TextFileService));
758

759
		// File Decorations
J
Johannes Rieken 已提交
760
		serviceCollection.set(IDecorationsService, new SyncDescriptor(FileDecorationsService));
761

J
Joao Moreno 已提交
762
		// SCM Service
763
		serviceCollection.set(ISCMService, new SyncDescriptor(SCMService));
764

J
Joao Moreno 已提交
765
		// Inactive extension URL handler
J
Joao Moreno 已提交
766
		serviceCollection.set(IExtensionUrlHandler, new SyncDescriptor(ExtensionUrlHandler));
J
Joao Moreno 已提交
767

B
Benjamin Pasero 已提交
768
		// Text Model Resolver Service
769
		serviceCollection.set(ITextModelService, new SyncDescriptor(TextModelResolverService));
B
Benjamin Pasero 已提交
770

771 772 773 774
		// JSON Editing
		const jsonEditingService = this.instantiationService.createInstance(JSONEditingService);
		serviceCollection.set(IJSONEditingService, jsonEditingService);

775 776 777
		// Workspace Editing
		serviceCollection.set(IWorkspaceEditingService, new SyncDescriptor(WorkspaceEditingService));

778 779 780
		// Keybinding Editing
		serviceCollection.set(IKeybindingEditingService, this.instantiationService.createInstance(KeybindingsEditingService));

781
		// Configuration Resolver
B
Benjamin Pasero 已提交
782
		serviceCollection.set(IConfigurationResolverService, new SyncDescriptor(ConfigurationResolverService, process.env));
783

E
Erich Gamma 已提交
784
		// Quick open service (quick open controller)
785
		this.quickOpen = this.instantiationService.createInstance(QuickOpenController);
786
		this._register(toDisposable(() => this.quickOpen.shutdown()));
787
		serviceCollection.set(IQuickOpenService, this.quickOpen);
788

C
Christof Marti 已提交
789 790
		// Quick input service
		this.quickInput = this.instantiationService.createInstance(QuickInputService);
791
		this._register(toDisposable(() => this.quickInput.shutdown()));
C
Christof Marti 已提交
792 793
		serviceCollection.set(IQuickInputService, this.quickInput);

S
Sandeep Somavarapu 已提交
794 795 796
		// PreferencesService
		serviceCollection.set(IPreferencesService, this.instantiationService.createInstance(PreferencesService));

B
polish  
Benjamin Pasero 已提交
797
		// Contributed services
B
Benjamin Pasero 已提交
798
		const contributedServices = getServices();
E
Erich Gamma 已提交
799
		for (let contributedService of contributedServices) {
800
			serviceCollection.set(contributedService.id, contributedService.descriptor);
E
Erich Gamma 已提交
801 802 803
		}

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

808
		this.instantiationService.createInstance(DefaultConfigurationExportHelper);
809

S
#47154  
Sandeep Somavarapu 已提交
810
		this.configurationService.acquireInstantiationService(this.getInstantiationService());
E
Erich Gamma 已提交
811 812 813 814 815
	}

	private initSettings(): void {

		// Sidebar visibility
I
isidor 已提交
816
		this.sideBarHidden = this.storageService.getBoolean(Workbench.sidebarHiddenStorageKey, StorageScope.WORKSPACE, this.contextService.getWorkbenchState() === WorkbenchState.EMPTY);
E
Erich Gamma 已提交
817

I
isidor 已提交
818
		// Panel part visibility
819
		const panelRegistry = Registry.as<PanelRegistry>(PanelExtensions.Panels);
I
isidor 已提交
820
		this.panelHidden = this.storageService.getBoolean(Workbench.panelHiddenStorageKey, StorageScope.WORKSPACE, true);
821 822
		if (!panelRegistry.getDefaultPanelId()) {
			this.panelHidden = true; // we hide panel part if there is no default panel
I
isidor 已提交
823
		}
I
isidor 已提交
824

E
Erich Gamma 已提交
825
		// Sidebar position
826
		const sideBarPosition = this.configurationService.getValue<string>(Workbench.sidebarPositionConfigurationKey);
827
		this.sideBarPosition = (sideBarPosition === 'right') ? Position.RIGHT : Position.LEFT;
B
Benjamin Pasero 已提交
828

I
isidor 已提交
829
		// Panel position
830
		this.setPanelPositionFromStorageOrConfig();
I
isidor 已提交
831

B
Benjamin Pasero 已提交
832
		// Statusbar visibility
833
		const statusBarVisible = this.configurationService.getValue<string>(Workbench.statusbarVisibleConfigurationKey);
834
		this.statusBarHidden = !statusBarVisible;
S
Sanders Lauture 已提交
835 836

		// Activity bar visibility
837
		const activityBarVisible = this.configurationService.getValue<string>(Workbench.activityBarVisibleConfigurationKey);
S
Sanders Lauture 已提交
838
		this.activityBarHidden = !activityBarVisible;
I
isidor 已提交
839

840
		// Font aliasing
841
		this.fontAliasing = this.configurationService.getValue<FontAliasingOption>(Workbench.fontAliasingConfigurationKey);
842

I
isidor 已提交
843 844
		// Zen mode
		this.zenMode = {
I
isidor 已提交
845
			active: false,
846
			transitionedToFullScreen: false,
847
			transitionedToCenteredEditorLayout: false,
848
			wasSideBarVisible: false,
849 850
			wasPanelVisible: false,
			transitionDisposeables: []
I
isidor 已提交
851
		};
S
SrTobi 已提交
852

B
Benjamin Pasero 已提交
853 854
		// Centered Editor Layout
		this.centeredEditorLayoutActive = false;
E
Erich Gamma 已提交
855 856
	}

857 858 859 860 861 862
	private setPanelPositionFromStorageOrConfig() {
		const defaultPanelPosition = this.configurationService.getValue<string>(Workbench.defaultPanelPositionStorageKey);
		const panelPosition = this.storageService.get(Workbench.panelPositionStorageKey, StorageScope.WORKSPACE, defaultPanelPosition);
		this.panelPosition = (panelPosition === 'right') ? Position.RIGHT : Position.BOTTOM;
	}

E
Erich Gamma 已提交
863 864 865
	/**
	 * Returns whether the workbench has been started.
	 */
866
	isStarted(): boolean {
E
Erich Gamma 已提交
867 868 869 870 871 872
		return this.workbenchStarted && !this.workbenchShutdown;
	}

	/**
	 * Returns whether the workbench has been fully created.
	 */
873
	isCreated(): boolean {
E
Erich Gamma 已提交
874 875 876
		return this.workbenchCreated && this.workbenchStarted;
	}

877
	hasFocus(part: Parts): boolean {
B
Benjamin Pasero 已提交
878
		const activeElement = document.activeElement;
E
Erich Gamma 已提交
879 880 881 882
		if (!activeElement) {
			return false;
		}

883 884 885 886
		const container = this.getContainer(part);
		return DOM.isAncestor(activeElement, container);
	}

887
	getContainer(part: Parts): HTMLElement {
888
		let container: HTMLElement = null;
E
Erich Gamma 已提交
889
		switch (part) {
B
Benjamin Pasero 已提交
890 891 892
			case Parts.TITLEBAR_PART:
				container = this.titlebarPart.getContainer();
				break;
E
Erich Gamma 已提交
893 894 895 896 897 898
			case Parts.ACTIVITYBAR_PART:
				container = this.activitybarPart.getContainer();
				break;
			case Parts.SIDEBAR_PART:
				container = this.sidebarPart.getContainer();
				break;
I
isidor 已提交
899 900 901
			case Parts.PANEL_PART:
				container = this.panelPart.getContainer();
				break;
E
Erich Gamma 已提交
902 903 904 905 906 907 908
			case Parts.EDITOR_PART:
				container = this.editorPart.getContainer();
				break;
			case Parts.STATUSBAR_PART:
				container = this.statusbarPart.getContainer();
				break;
		}
909 910

		return container;
E
Erich Gamma 已提交
911 912
	}

913
	isVisible(part: Parts): boolean {
B
Benjamin Pasero 已提交
914
		switch (part) {
B
Benjamin Pasero 已提交
915
			case Parts.TITLEBAR_PART:
916
				return this.getCustomTitleBarStyle() && !browser.isFullscreen();
B
Benjamin Pasero 已提交
917
			case Parts.SIDEBAR_PART:
918
				return !this.sideBarHidden;
B
Benjamin Pasero 已提交
919
			case Parts.PANEL_PART:
920
				return !this.panelHidden;
B
Benjamin Pasero 已提交
921
			case Parts.STATUSBAR_PART:
922
				return !this.statusBarHidden;
S
Sanders Lauture 已提交
923
			case Parts.ACTIVITYBAR_PART:
924
				return !this.activityBarHidden;
925
		}
E
Erich Gamma 已提交
926 927 928 929

		return true; // any other part cannot be hidden
	}

930
	getTitleBarOffset(): number {
931
		let offset = 0;
932
		if (this.isVisible(Parts.TITLEBAR_PART)) {
933 934 935 936 937 938
			offset = 22 / browser.getZoomFactor(); // adjust the position based on title bar size and zoom factor
		}

		return offset;
	}

939
	private getCustomTitleBarStyle(): 'custom' {
B
Benjamin Pasero 已提交
940
		if (!isMacintosh) {
941
			return null; // custom title bar is only supported on Mac currently
B
Benjamin Pasero 已提交
942 943
		}

944
		const isDev = !this.environmentService.isBuilt || this.environmentService.isExtensionDevelopment;
B
Benjamin Pasero 已提交
945
		if (isDev) {
946
			return null; // not enabled when developing due to https://github.com/electron/electron/issues/3647
B
Benjamin Pasero 已提交
947 948
		}

949
		const windowConfig = this.configurationService.getValue<IWindowSettings>();
950 951 952 953 954
		if (windowConfig && windowConfig.window) {
			const useNativeTabs = windowConfig.window.nativeTabs;
			if (useNativeTabs) {
				return null; // native tabs on sierra do not work with custom title style
			}
B
Benjamin Pasero 已提交
955

956 957 958 959
			const style = windowConfig.window.titleBarStyle;
			if (style === 'custom') {
				return style;
			}
960 961 962
		}

		return null;
B
Benjamin Pasero 已提交
963 964
	}

965
	private setStatusBarHidden(hidden: boolean, skipLayout?: boolean): void {
966 967
		this.statusBarHidden = hidden;

968 969 970 971 972 973
		// Adjust CSS
		if (hidden) {
			this.workbench.addClass('nostatusbar');
		} else {
			this.workbench.removeClass('nostatusbar');
		}
I
isidor 已提交
974

975 976
		// Layout
		if (!skipLayout) {
977
			this.workbenchLayout.layout();
978 979 980
		}
	}

981
	setActivityBarHidden(hidden: boolean, skipLayout?: boolean): void {
S
Sanders Lauture 已提交
982 983 984 985
		this.activityBarHidden = hidden;

		// Layout
		if (!skipLayout) {
986
			this.workbenchLayout.layout();
S
Sanders Lauture 已提交
987 988 989
		}
	}

990
	setSideBarHidden(hidden: boolean, skipLayout?: boolean): TPromise<void> {
E
Erich Gamma 已提交
991
		this.sideBarHidden = hidden;
992
		this.sideBarVisibleContext.set(!hidden);
E
Erich Gamma 已提交
993 994 995 996 997 998 999 1000

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

B
Benjamin Pasero 已提交
1001
		// If sidebar becomes hidden, also hide the current active Viewlet if any
1002
		let promise = TPromise.wrap<any>(null);
E
Erich Gamma 已提交
1003
		if (hidden && this.sidebarPart.getActiveViewlet()) {
1004
			promise = this.sidebarPart.hideActiveViewlet().then(() => {
1005
				const activeEditor = this.nextEditorService.activeControl;
1006
				const activePanel = this.panelPart.getActivePanel();
B
Benjamin Pasero 已提交
1007

1008 1009 1010 1011 1012 1013 1014
				// Pass Focus to Editor or Panel if Sidebar is now hidden
				if (this.hasFocus(Parts.PANEL_PART) && activePanel) {
					activePanel.focus();
				} else if (activeEditor) {
					activeEditor.focus();
				}
			});
E
Erich Gamma 已提交
1015 1016
		}

B
Benjamin Pasero 已提交
1017
		// If sidebar becomes visible, show last active Viewlet or default viewlet
E
Erich Gamma 已提交
1018
		else if (!hidden && !this.sidebarPart.getActiveViewlet()) {
1019
			const viewletToOpen = this.sidebarPart.getLastActiveViewletId();
E
Erich Gamma 已提交
1020
			if (viewletToOpen) {
1021
				promise = this.sidebarPart.openViewlet(viewletToOpen, true);
E
Erich Gamma 已提交
1022 1023 1024
			}
		}

1025
		return promise.then(() => {
1026

1027
			// Remember in settings
1028
			const defaultHidden = this.contextService.getWorkbenchState() === WorkbenchState.EMPTY;
1029
			if (hidden !== defaultHidden) {
I
isidor 已提交
1030
				this.storageService.store(Workbench.sidebarHiddenStorageKey, hidden ? 'true' : 'false', StorageScope.WORKSPACE);
1031
			} else {
I
isidor 已提交
1032
				this.storageService.remove(Workbench.sidebarHiddenStorageKey, StorageScope.WORKSPACE);
1033
			}
1034 1035 1036

			// Layout
			if (!skipLayout) {
1037
				this.workbenchLayout.layout();
1038 1039
			}
		});
E
Erich Gamma 已提交
1040 1041
	}

1042
	setPanelHidden(hidden: boolean, skipLayout?: boolean): TPromise<void> {
I
isidor 已提交
1043
		this.panelHidden = hidden;
I
isidor 已提交
1044

1045 1046 1047 1048 1049 1050 1051
		// Adjust CSS
		if (hidden) {
			this.workbench.addClass('nopanel');
		} else {
			this.workbench.removeClass('nopanel');
		}

I
isidor 已提交
1052
		// If panel part becomes hidden, also hide the current active panel if any
1053
		let promise = TPromise.wrap<any>(null);
I
isidor 已提交
1054
		if (hidden && this.panelPart.getActivePanel()) {
1055
			promise = this.panelPart.hideActivePanel().then(() => {
1056

1057
				// Pass Focus to Editor if Panel part is now hidden
1058
				const editor = this.nextEditorService.activeControl;
1059 1060 1061 1062
				if (editor) {
					editor.focus();
				}
			});
I
isidor 已提交
1063 1064 1065 1066
		}

		// If panel part becomes visible, show last active panel or default panel
		else if (!hidden && !this.panelPart.getActivePanel()) {
1067
			const panelToOpen = this.panelPart.getLastActivePanelId();
I
isidor 已提交
1068
			if (panelToOpen) {
1069
				promise = this.panelPart.openPanel(panelToOpen, true);
I
isidor 已提交
1070 1071 1072
			}
		}

1073
		return promise.then(() => {
1074

1075
			// Remember in settings
1076
			if (!hidden) {
I
isidor 已提交
1077
				this.storageService.store(Workbench.panelHiddenStorageKey, 'false', StorageScope.WORKSPACE);
1078
			} else {
I
isidor 已提交
1079
				this.storageService.remove(Workbench.panelHiddenStorageKey, StorageScope.WORKSPACE);
1080
			}
1081 1082 1083

			// Layout
			if (!skipLayout) {
1084
				this.workbenchLayout.layout();
1085 1086
			}
		});
I
isidor 已提交
1087 1088
	}

1089
	toggleMaximizedPanel(): void {
I
isidor 已提交
1090
		this.workbenchLayout.layout({ toggleMaximizedPanel: true, source: Parts.PANEL_PART });
1091 1092
	}

1093
	isPanelMaximized(): boolean {
1094 1095 1096
		return this.workbenchLayout.isPanelMaximized();
	}

1097
	getSideBarPosition(): Position {
E
Erich Gamma 已提交
1098 1099 1100
		return this.sideBarPosition;
	}

1101
	setSideBarPosition(position: Position): void {
E
Erich Gamma 已提交
1102
		if (this.sideBarHidden) {
1103
			this.setSideBarHidden(false, true /* Skip Layout */).done(void 0, errors.onUnexpectedError);
E
Erich Gamma 已提交
1104 1105
		}

B
Benjamin Pasero 已提交
1106 1107
		const newPositionValue = (position === Position.LEFT) ? 'left' : 'right';
		const oldPositionValue = (this.sideBarPosition === Position.LEFT) ? 'left' : 'right';
E
Erich Gamma 已提交
1108 1109 1110
		this.sideBarPosition = position;

		// Adjust CSS
1111 1112 1113 1114
		DOM.removeClass(this.activitybarPart.getContainer(), oldPositionValue);
		DOM.removeClass(this.sidebarPart.getContainer(), oldPositionValue);
		DOM.addClass(this.activitybarPart.getContainer(), newPositionValue);
		DOM.addClass(this.sidebarPart.getContainer(), newPositionValue);
E
Erich Gamma 已提交
1115

1116 1117 1118 1119
		// Update Styles
		this.activitybarPart.updateStyles();
		this.sidebarPart.updateStyles();

E
Erich Gamma 已提交
1120
		// Layout
1121
		this.workbenchLayout.layout();
E
Erich Gamma 已提交
1122 1123
	}

1124
	getPanelPosition(): Position {
I
isidor 已提交
1125 1126 1127
		return this.panelPosition;
	}

1128
	setPanelPosition(position: Position): TPromise<void> {
I
isidor 已提交
1129 1130 1131 1132 1133
		return (this.panelHidden ? this.setPanelHidden(false, true /* Skip Layout */) : TPromise.as(undefined)).then(() => {
			const newPositionValue = (position === Position.BOTTOM) ? 'bottom' : 'right';
			const oldPositionValue = (this.panelPosition === Position.BOTTOM) ? 'bottom' : 'right';
			this.panelPosition = position;
			this.storageService.store(Workbench.panelPositionStorageKey, Position[this.panelPosition].toLowerCase(), StorageScope.WORKSPACE);
I
isidor 已提交
1134

I
isidor 已提交
1135
			// Adjust CSS
1136 1137
			DOM.removeClass(this.panelPart.getContainer(), oldPositionValue);
			DOM.addClass(this.panelPart.getContainer(), newPositionValue);
I
isidor 已提交
1138

I
isidor 已提交
1139 1140
			// Update Styles
			this.panelPart.updateStyles();
I
isidor 已提交
1141

I
isidor 已提交
1142 1143 1144
			// Layout
			this.workbenchLayout.layout();
		});
I
isidor 已提交
1145 1146
	}

1147
	private setFontAliasing(aliasing: FontAliasingOption) {
1148
		this.fontAliasing = aliasing;
B
Benjamin Pasero 已提交
1149 1150 1151 1152 1153 1154

		// Remove all
		document.body.classList.remove(...fontAliasingValues.map(value => `monaco-font-aliasing-${value}`));

		// Add specific
		if (fontAliasingValues.some(option => option === aliasing)) {
1155 1156
			document.body.classList.add(`monaco-font-aliasing-${aliasing}`);
		}
1157 1158
	}

1159
	layout(options?: ILayoutOptions): void {
1160 1161 1162
		if (this.isStarted()) {
			this.workbenchLayout.layout(options);
		}
E
Erich Gamma 已提交
1163 1164 1165
	}

	private createWorkbenchLayout(): void {
1166 1167
		this.workbenchLayout = this.instantiationService.createInstance(
			WorkbenchLayout,
1168 1169
			this.container,								// Parent
			this.workbench.getHTMLElement(),			// Workbench Container
I
isidor 已提交
1170
			{
B
Benjamin Pasero 已提交
1171
				titlebar: this.titlebarPart,			// Title Bar
I
isidor 已提交
1172 1173 1174 1175 1176 1177
				activitybar: this.activitybarPart,		// Activity Bar
				editor: this.editorPart,				// Editor
				sidebar: this.sidebarPart,				// Sidebar
				panel: this.panelPart,					// Panel Part
				statusbar: this.statusbarPart,			// Statusbar
			},
1178
			this.quickOpen,								// Quickopen
C
Christof Marti 已提交
1179
			this.quickInput,							// QuickInput
1180 1181
			this.notificationsCenter,					// Notifications Center
			this.notificationsToasts					// Notifications Toasts
E
Erich Gamma 已提交
1182 1183 1184 1185 1186 1187 1188 1189 1190
		);
	}

	private renderWorkbench(): void {

		// Apply sidebar state as CSS class
		if (this.sideBarHidden) {
			this.workbench.addClass('nosidebar');
		}
1191 1192 1193
		if (this.panelHidden) {
			this.workbench.addClass('nopanel');
		}
1194 1195 1196
		if (this.statusBarHidden) {
			this.workbench.addClass('nostatusbar');
		}
E
Erich Gamma 已提交
1197

B
Benjamin Pasero 已提交
1198
		// Apply font aliasing
1199 1200
		this.setFontAliasing(this.fontAliasing);

B
Benjamin Pasero 已提交
1201
		// Apply title style if shown
1202 1203 1204 1205 1206 1207 1208 1209
		const titleStyle = this.getCustomTitleBarStyle();
		if (titleStyle) {
			DOM.addClass(this.parent, `titlebar-style-${titleStyle}`);
		}

		// Apply fullscreen state
		if (browser.isFullscreen()) {
			this.workbench.addClass('fullscreen');
B
Benjamin Pasero 已提交
1210 1211
		}

E
Erich Gamma 已提交
1212
		// Create Parts
B
Benjamin Pasero 已提交
1213
		this.createTitlebarPart();
E
Erich Gamma 已提交
1214 1215 1216
		this.createActivityBarPart();
		this.createSidebarPart();
		this.createEditorPart();
1217
		this.createPanelPart();
E
Erich Gamma 已提交
1218 1219
		this.createStatusbarPart();

1220 1221
		// Notification Handlers
		this.createNotificationsHandlers();
1222

E
Erich Gamma 已提交
1223 1224 1225 1226
		// Add Workbench to DOM
		this.workbenchContainer.build(this.container);
	}

B
Benjamin Pasero 已提交
1227 1228 1229 1230 1231 1232 1233
	private createTitlebarPart(): void {
		const titlebarContainer = $(this.workbench).div({
			'class': ['part', 'titlebar'],
			id: Identifiers.TITLEBAR_PART,
			role: 'contentinfo'
		});

1234
		this.titlebarPart.create(titlebarContainer.getHTMLElement());
B
Benjamin Pasero 已提交
1235 1236
	}

E
Erich Gamma 已提交
1237
	private createActivityBarPart(): void {
B
Benjamin Pasero 已提交
1238
		const activitybarPartContainer = $(this.workbench)
E
Erich Gamma 已提交
1239 1240
			.div({
				'class': ['part', 'activitybar', this.sideBarPosition === Position.LEFT ? 'left' : 'right'],
1241 1242
				id: Identifiers.ACTIVITYBAR_PART,
				role: 'navigation'
E
Erich Gamma 已提交
1243 1244
			});

1245
		this.activitybarPart.create(activitybarPartContainer.getHTMLElement());
E
Erich Gamma 已提交
1246 1247 1248
	}

	private createSidebarPart(): void {
B
Benjamin Pasero 已提交
1249
		const sidebarPartContainer = $(this.workbench)
E
Erich Gamma 已提交
1250 1251
			.div({
				'class': ['part', 'sidebar', this.sideBarPosition === Position.LEFT ? 'left' : 'right'],
1252 1253
				id: Identifiers.SIDEBAR_PART,
				role: 'complementary'
E
Erich Gamma 已提交
1254 1255
			});

1256
		this.sidebarPart.create(sidebarPartContainer.getHTMLElement());
E
Erich Gamma 已提交
1257 1258
	}

I
isidor 已提交
1259
	private createPanelPart(): void {
B
Benjamin Pasero 已提交
1260
		const panelPartContainer = $(this.workbench)
I
isidor 已提交
1261
			.div({
1262
				'class': ['part', 'panel', this.panelPosition === Position.BOTTOM ? 'bottom' : 'right'],
1263 1264
				id: Identifiers.PANEL_PART,
				role: 'complementary'
I
isidor 已提交
1265 1266
			});

1267
		this.panelPart.create(panelPartContainer.getHTMLElement());
I
isidor 已提交
1268 1269
	}

E
Erich Gamma 已提交
1270
	private createEditorPart(): void {
B
Benjamin Pasero 已提交
1271
		const editorContainer = $(this.workbench)
E
Erich Gamma 已提交
1272
			.div({
1273
				'class': ['part', 'editor'],
1274 1275
				id: Identifiers.EDITOR_PART,
				role: 'main'
E
Erich Gamma 已提交
1276 1277
			});

1278
		this.editorPart.create(editorContainer.getHTMLElement());
E
Erich Gamma 已提交
1279 1280 1281
	}

	private createStatusbarPart(): void {
B
Benjamin Pasero 已提交
1282
		const statusbarContainer = $(this.workbench).div({
E
Erich Gamma 已提交
1283
			'class': ['part', 'statusbar'],
1284 1285
			id: Identifiers.STATUSBAR_PART,
			role: 'contentinfo'
E
Erich Gamma 已提交
1286 1287
		});

1288
		this.statusbarPart.create(statusbarContainer.getHTMLElement());
E
Erich Gamma 已提交
1289 1290
	}

1291 1292
	private createNotificationsHandlers(): void {

1293
		// Notifications Center
1294
		this.notificationsCenter = this._register(this.instantiationService.createInstance(NotificationsCenter, this.workbench.getHTMLElement(), this.notificationService.model));
1295

1296
		// Notifications Toasts
1297
		this.notificationsToasts = this._register(this.instantiationService.createInstance(NotificationsToasts, this.workbench.getHTMLElement(), this.notificationService.model));
1298

1299
		// Notifications Alerts
1300
		this._register(this.instantiationService.createInstance(NotificationsAlerts, this.notificationService.model));
1301 1302 1303 1304

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

1305
		// Eventing
1306
		this._register(this.notificationsCenter.onDidChangeVisibility(() => {
1307 1308 1309 1310 1311 1312 1313 1314

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

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

1315
		// Register Commands
1316
		registerNotificationCommands(this.notificationsCenter, this.notificationsToasts);
1317 1318
	}

1319
	getInstantiationService(): IInstantiationService {
E
Erich Gamma 已提交
1320 1321 1322
		return this.instantiationService;
	}

1323
	getWorkbenchElementId(): string {
1324 1325
		return Identifiers.WORKBENCH_CONTAINER;
	}
1326

1327
	toggleZenMode(skipLayout?: boolean): void {
I
isidor 已提交
1328
		this.zenMode.active = !this.zenMode.active;
1329
		this.zenMode.transitionDisposeables = dispose(this.zenMode.transitionDisposeables);
1330

1331 1332
		// 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)
1333
		let toggleFullScreen = false;
1334 1335

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

I
isidor 已提交
1339
			toggleFullScreen = !browser.isFullscreen() && config.fullScreen;
I
isidor 已提交
1340
			this.zenMode.transitionedToFullScreen = toggleFullScreen;
1341
			this.zenMode.transitionedToCenteredEditorLayout = !this.isEditorLayoutCentered() && config.centerLayout;
1342 1343
			this.zenMode.wasSideBarVisible = this.isVisible(Parts.SIDEBAR_PART);
			this.zenMode.wasPanelVisible = this.isVisible(Parts.PANEL_PART);
1344

1345 1346
			this.setPanelHidden(true, true).done(void 0, errors.onUnexpectedError);
			this.setSideBarHidden(true, true).done(void 0, errors.onUnexpectedError);
I
isidor 已提交
1347

1348 1349 1350
			if (config.hideActivityBar) {
				this.setActivityBarHidden(true, true);
			}
1351

I
isidor 已提交
1352
			if (config.hideStatusBar) {
I
isidor 已提交
1353 1354
				this.setStatusBarHidden(true, true);
			}
1355

1356 1357
			if (config.hideTabs && this.editorPart.partOptions.showTabs) {
				this.zenMode.transitionDisposeables.push(this.editorPart.enforcePartOptions({ showTabs: false }));
I
isidor 已提交
1358
			}
1359 1360 1361 1362

			if (config.centerLayout) {
				this.centerEditorLayout(true, true);
			}
1363 1364 1365 1366
		}

		// Zen Mode Inactive
		else {
1367
			if (this.zenMode.wasPanelVisible) {
1368
				this.setPanelHidden(false, true).done(void 0, errors.onUnexpectedError);
1369
			}
1370

1371
			if (this.zenMode.wasSideBarVisible) {
1372
				this.setSideBarHidden(false, true).done(void 0, errors.onUnexpectedError);
1373
			}
1374

1375 1376 1377
			if (this.zenMode.transitionedToCenteredEditorLayout) {
				this.centerEditorLayout(false, true);
			}
1378

1379 1380
			// Status bar and activity bar visibility come from settings -> update their visibility.
			this.onDidUpdateConfiguration(true);
1381 1382

			const activeEditor = this.nextEditorService.activeControl;
I
isidor 已提交
1383 1384 1385
			if (activeEditor) {
				activeEditor.focus();
			}
1386

1387
			toggleFullScreen = this.zenMode.transitionedToFullScreen && browser.isFullscreen();
I
isidor 已提交
1388
		}
1389

1390
		this.inZenMode.set(this.zenMode.active);
I
isidor 已提交
1391

I
isidor 已提交
1392
		if (!skipLayout) {
1393
			this.layout();
I
isidor 已提交
1394
		}
1395

1396
		if (toggleFullScreen) {
1397
			this.windowService.toggleFullScreen().done(void 0, errors.onUnexpectedError);
1398
		}
I
isidor 已提交
1399 1400
	}

1401
	isEditorLayoutCentered(): boolean {
B
Benjamin Pasero 已提交
1402
		return this.centeredEditorLayoutActive;
S
SrTobi 已提交
1403 1404
	}

1405 1406 1407 1408
	// TODO@grid support centered editor layout using empty groups or not? functionality missing:
	// - proper initial sizing (left and right empty group sizes are not the same)
	// - resize sashes left and right in sync
	// - IEditorInput.supportsCenteredEditorLayout() no longer supported
1409
	centerEditorLayout(active: boolean, skipLayout?: boolean): void {
1410
		this.centeredEditorLayoutActive = active;
B
Benjamin Pasero 已提交
1411 1412
		this.storageService.store(Workbench.centeredEditorLayoutActiveStorageKey, this.centeredEditorLayoutActive, StorageScope.GLOBAL);

1413 1414 1415 1416
		// Enter Centered Editor Layout
		if (active) {
			if (this.nextEditorGroupsService.count === 1) {
				const activeGroup = this.nextEditorGroupsService.activeGroup;
1417 1418
				this.nextEditorGroupsService.addGroup(activeGroup, GroupDirection.LEFT);
				this.nextEditorGroupsService.addGroup(activeGroup, GroupDirection.RIGHT);
1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432
			}
		}

		// Leave Centered Editor Layout
		else {
			if (this.nextEditorGroupsService.count === 3) {
				this.nextEditorGroupsService.groups.forEach(group => {
					if (group.count === 0) {
						this.nextEditorGroupsService.removeGroup(group);
					}
				});
			}
		}

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

1438
	resizePart(part: Parts, sizeChange: number): void {
1439 1440 1441 1442 1443 1444 1445
		switch (part) {
			case Parts.SIDEBAR_PART:
			case Parts.PANEL_PART:
			case Parts.EDITOR_PART:
				this.workbenchLayout.resizePart(part, sizeChange);
				break;
			default:
B
Benjamin Pasero 已提交
1446
				return; // Cannot resize other parts
1447 1448 1449
		}
	}

1450 1451
	dispose(reason = ShutdownReason.QUIT): void {
		super.dispose();
1452

1453 1454 1455
		// Restore sidebar if we are being shutdown as a matter of a reload
		if (reason === ShutdownReason.RELOAD) {
			this.storageService.store(Workbench.sidebarRestoreStorageKey, 'true', StorageScope.WORKSPACE);
1456 1457
		}

1458 1459 1460 1461 1462 1463 1464 1465 1466 1467
		// Preserve zen mode only on reload. Real quit gets out of zen mode so novice users do not get stuck in zen mode.
		const zenConfig = this.configurationService.getValue<IZenModeSettings>('zenMode');
		const restoreZenMode = this.zenMode.active && (zenConfig.restore || reason === ShutdownReason.RELOAD);
		if (restoreZenMode) {
			this.storageService.store(Workbench.zenModeActiveStorageKey, true, StorageScope.WORKSPACE);
		} else {
			if (this.zenMode.active) {
				this.toggleZenMode(true);
			}
			this.storageService.remove(Workbench.zenModeActiveStorageKey, StorageScope.WORKSPACE);
1468 1469
		}

1470 1471
		// Pass shutdown on to each participant
		this.workbenchShutdown = true;
1472
	}
J
Johannes Rieken 已提交
1473
}