workbench.ts 50.8 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';
J
Johannes Rieken 已提交
11 12
import { TPromise, ValueCallback } from 'vs/base/common/winjs.base';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
13
import Event, { Emitter, chain } from 'vs/base/common/event';
E
Erich Gamma 已提交
14
import DOM = require('vs/base/browser/dom');
B
Benjamin Pasero 已提交
15
import { Builder, $ } from 'vs/base/browser/builder';
16
import { Delayer, RunOnceScheduler } from 'vs/base/common/async';
17
import * as browser from 'vs/base/browser/browser';
E
Erich Gamma 已提交
18
import assert = require('vs/base/common/assert');
19
import { StopWatch } from 'vs/base/common/stopwatch';
20
import { startTimer } from 'vs/base/node/startupTimers';
E
Erich Gamma 已提交
21
import errors = require('vs/base/common/errors');
22
import { BackupFileService } from 'vs/workbench/services/backup/node/backupFileService';
23
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
J
Johannes Rieken 已提交
24
import { toErrorMessage } from 'vs/base/common/errorMessage';
25
import { Registry } from 'vs/platform/registry/common/platform';
B
Benjamin Pasero 已提交
26
import { isWindows, isLinux, isMacintosh } from 'vs/base/common/platform';
B
Benjamin Pasero 已提交
27
import { Position as EditorPosition, IResourceDiffInput, IUntitledResourceInput, IEditor, IResourceInput } from 'vs/platform/editor/common/editor';
J
Johannes Rieken 已提交
28
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
29
import { IEditorInputFactoryRegistry, Extensions as EditorExtensions } from 'vs/workbench/common/editor';
J
Johannes Rieken 已提交
30 31 32 33 34 35
import { HistoryService } from 'vs/workbench/services/history/browser/history';
import { ActivitybarPart } from 'vs/workbench/browser/parts/activitybar/activitybarPart';
import { EditorPart } from 'vs/workbench/browser/parts/editor/editorPart';
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 已提交
36 37
import { TitlebarPart } from 'vs/workbench/browser/parts/titlebar/titlebarPart';
import { WorkbenchLayout } from 'vs/workbench/browser/layout';
38
import { IActionBarRegistry, Extensions as ActionBarExtensions } from 'vs/workbench/browser/actions';
J
Johannes Rieken 已提交
39 40 41
import { PanelRegistry, Extensions as PanelExtensions } from 'vs/workbench/browser/panel';
import { QuickOpenController } from 'vs/workbench/browser/parts/quickopen/quickOpenController';
import { getServices } from 'vs/platform/instantiation/common/extensions';
I
isidor 已提交
42
import { Position, Parts, IPartService, ILayoutOptions } from 'vs/workbench/services/part/common/partService';
43
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
J
Johannes Rieken 已提交
44 45 46 47
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';
48
import { WorkspaceService, DefaultConfigurationExportHelper } from 'vs/workbench/services/configuration/node/configurationService';
49 50
import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing';
import { JSONEditingService } from 'vs/workbench/services/configuration/node/jsonEditingService';
J
Johannes Rieken 已提交
51 52
import { ContextKeyService } from 'vs/platform/contextkey/browser/contextKeyService';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
53
import { IKeybindingEditingService, KeybindingsEditingService } from 'vs/workbench/services/keybinding/common/keybindingEditing';
J
Johannes Rieken 已提交
54
import { ContextKeyExpr, RawContextKey, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
I
isidor 已提交
55
import { IActivityService } from 'vs/workbench/services/activity/common/activity';
B
Benjamin Pasero 已提交
56
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
P
Pine Wu 已提交
57
import { ViewletService } from 'vs/workbench/services/viewlet/browser/viewletService';
58
import { RemoteFileService } from 'vs/workbench/services/files/electron-browser/remoteFileService';
J
Johannes Rieken 已提交
59
import { IFileService } from 'vs/platform/files/common/files';
60
import { IListService, ListService } from 'vs/platform/list/browser/listService';
J
Johannes Rieken 已提交
61 62 63
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
import { ConfigurationResolverService } from 'vs/workbench/services/configurationResolver/node/configurationResolverService';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
B
Benjamin Pasero 已提交
64
import { ITitleService } from 'vs/workbench/services/title/common/titleService';
J
Johannes Rieken 已提交
65
import { WorkbenchMessageService } from 'vs/workbench/services/message/browser/messageService';
B
Benjamin Pasero 已提交
66
import { IWorkbenchEditorService, IResourceInputType, WorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
J
Johannes Rieken 已提交
67
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
68 69
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { ClipboardService } from 'vs/platform/clipboard/electron-browser/clipboardService';
J
Johannes Rieken 已提交
70 71 72 73 74 75
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 已提交
76 77
import { ISCMService } from 'vs/workbench/services/scm/common/scm';
import { SCMService } from 'vs/workbench/services/scm/common/scmService';
78 79
import { IProgressService2 } from 'vs/platform/progress/common/progress';
import { ProgressService2 } from 'vs/workbench/services/progress/browser/progressService2';
80
import { TextModelResolverService } from 'vs/workbench/services/textmodelResolver/common/textModelResolverService';
81
import { ITextModelService } from 'vs/editor/common/services/resolverService';
J
Johannes Rieken 已提交
82
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
83
import { ILifecycleService, ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle';
B
Benjamin Pasero 已提交
84
import { IWindowService, IWindowConfiguration as IWindowSettings, IWindowConfiguration, IPath } from 'vs/platform/windows/common/windows';
J
Johannes Rieken 已提交
85 86
import { IMessageService } from 'vs/platform/message/common/message';
import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar';
87
import { IMenuService, SyncActionDescriptor } from 'vs/platform/actions/common/actions';
J
Johannes Rieken 已提交
88 89 90 91
import { MenuService } from 'vs/platform/actions/common/menuService';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
B
Benjamin Pasero 已提交
92
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
93
import { OpenRecentAction, ToggleDevToolsAction, ReloadWindowAction, ShowPreviousWindowTab, MoveWindowTabToNewWindow, MergeAllWindowTabs, ShowNextWindowTab, ToggleWindowTabsBar } from 'vs/workbench/electron-browser/actions';
94
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
95
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
B
Benjamin Pasero 已提交
96
import { WorkspaceEditingService } from 'vs/workbench/services/workspace/node/workspaceEditingService';
97
import { FileDecorationsService } from 'vs/workbench/services/decorations/browser/decorationsService';
J
Johannes Rieken 已提交
98
import { IDecorationsService } from 'vs/workbench/services/decorations/browser/decorations';
I
isidor 已提交
99
import { ActivityService } from 'vs/workbench/services/activity/browser/activityService';
B
Benjamin Pasero 已提交
100
import URI from 'vs/base/common/uri';
101

A
Alex Dima 已提交
102 103
export const MessagesVisibleContext = new RawContextKey<boolean>('globalMessageVisible', false);
export const EditorsVisibleContext = new RawContextKey<boolean>('editorIsOpen', false);
I
isidor 已提交
104
export const InZenModeContext = new RawContextKey<boolean>('inZenMode', false);
J
Johannes Rieken 已提交
105
export const NoEditorsVisibleContext: ContextKeyExpr = EditorsVisibleContext.toNegated();
A
Alex Dima 已提交
106

E
Erich Gamma 已提交
107
interface WorkbenchParams {
108
	configuration: IWindowConfiguration;
109
	serviceCollection: ServiceCollection;
E
Erich Gamma 已提交
110 111
}

I
isidor 已提交
112 113 114
interface IZenModeSettings {
	fullScreen: boolean;
	hideTabs: boolean;
115
	hideActivityBar: boolean;
I
isidor 已提交
116
	hideStatusBar: boolean;
I
isidor 已提交
117
	restore: boolean;
I
isidor 已提交
118 119
}

120 121 122 123 124
export interface IWorkbenchStartedInfo {
	customKeybindingsCount: number;
	restoreViewletDuration: number;
	restoreEditorsDuration: number;
	pinnedViewlets: string[];
125 126
	restoredViewlet: string;
	restoredEditors: string[];
127 128
}

E
Erich Gamma 已提交
129 130
export interface IWorkbenchCallbacks {
	onServicesCreated?: () => void;
131
	onWorkbenchStarted?: (info: IWorkbenchStartedInfo) => void;
E
Erich Gamma 已提交
132 133
}

134 135
const Identifiers = {
	WORKBENCH_CONTAINER: 'workbench.main.container',
B
Benjamin Pasero 已提交
136
	TITLEBAR_PART: 'workbench.parts.titlebar',
137 138 139 140 141 142 143
	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'
};

E
Erich Gamma 已提交
144
/**
B
Benjamin Pasero 已提交
145
 * The workbench creates and lays out all parts that make up the workbench.
E
Erich Gamma 已提交
146 147 148 149
 */
export class Workbench implements IPartService {

	private static sidebarHiddenSettingKey = 'workbench.sidebar.hidden';
150
	private static sidebarRestoreSettingKey = 'workbench.sidebar.restore';
I
isidor 已提交
151
	private static panelHiddenSettingKey = 'workbench.panel.hidden';
I
isidor 已提交
152
	private static zenModeActiveSettingKey = 'workbench.zenmode.active';
E
Erich Gamma 已提交
153

154
	private static sidebarPositionConfigurationKey = 'workbench.sideBar.location';
155
	private static statusbarVisibleConfigurationKey = 'workbench.statusBar.visible';
S
Sanders Lauture 已提交
156
	private static activityBarVisibleConfigurationKey = 'workbench.activityBar.visible';
157

158 159
	private static closeWhenEmptyConfigurationKey = 'window.closeWhenEmpty';

160 161
	private static fontAliasingConfigurationKey = 'workbench.fontAliasing';

162 163
	private _onTitleBarVisibilityChange: Emitter<void>;

164
	public _serviceBrand: any;
E
Erich Gamma 已提交
165

B
Benjamin Pasero 已提交
166
	private parent: HTMLElement;
E
Erich Gamma 已提交
167 168 169 170 171 172 173
	private container: HTMLElement;
	private workbenchParams: WorkbenchParams;
	private workbenchContainer: Builder;
	private workbench: Builder;
	private workbenchStarted: boolean;
	private workbenchCreated: boolean;
	private workbenchShutdown: boolean;
174
	private editorService: WorkbenchEditorService;
P
Pine Wu 已提交
175
	private viewletService: IViewletService;
176
	private contextKeyService: IContextKeyService;
177
	private keybindingService: IKeybindingService;
178
	private backupFileService: IBackupFileService;
179
	private fileService: IFileService;
B
Benjamin Pasero 已提交
180
	private titlebarPart: TitlebarPart;
E
Erich Gamma 已提交
181 182
	private activitybarPart: ActivitybarPart;
	private sidebarPart: SidebarPart;
I
isidor 已提交
183
	private panelPart: PanelPart;
E
Erich Gamma 已提交
184 185 186 187 188 189 190 191 192 193
	private editorPart: EditorPart;
	private statusbarPart: StatusbarPart;
	private quickOpen: QuickOpenController;
	private workbenchLayout: WorkbenchLayout;
	private toDispose: IDisposable[];
	private toShutdown: { shutdown: () => void; }[];
	private callbacks: IWorkbenchCallbacks;
	private creationPromise: TPromise<boolean>;
	private creationPromiseComplete: ValueCallback;
	private sideBarHidden: boolean;
194
	private statusBarHidden: boolean;
S
Sanders Lauture 已提交
195
	private activityBarHidden: boolean;
E
Erich Gamma 已提交
196
	private sideBarPosition: Position;
I
isidor 已提交
197
	private panelHidden: boolean;
E
Erich Gamma 已提交
198
	private editorBackgroundDelayer: Delayer<void>;
199
	private closeEmptyWindowScheduler: RunOnceScheduler;
A
Alex Dima 已提交
200 201
	private messagesVisibleContext: IContextKey<boolean>;
	private editorsVisibleContext: IContextKey<boolean>;
I
isidor 已提交
202
	private inZenMode: IContextKey<boolean>;
203
	private hasFilesToCreateOpenOrDiff: boolean;
204
	private fontAliasing: string;
I
isidor 已提交
205
	private zenMode: {
I
isidor 已提交
206 207
		active: boolean;
		transitionedToFullScreen: boolean;
208 209
		wasSideBarVisible: boolean;
		wasPanelVisible: boolean;
I
isidor 已提交
210
	};
E
Erich Gamma 已提交
211

212
	constructor(
B
Benjamin Pasero 已提交
213
		parent: HTMLElement,
214
		container: HTMLElement,
215
		configuration: IWindowConfiguration,
216
		serviceCollection: ServiceCollection,
217
		@IInstantiationService private instantiationService: IInstantiationService,
218
		@IWorkspaceContextService private contextService: IWorkspaceContextService,
219 220 221
		@IStorageService private storageService: IStorageService,
		@ILifecycleService private lifecycleService: ILifecycleService,
		@IMessageService private messageService: IMessageService,
222
		@IConfigurationService private configurationService: WorkspaceService,
223
		@ITelemetryService private telemetryService: ITelemetryService,
I
isidor 已提交
224 225
		@IEnvironmentService private environmentService: IEnvironmentService,
		@IWindowService private windowService: IWindowService
226
	) {
B
Benjamin Pasero 已提交
227
		this.parent = parent;
228
		this.container = container;
E
Erich Gamma 已提交
229 230

		this.workbenchParams = {
231
			configuration,
232
			serviceCollection
E
Erich Gamma 已提交
233 234
		};

235
		this.hasFilesToCreateOpenOrDiff =
B
Benjamin Pasero 已提交
236 237 238
			(configuration.filesToCreate && configuration.filesToCreate.length > 0) ||
			(configuration.filesToOpen && configuration.filesToOpen.length > 0) ||
			(configuration.filesToDiff && configuration.filesToDiff.length > 0);
239

E
Erich Gamma 已提交
240 241
		this.toDispose = [];
		this.toShutdown = [];
242

E
Erich Gamma 已提交
243
		this.editorBackgroundDelayer = new Delayer<void>(50);
244
		this.closeEmptyWindowScheduler = new RunOnceScheduler(() => this.onAllEditorsClosed(), 50);
E
Erich Gamma 已提交
245

246 247
		this._onTitleBarVisibilityChange = new Emitter<void>();

248
		this.creationPromise = new TPromise<boolean>(c => {
E
Erich Gamma 已提交
249 250 251 252
			this.creationPromiseComplete = c;
		});
	}

253 254 255 256
	public get onTitleBarVisibilityChange(): Event<void> {
		return this._onTitleBarVisibilityChange.event;
	}

257 258 259 260 261 262
	public get onEditorLayout(): Event<void> {
		return chain(this.editorPart.onLayout)
			.map(() => void 0)
			.event;
	}

E
Erich Gamma 已提交
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
	/**
	 * Starts the workbench and creates the HTML elements on the container. A workbench can only be started
	 * once. Use the shutdown function to free up resources created by the workbench on startup.
	 */
	public startup(callbacks?: IWorkbenchCallbacks): void {
		assert.ok(!this.workbenchStarted, 'Can not start a workbench that was already started');
		assert.ok(!this.workbenchShutdown, 'Can not start a workbench that was shutdown');

		try {
			this.workbenchStarted = true;
			this.callbacks = callbacks;

			// Create Workbench
			this.createWorkbench();

278 279 280
			// Install some global actions
			this.createGlobalActions();

E
Erich Gamma 已提交
281 282 283 284 285 286
			// Services
			this.initServices();
			if (this.callbacks && this.callbacks.onServicesCreated) {
				this.callbacks.onServicesCreated();
			}

287
			// Contexts
288 289
			this.messagesVisibleContext = MessagesVisibleContext.bindTo(this.contextKeyService);
			this.editorsVisibleContext = EditorsVisibleContext.bindTo(this.contextKeyService);
I
isidor 已提交
290
			this.inZenMode = InZenModeContext.bindTo(this.contextKeyService);
291

E
Erich Gamma 已提交
292 293 294 295 296 297 298 299 300 301 302 303
			// Register Listeners
			this.registerListeners();

			// Settings
			this.initSettings();

			// Create Workbench and Parts
			this.renderWorkbench();

			// Workbench Layout
			this.createWorkbenchLayout();

B
Benjamin Pasero 已提交
304
			// Load composites and editors in parallel
B
Benjamin Pasero 已提交
305
			const compositeAndEditorPromises: TPromise<any>[] = [];
E
Erich Gamma 已提交
306

P
Pine Wu 已提交
307
			// Restore last opened viewlet
308
			let viewletRestoreStopWatch: StopWatch;
309
			let viewletIdToRestore: string;
310
			if (!this.sideBarHidden) {
311

312
				if (this.shouldRestoreLastOpenedViewlet()) {
313
					viewletIdToRestore = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE);
B
polish  
Benjamin Pasero 已提交
314 315 316
				}

				if (!viewletIdToRestore) {
317
					viewletIdToRestore = this.viewletService.getDefaultViewletId();
P
Pine Wu 已提交
318
				}
319

320
				viewletRestoreStopWatch = StopWatch.create();
321 322
				const viewletTimer = startTimer('restore:viewlet');
				compositeAndEditorPromises.push(viewletTimer.while(this.viewletService.openViewlet(viewletIdToRestore)).then(() => {
323 324
					viewletRestoreStopWatch.stop();
				}));
E
Erich Gamma 已提交
325 326
			}

B
Benjamin Pasero 已提交
327
			// Load Panel
328
			const panelRegistry = Registry.as<PanelRegistry>(PanelExtensions.Panels);
329 330
			const panelId = this.storageService.get(PanelPart.activePanelSettingsKey, StorageScope.WORKSPACE, panelRegistry.getDefaultPanelId());
			if (!this.panelHidden && !!panelId) {
I
isidor 已提交
331
				compositeAndEditorPromises.push(this.panelPart.openPanel(panelId, false));
332 333
			}

B
Benjamin Pasero 已提交
334
			// Load Editors
335
			const editorRestoreStopWatch = StopWatch.create();
336
			const restoredEditors: string[] = [];
337 338
			const editorsTimer = startTimer('restore:editors');
			compositeAndEditorPromises.push(editorsTimer.while(this.resolveEditorsToOpen().then(inputs => {
339
				let editorOpenPromise: TPromise<IEditor[]>;
340 341
				if (inputs.length) {
					editorOpenPromise = this.editorService.openEditors(inputs.map(input => { return { input, position: EditorPosition.ONE }; }));
B
Benjamin Pasero 已提交
342
				} else {
B
Benjamin Pasero 已提交
343
					editorOpenPromise = this.editorPart.restoreEditors();
344
				}
345

346
				return editorOpenPromise.then(editors => {
B
Benjamin Pasero 已提交
347
					this.handleEditorBackground(); // make sure we show the proper background in the editor area
348
					editorRestoreStopWatch.stop();
B
Benjamin Pasero 已提交
349

350
					for (const editor of editors) {
B
Benjamin Pasero 已提交
351 352 353 354 355 356
						if (editor) {
							if (editor.input) {
								restoredEditors.push(editor.input.getName());
							} else {
								restoredEditors.push(`other:${editor.getId()}`);
							}
357 358
						}
					}
E
Erich Gamma 已提交
359
				});
360
			})));
E
Erich Gamma 已提交
361

362
			if (this.storageService.getBoolean(Workbench.zenModeActiveSettingKey, StorageScope.WORKSPACE, false)) {
I
isidor 已提交
363 364 365
				this.toggleZenMode(true);
			}

E
Erich Gamma 已提交
366
			// Flag workbench as created once done
367
			const workbenchDone = (error?: Error) => {
E
Erich Gamma 已提交
368 369 370
				this.workbenchCreated = true;
				this.creationPromiseComplete(true);

B
Benjamin Pasero 已提交
371
				if (this.callbacks && this.callbacks.onWorkbenchStarted) {
372 373
					this.callbacks.onWorkbenchStarted({
						customKeybindingsCount: this.keybindingService.customKeybindingsCount(),
374 375
						restoreViewletDuration: viewletRestoreStopWatch ? Math.round(viewletRestoreStopWatch.elapsed()) : 0,
						restoreEditorsDuration: Math.round(editorRestoreStopWatch.elapsed()),
B
Benjamin Pasero 已提交
376
						pinnedViewlets: this.activitybarPart.getPinned(),
377 378
						restoredViewlet: viewletIdToRestore,
						restoredEditors
379
					});
B
Benjamin Pasero 已提交
380
				}
381 382 383 384 385 386

				if (error) {
					errors.onUnexpectedError(error);
				}
			};

B
polish  
Benjamin Pasero 已提交
387
			// Join viewlet, panel and editor promises
388
			TPromise.join(compositeAndEditorPromises).then(() => workbenchDone(), error => workbenchDone(error));
E
Erich Gamma 已提交
389 390 391
		} catch (error) {

			// Print out error
392
			console.error(toErrorMessage(error, true));
E
Erich Gamma 已提交
393 394 395 396 397 398

			// Rethrow
			throw error;
		}
	}

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

B
Benjamin Pasero 已提交
402
		// Actions registered here to adjust for developing vs built workbench
403 404
		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 已提交
405
		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 已提交
406
		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"));
407

408
		// Actions for macOS native tabs management (only when enabled)
409
		const windowConfig = this.configurationService.getConfiguration<IWindowConfiguration>();
410 411 412 413 414 415 416
		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');
		}
417 418
	}

419
	private resolveEditorsToOpen(): TPromise<IResourceInputType[]> {
420
		const config = this.workbenchParams.configuration;
B
Benjamin Pasero 已提交
421 422

		// Files to open, diff or create
423
		if (this.hasFilesToCreateOpenOrDiff) {
B
Benjamin Pasero 已提交
424 425

			// Files to diff is exclusive
426
			const filesToDiff = this.toInputs(config.filesToDiff, false);
427
			if (filesToDiff && filesToDiff.length === 2) {
428 429 430 431 432
				return TPromise.as([<IResourceDiffInput>{
					leftResource: filesToDiff[0].resource,
					rightResource: filesToDiff[1].resource,
					options: { pinned: true }
				}]);
B
Benjamin Pasero 已提交
433 434
			}

435 436
			const filesToCreate = this.toInputs(config.filesToCreate, true);
			const filesToOpen = this.toInputs(config.filesToOpen, false);
437

438 439
			// Otherwise: Open/Create files
			return TPromise.as([...filesToOpen, ...filesToCreate]);
B
Benjamin Pasero 已提交
440 441
		}

442
		// Empty workbench
443
		else if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY && this.openUntitledFile()) {
444 445 446 447
			if (this.editorPart.hasEditorsToRestore()) {
				return TPromise.as([]); // do not open any empty untitled file if we have editors to restore
			}

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

453
				return TPromise.as([<IUntitledResourceInput>{}]);
454
			});
B
Benjamin Pasero 已提交
455 456 457 458 459
		}

		return TPromise.as([]);
	}

460
	private toInputs(paths: IPath[], isNew: boolean): (IResourceInput | IUntitledResourceInput)[] {
B
Benjamin Pasero 已提交
461 462 463 464 465
		if (!paths || !paths.length) {
			return [];
		}

		return paths.map(p => {
466 467 468 469 470 471 472
			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 已提交
473

474
			if (!isNew && p.lineNumber) {
B
Benjamin Pasero 已提交
475 476 477 478 479 480 481 482 483 484
				input.options.selection = {
					startLineNumber: p.lineNumber,
					startColumn: p.columnNumber
				};
			}

			return input;
		});
	}

485
	private openUntitledFile() {
486
		const startupEditor = this.configurationService.inspect('workbench.startupEditor');
B
Benjamin Pasero 已提交
487 488

		// Fallback to previous workbench.welcome.enabled setting in case startupEditor is not defined
489
		if (!startupEditor.user && !startupEditor.workspace) {
490 491 492
			const welcomeEnabledValue = this.configurationService.getValue('workbench.welcome.enabled');
			if (typeof welcomeEnabledValue === 'boolean') {
				return !welcomeEnabledValue;
493 494
			}
		}
B
Benjamin Pasero 已提交
495

496
		return startupEditor.value === 'newUntitledFile';
497 498
	}

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

502
		this.toDispose.push(this.lifecycleService.onShutdown(this.shutdownComponents, this));
E
Erich Gamma 已提交
503 504

		// Services we contribute
505
		serviceCollection.set(IPartService, this);
E
Erich Gamma 已提交
506

507 508 509
		// Clipboard
		serviceCollection.set(IClipboardService, new ClipboardService());

510 511 512 513 514 515
		// Status bar
		this.statusbarPart = this.instantiationService.createInstance(StatusbarPart, Identifiers.STATUSBAR_PART);
		this.toDispose.push(this.statusbarPart);
		this.toShutdown.push(this.statusbarPart);
		serviceCollection.set(IStatusbarService, this.statusbarPart);

516 517 518
		// Progress 2
		serviceCollection.set(IProgressService2, new SyncDescriptor(ProgressService2));

519
		// Keybindings
A
Alex Dima 已提交
520
		this.contextKeyService = this.instantiationService.createInstance(ContextKeyService);
521
		serviceCollection.set(IContextKeyService, this.contextKeyService);
522

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

526 527 528
		// List
		serviceCollection.set(IListService, this.instantiationService.createInstance(ListService));

529
		// Context Menu
530
		serviceCollection.set(IContextMenuService, new SyncDescriptor(ContextMenuService));
531

532 533
		// Menus/Actions
		serviceCollection.set(IMenuService, new SyncDescriptor(MenuService));
534

P
Pine Wu 已提交
535
		// Sidebar part
536
		this.sidebarPart = this.instantiationService.createInstance(SidebarPart, Identifiers.SIDEBAR_PART);
E
Erich Gamma 已提交
537 538
		this.toDispose.push(this.sidebarPart);
		this.toShutdown.push(this.sidebarPart);
P
Pine Wu 已提交
539 540 541 542

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

I
isidor 已提交
544
		// Panel service (panel part)
545
		this.panelPart = this.instantiationService.createInstance(PanelPart, Identifiers.PANEL_PART);
I
isidor 已提交
546 547
		this.toDispose.push(this.panelPart);
		this.toShutdown.push(this.panelPart);
548
		serviceCollection.set(IPanelService, this.panelPart);
I
isidor 已提交
549

E
Erich Gamma 已提交
550
		// Activity service (activitybar part)
551
		this.activitybarPart = this.instantiationService.createInstance(ActivitybarPart, Identifiers.ACTIVITYBAR_PART);
E
Erich Gamma 已提交
552 553
		this.toDispose.push(this.activitybarPart);
		this.toShutdown.push(this.activitybarPart);
I
isidor 已提交
554 555
		const activityService = this.instantiationService.createInstance(ActivityService, this.activitybarPart, this.panelPart);
		serviceCollection.set(IActivityService, activityService);
E
Erich Gamma 已提交
556

557 558 559 560 561
		// File Service
		this.fileService = this.instantiationService.createInstance(RemoteFileService);
		serviceCollection.set(IFileService, this.fileService);
		this.toDispose.push(this.fileService.onFileChanges(e => this.configurationService.handleWorkspaceFileEvents(e)));

E
Erich Gamma 已提交
562
		// Editor service (editor part)
563
		this.editorPart = this.instantiationService.createInstance(EditorPart, Identifiers.EDITOR_PART, !this.hasFilesToCreateOpenOrDiff);
E
Erich Gamma 已提交
564 565
		this.toDispose.push(this.editorPart);
		this.toShutdown.push(this.editorPart);
566
		this.editorService = this.instantiationService.createInstance(WorkbenchEditorService, this.editorPart);
567
		serviceCollection.set(IWorkbenchEditorService, this.editorService);
568
		serviceCollection.set(IEditorGroupService, this.editorPart);
E
Erich Gamma 已提交
569

570 571 572 573 574 575
		// Title bar
		this.titlebarPart = this.instantiationService.createInstance(TitlebarPart, Identifiers.TITLEBAR_PART);
		this.toDispose.push(this.titlebarPart);
		this.toShutdown.push(this.titlebarPart);
		serviceCollection.set(ITitleService, this.titlebarPart);

576
		// History
577
		serviceCollection.set(IHistoryService, new SyncDescriptor(HistoryService));
578

579
		// Backup File Service
580
		this.backupFileService = this.instantiationService.createInstance(BackupFileService, this.workbenchParams.configuration.backupPath);
581
		serviceCollection.set(IBackupFileService, this.backupFileService);
582

583
		// Text File Service
584
		serviceCollection.set(ITextFileService, new SyncDescriptor(TextFileService));
585

586
		// File Decorations
J
Johannes Rieken 已提交
587
		serviceCollection.set(IDecorationsService, new SyncDescriptor(FileDecorationsService));
588

J
Joao Moreno 已提交
589
		// SCM Service
590
		serviceCollection.set(ISCMService, new SyncDescriptor(SCMService));
591

B
Benjamin Pasero 已提交
592
		// Text Model Resolver Service
593
		serviceCollection.set(ITextModelService, new SyncDescriptor(TextModelResolverService));
B
Benjamin Pasero 已提交
594

595 596 597 598
		// JSON Editing
		const jsonEditingService = this.instantiationService.createInstance(JSONEditingService);
		serviceCollection.set(IJSONEditingService, jsonEditingService);

599 600 601
		// Workspace Editing
		serviceCollection.set(IWorkspaceEditingService, new SyncDescriptor(WorkspaceEditingService));

602 603 604
		// Keybinding Editing
		serviceCollection.set(IKeybindingEditingService, this.instantiationService.createInstance(KeybindingsEditingService));

605
		// Configuration Resolver
B
Benjamin Pasero 已提交
606
		serviceCollection.set(IConfigurationResolverService, new SyncDescriptor(ConfigurationResolverService, process.env));
607

E
Erich Gamma 已提交
608
		// Quick open service (quick open controller)
609
		this.quickOpen = this.instantiationService.createInstance(QuickOpenController);
E
Erich Gamma 已提交
610 611
		this.toDispose.push(this.quickOpen);
		this.toShutdown.push(this.quickOpen);
612
		serviceCollection.set(IQuickOpenService, this.quickOpen);
613

B
polish  
Benjamin Pasero 已提交
614
		// Contributed services
B
Benjamin Pasero 已提交
615
		const contributedServices = getServices();
E
Erich Gamma 已提交
616
		for (let contributedService of contributedServices) {
617
			serviceCollection.set(contributedService.id, contributedService.descriptor);
E
Erich Gamma 已提交
618 619 620
		}

		// Set the some services to registries that have been created eagerly
621 622
		Registry.as<IActionBarRegistry>(ActionBarExtensions.Actionbar).setInstantiationService(this.instantiationService);
		Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).setInstantiationService(this.instantiationService);
623
		Registry.as<IEditorInputFactoryRegistry>(EditorExtensions.EditorInputFactories).setInstantiationService(this.instantiationService);
624

625
		this.instantiationService.createInstance(DefaultConfigurationExportHelper);
626 627

		this.configurationService.setInstantiationService(this.getInstantiationService());
E
Erich Gamma 已提交
628 629 630 631 632
	}

	private initSettings(): void {

		// Sidebar visibility
633
		this.sideBarHidden = this.storageService.getBoolean(Workbench.sidebarHiddenSettingKey, StorageScope.WORKSPACE, this.contextService.getWorkbenchState() === WorkbenchState.EMPTY);
E
Erich Gamma 已提交
634

I
isidor 已提交
635
		// Panel part visibility
636
		const panelRegistry = Registry.as<PanelRegistry>(PanelExtensions.Panels);
B
Benjamin Pasero 已提交
637
		this.panelHidden = this.storageService.getBoolean(Workbench.panelHiddenSettingKey, StorageScope.WORKSPACE, true);
638 639
		if (!panelRegistry.getDefaultPanelId()) {
			this.panelHidden = true; // we hide panel part if there is no default panel
I
isidor 已提交
640
		}
I
isidor 已提交
641

E
Erich Gamma 已提交
642
		// Sidebar position
643
		const sideBarPosition = this.configurationService.getValue<string>(Workbench.sidebarPositionConfigurationKey);
644
		this.sideBarPosition = (sideBarPosition === 'right') ? Position.RIGHT : Position.LEFT;
B
Benjamin Pasero 已提交
645 646

		// Statusbar visibility
647
		const statusBarVisible = this.configurationService.getValue<string>(Workbench.statusbarVisibleConfigurationKey);
648
		this.statusBarHidden = !statusBarVisible;
S
Sanders Lauture 已提交
649 650

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

654
		// Font aliasing
655
		this.fontAliasing = this.configurationService.getValue<string>(Workbench.fontAliasingConfigurationKey);
656

I
isidor 已提交
657 658
		// Zen mode
		this.zenMode = {
I
isidor 已提交
659
			active: false,
660 661 662
			transitionedToFullScreen: false,
			wasSideBarVisible: false,
			wasPanelVisible: false
I
isidor 已提交
663
		};
E
Erich Gamma 已提交
664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684
	}

	/**
	 * Returns whether the workbench has been started.
	 */
	public isStarted(): boolean {
		return this.workbenchStarted && !this.workbenchShutdown;
	}

	/**
	 * Returns whether the workbench has been fully created.
	 */
	public isCreated(): boolean {
		return this.workbenchCreated && this.workbenchStarted;
	}

	public joinCreation(): TPromise<boolean> {
		return this.creationPromise;
	}

	public hasFocus(part: Parts): boolean {
B
Benjamin Pasero 已提交
685
		const activeElement = document.activeElement;
E
Erich Gamma 已提交
686 687 688 689
		if (!activeElement) {
			return false;
		}

690 691 692 693 694
		const container = this.getContainer(part);
		return DOM.isAncestor(activeElement, container);
	}

	public getContainer(part: Parts): HTMLElement {
E
Erich Gamma 已提交
695 696
		let container: Builder = null;
		switch (part) {
B
Benjamin Pasero 已提交
697 698 699
			case Parts.TITLEBAR_PART:
				container = this.titlebarPart.getContainer();
				break;
E
Erich Gamma 已提交
700 701 702 703 704 705
			case Parts.ACTIVITYBAR_PART:
				container = this.activitybarPart.getContainer();
				break;
			case Parts.SIDEBAR_PART:
				container = this.sidebarPart.getContainer();
				break;
I
isidor 已提交
706 707 708
			case Parts.PANEL_PART:
				container = this.panelPart.getContainer();
				break;
E
Erich Gamma 已提交
709 710 711 712 713 714 715
			case Parts.EDITOR_PART:
				container = this.editorPart.getContainer();
				break;
			case Parts.STATUSBAR_PART:
				container = this.statusbarPart.getContainer();
				break;
		}
716
		return container && container.getHTMLElement();
E
Erich Gamma 已提交
717 718 719
	}

	public isVisible(part: Parts): boolean {
B
Benjamin Pasero 已提交
720
		switch (part) {
B
Benjamin Pasero 已提交
721
			case Parts.TITLEBAR_PART:
722
				return this.getCustomTitleBarStyle() && !browser.isFullscreen();
B
Benjamin Pasero 已提交
723
			case Parts.SIDEBAR_PART:
724
				return !this.sideBarHidden;
B
Benjamin Pasero 已提交
725
			case Parts.PANEL_PART:
726
				return !this.panelHidden;
B
Benjamin Pasero 已提交
727
			case Parts.STATUSBAR_PART:
728
				return !this.statusBarHidden;
S
Sanders Lauture 已提交
729
			case Parts.ACTIVITYBAR_PART:
730
				return !this.activityBarHidden;
731
		}
E
Erich Gamma 已提交
732 733 734 735

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

736 737
	public getTitleBarOffset(): number {
		let offset = 0;
738
		if (this.isVisible(Parts.TITLEBAR_PART)) {
739 740 741 742 743 744
			offset = 22 / browser.getZoomFactor(); // adjust the position based on title bar size and zoom factor
		}

		return offset;
	}

745
	private getCustomTitleBarStyle(): 'custom' {
B
Benjamin Pasero 已提交
746
		if (!isMacintosh) {
747
			return null; // custom title bar is only supported on Mac currently
B
Benjamin Pasero 已提交
748 749
		}

750
		const isDev = !this.environmentService.isBuilt || this.environmentService.isExtensionDevelopment;
B
Benjamin Pasero 已提交
751
		if (isDev) {
752
			return null; // not enabled when developing due to https://github.com/electron/electron/issues/3647
B
Benjamin Pasero 已提交
753 754
		}

755
		const windowConfig = this.configurationService.getConfiguration<IWindowSettings>();
756 757 758 759 760
		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 已提交
761

762 763 764 765
			const style = windowConfig.window.titleBarStyle;
			if (style === 'custom') {
				return style;
			}
766 767 768
		}

		return null;
B
Benjamin Pasero 已提交
769 770
	}

771
	private setStatusBarHidden(hidden: boolean, skipLayout?: boolean): void {
772 773
		this.statusBarHidden = hidden;

I
isidor 已提交
774

775 776
		// Layout
		if (!skipLayout) {
777
			this.workbenchLayout.layout();
778 779 780
		}
	}

S
Sanders Lauture 已提交
781 782 783
	public setActivityBarHidden(hidden: boolean, skipLayout?: boolean): void {
		this.activityBarHidden = hidden;

I
isidor 已提交
784

S
Sanders Lauture 已提交
785 786
		// Layout
		if (!skipLayout) {
787
			this.workbenchLayout.layout();
S
Sanders Lauture 已提交
788 789 790
		}
	}

791
	public setSideBarHidden(hidden: boolean, skipLayout?: boolean): TPromise<void> {
E
Erich Gamma 已提交
792 793 794 795 796 797 798 799 800
		this.sideBarHidden = hidden;

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

B
Benjamin Pasero 已提交
801
		// If sidebar becomes hidden, also hide the current active Viewlet if any
B
Benjamin Pasero 已提交
802
		let promise = TPromise.as<any>(null);
E
Erich Gamma 已提交
803
		if (hidden && this.sidebarPart.getActiveViewlet()) {
804 805 806
			promise = this.sidebarPart.hideActiveViewlet().then(() => {
				const activeEditor = this.editorPart.getActiveEditor();
				const activePanel = this.panelPart.getActivePanel();
B
Benjamin Pasero 已提交
807

808 809 810 811 812 813 814
				// 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 已提交
815 816
		}

B
Benjamin Pasero 已提交
817
		// If sidebar becomes visible, show last active Viewlet or default viewlet
E
Erich Gamma 已提交
818
		else if (!hidden && !this.sidebarPart.getActiveViewlet()) {
819
			const viewletToOpen = this.sidebarPart.getLastActiveViewletId();
E
Erich Gamma 已提交
820
			if (viewletToOpen) {
821
				promise = this.sidebarPart.openViewlet(viewletToOpen, true);
E
Erich Gamma 已提交
822 823 824
			}
		}

825
		return promise.then(() => {
826

827
			// Remember in settings
828
			const defaultHidden = this.contextService.getWorkbenchState() === WorkbenchState.EMPTY;
829 830 831 832 833
			if (hidden !== defaultHidden) {
				this.storageService.store(Workbench.sidebarHiddenSettingKey, hidden ? 'true' : 'false', StorageScope.WORKSPACE);
			} else {
				this.storageService.remove(Workbench.sidebarHiddenSettingKey, StorageScope.WORKSPACE);
			}
834 835 836

			// Layout
			if (!skipLayout) {
837
				this.workbenchLayout.layout();
838 839
			}
		});
E
Erich Gamma 已提交
840 841
	}

842
	public setPanelHidden(hidden: boolean, skipLayout?: boolean): TPromise<void> {
I
isidor 已提交
843
		this.panelHidden = hidden;
I
isidor 已提交
844

845 846 847 848 849 850 851
		// Adjust CSS
		if (hidden) {
			this.workbench.addClass('nopanel');
		} else {
			this.workbench.removeClass('nopanel');
		}

I
isidor 已提交
852
		// If panel part becomes hidden, also hide the current active panel if any
853
		let promise = TPromise.as<any>(null);
I
isidor 已提交
854
		if (hidden && this.panelPart.getActivePanel()) {
855 856 857 858 859 860 861
			promise = this.panelPart.hideActivePanel().then(() => {
				// Pass Focus to Editor if Panel part is now hidden
				const editor = this.editorPart.getActiveEditor();
				if (editor) {
					editor.focus();
				}
			});
I
isidor 已提交
862 863 864 865
		}

		// If panel part becomes visible, show last active panel or default panel
		else if (!hidden && !this.panelPart.getActivePanel()) {
866
			const panelToOpen = this.panelPart.getLastActivePanelId();
I
isidor 已提交
867
			if (panelToOpen) {
868
				promise = this.panelPart.openPanel(panelToOpen, true);
I
isidor 已提交
869 870 871
			}
		}

872
		return promise.then(() => {
873

874
			// Remember in settings
875 876 877 878 879
			if (!hidden) {
				this.storageService.store(Workbench.panelHiddenSettingKey, 'false', StorageScope.WORKSPACE);
			} else {
				this.storageService.remove(Workbench.panelHiddenSettingKey, StorageScope.WORKSPACE);
			}
880 881 882

			// Layout
			if (!skipLayout) {
883
				this.workbenchLayout.layout();
884 885
			}
		});
I
isidor 已提交
886 887
	}

I
isidor 已提交
888
	public toggleMaximizedPanel(): void {
889
		this.workbenchLayout.layout({ toggleMaximizedPanel: true });
I
isidor 已提交
890 891
	}

I
isidor 已提交
892 893 894 895
	public isPanelMaximized(): boolean {
		return this.workbenchLayout.isPanelMaximized();
	}

E
Erich Gamma 已提交
896 897 898 899
	public getSideBarPosition(): Position {
		return this.sideBarPosition;
	}

900
	private setSideBarPosition(position: Position): void {
E
Erich Gamma 已提交
901
		if (this.sideBarHidden) {
902
			this.setSideBarHidden(false, true /* Skip Layout */).done(undefined, errors.onUnexpectedError);
E
Erich Gamma 已提交
903 904
		}

B
Benjamin Pasero 已提交
905 906
		const newPositionValue = (position === Position.LEFT) ? 'left' : 'right';
		const oldPositionValue = (this.sideBarPosition === Position.LEFT) ? 'left' : 'right';
E
Erich Gamma 已提交
907 908 909 910 911 912 913 914
		this.sideBarPosition = position;

		// Adjust CSS
		this.activitybarPart.getContainer().removeClass(oldPositionValue);
		this.sidebarPart.getContainer().removeClass(oldPositionValue);
		this.activitybarPart.getContainer().addClass(newPositionValue);
		this.sidebarPart.getContainer().addClass(newPositionValue);

915 916 917 918
		// Update Styles
		this.activitybarPart.updateStyles();
		this.sidebarPart.updateStyles();

E
Erich Gamma 已提交
919
		// Layout
920
		this.workbenchLayout.layout();
E
Erich Gamma 已提交
921 922
	}

923 924
	private setFontAliasing(aliasing: string) {
		this.fontAliasing = aliasing;
B
Benjamin Pasero 已提交
925

926 927 928
		document.body.style['-webkit-font-smoothing'] = (aliasing === 'default' ? '' : aliasing);
	}

B
Benjamin Pasero 已提交
929
	public dispose(): void {
E
Erich Gamma 已提交
930
		if (this.isStarted()) {
B
Benjamin Pasero 已提交
931
			this.shutdownComponents();
E
Erich Gamma 已提交
932 933 934
			this.workbenchShutdown = true;
		}

J
Joao Moreno 已提交
935
		this.toDispose = dispose(this.toDispose);
E
Erich Gamma 已提交
936 937 938 939 940 941
	}

	/**
	 * Asks the workbench and all its UI components inside to lay out according to
	 * the containers dimension the workbench is living in.
	 */
B
Benjamin Pasero 已提交
942
	public layout(options?: ILayoutOptions): void {
E
Erich Gamma 已提交
943
		if (this.isStarted()) {
B
Benjamin Pasero 已提交
944
			this.workbenchLayout.layout(options);
E
Erich Gamma 已提交
945 946 947
		}
	}

948 949 950 951 952 953
	private shutdownComponents(reason = ShutdownReason.QUIT): void {

		// Restore sidebar if we are being shutdown as a matter of a reload
		if (reason === ShutdownReason.RELOAD) {
			this.storageService.store(Workbench.sidebarRestoreSettingKey, 'true', StorageScope.WORKSPACE);
		}
I
isidor 已提交
954

I
isidor 已提交
955
		// Preserve zen mode only on reload. Real quit gets out of zen mode so novice users do not get stuck in zen mode.
956 957 958 959 960 961 962
		const zenConfig = this.configurationService.getConfiguration<IZenModeSettings>('zenMode');
		const zenModeActive = (zenConfig.restore || reason === ShutdownReason.RELOAD) && this.zenMode.active;
		if (zenModeActive) {
			this.storageService.store(Workbench.zenModeActiveSettingKey, true, StorageScope.WORKSPACE);
		} else {
			this.storageService.remove(Workbench.zenModeActiveSettingKey, StorageScope.WORKSPACE);
		}
E
Erich Gamma 已提交
963 964 965 966 967 968 969 970

		// Pass shutdown on to each participant
		this.toShutdown.forEach(s => s.shutdown());
	}

	private registerListeners(): void {

		// Listen to editor changes
971
		this.toDispose.push(this.editorPart.onEditorsChanged(() => this.onEditorsChanged()));
972

973 974 975 976 977 978 979 980 981 982
		// 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);
			const listenerDispose = this.editorPart.getStacksModel().onEditorClosed(() => this.onEditorClosed(listenerDispose, resourcesToWaitFor, waitMarkerFile));

			this.toDispose.push(listenerDispose);
		}

983
		// Handle message service and quick open events
984 985
		this.toDispose.push((<WorkbenchMessageService>this.messageService).onMessagesShowing(() => this.messagesVisibleContext.set(true)));
		this.toDispose.push((<WorkbenchMessageService>this.messageService).onMessagesCleared(() => this.messagesVisibleContext.reset()));
986

987 988 989 990
		this.toDispose.push(this.quickOpen.onShow(() => (<WorkbenchMessageService>this.messageService).suspend())); // when quick open is open, don't show messages behind
		this.toDispose.push(this.quickOpen.onHide(() => (<WorkbenchMessageService>this.messageService).resume()));  // resume messages once quick open is closed again

		// Configuration changes
991
		this.toDispose.push(this.configurationService.onDidChangeConfiguration(() => this.onDidUpdateConfiguration()));
992 993 994 995 996 997 998 999 1000 1001

		// Fullscreen changes
		this.toDispose.push(browser.onDidChangeFullscreen(() => this.onFullscreenChanged()));
	}

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

1002
		// Apply as CSS class
1003 1004 1005 1006 1007
		const isFullscreen = browser.isFullscreen();
		if (isFullscreen) {
			this.addClass('fullscreen');
		} else {
			this.removeClass('fullscreen');
I
isidor 已提交
1008 1009
			if (this.zenMode.transitionedToFullScreen && this.zenMode.active) {
				this.toggleZenMode();
I
isidor 已提交
1010
			}
1011
		}
1012

1013 1014 1015 1016 1017
		// 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
1018
		}
E
Erich Gamma 已提交
1019 1020
	}

1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032
	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.
		const stacks = this.editorPart.getStacksModel();
		if (resourcesToWaitFor.every(r => !stacks.isOpen(r))) {
			listenerDispose.dispose();
			this.fileService.del(waitMarkerFile).done(null, errors.onUnexpectedError);
		}
	}

1033
	private onEditorsChanged(): void {
B
Benjamin Pasero 已提交
1034
		const visibleEditors = this.editorService.getVisibleEditors().length;
E
Erich Gamma 已提交
1035

1036 1037
		// 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
1038
		// or setting is disabled. Also enabled when running with --wait from the command line.
1039
		if (visibleEditors === 0 && this.contextService.getWorkbenchState() === WorkbenchState.EMPTY && !this.environmentService.isExtensionDevelopment) {
1040
			const closeWhenEmpty = this.configurationService.getValue<boolean>(Workbench.closeWhenEmptyConfigurationKey);
1041
			if (closeWhenEmpty || this.environmentService.args.wait) {
1042 1043 1044 1045
				this.closeEmptyWindowScheduler.schedule();
			}
		}

E
Erich Gamma 已提交
1046 1047
		// We update the editorpart class to indicate if an editor is opened or not
		// through a delay to accomodate for fast editor switching
B
Benjamin Pasero 已提交
1048 1049 1050 1051 1052 1053
		this.handleEditorBackground();
	}

	private handleEditorBackground(): void {
		const visibleEditors = this.editorService.getVisibleEditors().length;

1054
		const editorContainer = this.editorPart.getContainer();
E
Erich Gamma 已提交
1055
		if (visibleEditors === 0) {
1056
			this.editorsVisibleContext.reset();
1057
			this.editorBackgroundDelayer.trigger(() => editorContainer.addClass('empty'));
E
Erich Gamma 已提交
1058
		} else {
1059
			this.editorsVisibleContext.set(true);
1060
			this.editorBackgroundDelayer.trigger(() => editorContainer.removeClass('empty'));
E
Erich Gamma 已提交
1061 1062 1063
		}
	}

1064 1065 1066 1067 1068 1069 1070
	private onAllEditorsClosed(): void {
		const visibleEditors = this.editorService.getVisibleEditors().length;
		if (visibleEditors === 0) {
			this.windowService.closeWindow();
		}
	}

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

1078
		const fontAliasing = this.configurationService.getValue<string>(Workbench.fontAliasingConfigurationKey);
1079 1080 1081 1082
		if (fontAliasing !== this.fontAliasing) {
			this.setFontAliasing(fontAliasing);
		}

1083
		if (!this.zenMode.active) {
1084
			const newStatusbarHiddenValue = !this.configurationService.getValue<boolean>(Workbench.statusbarVisibleConfigurationKey);
1085 1086 1087
			if (newStatusbarHiddenValue !== this.statusBarHidden) {
				this.setStatusBarHidden(newStatusbarHiddenValue, skipLayout);
			}
S
Sanders Lauture 已提交
1088

1089
			const newActivityBarHiddenValue = !this.configurationService.getValue<boolean>(Workbench.activityBarVisibleConfigurationKey);
1090 1091 1092
			if (newActivityBarHiddenValue !== this.activityBarHidden) {
				this.setActivityBarHidden(newActivityBarHiddenValue, skipLayout);
			}
S
Sanders Lauture 已提交
1093
		}
1094 1095
	}

E
Erich Gamma 已提交
1096 1097 1098 1099
	private createWorkbenchLayout(): void {
		this.workbenchLayout = this.instantiationService.createInstance(WorkbenchLayout,
			$(this.container),							// Parent
			this.workbench,								// Workbench Container
I
isidor 已提交
1100
			{
B
Benjamin Pasero 已提交
1101
				titlebar: this.titlebarPart,			// Title Bar
I
isidor 已提交
1102 1103 1104 1105 1106 1107
				activitybar: this.activitybarPart,		// Activity Bar
				editor: this.editorPart,				// Editor
				sidebar: this.sidebarPart,				// Sidebar
				panel: this.panelPart,					// Panel Part
				statusbar: this.statusbarPart,			// Statusbar
			},
B
Benjamin Pasero 已提交
1108
			this.quickOpen								// Quickopen
E
Erich Gamma 已提交
1109 1110 1111 1112 1113 1114 1115 1116 1117
		);

		this.toDispose.push(this.workbenchLayout);
	}

	private createWorkbench(): void {

		// Create Workbench DIV Off-DOM
		this.workbenchContainer = $('.monaco-workbench-container');
1118
		this.workbench = $().div({ 'class': 'monaco-workbench ' + (isWindows ? 'windows' : isLinux ? 'linux' : 'mac'), id: Identifiers.WORKBENCH_CONTAINER }).appendTo(this.workbenchContainer);
E
Erich Gamma 已提交
1119 1120 1121 1122 1123 1124 1125 1126
	}

	private renderWorkbench(): void {

		// Apply sidebar state as CSS class
		if (this.sideBarHidden) {
			this.workbench.addClass('nosidebar');
		}
1127 1128 1129
		if (this.panelHidden) {
			this.workbench.addClass('nopanel');
		}
E
Erich Gamma 已提交
1130

B
Benjamin Pasero 已提交
1131
		// Apply font aliasing
1132 1133
		this.setFontAliasing(this.fontAliasing);

B
Benjamin Pasero 已提交
1134
		// Apply title style if shown
1135 1136 1137 1138 1139 1140 1141 1142
		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 已提交
1143 1144
		}

E
Erich Gamma 已提交
1145
		// Create Parts
B
Benjamin Pasero 已提交
1146
		this.createTitlebarPart();
E
Erich Gamma 已提交
1147 1148 1149
		this.createActivityBarPart();
		this.createSidebarPart();
		this.createEditorPart();
1150
		this.createPanelPart();
E
Erich Gamma 已提交
1151 1152 1153 1154 1155 1156
		this.createStatusbarPart();

		// Add Workbench to DOM
		this.workbenchContainer.build(this.container);
	}

B
Benjamin Pasero 已提交
1157 1158 1159 1160 1161 1162 1163 1164 1165 1166
	private createTitlebarPart(): void {
		const titlebarContainer = $(this.workbench).div({
			'class': ['part', 'titlebar'],
			id: Identifiers.TITLEBAR_PART,
			role: 'contentinfo'
		});

		this.titlebarPart.create(titlebarContainer);
	}

E
Erich Gamma 已提交
1167
	private createActivityBarPart(): void {
B
Benjamin Pasero 已提交
1168
		const activitybarPartContainer = $(this.workbench)
E
Erich Gamma 已提交
1169 1170
			.div({
				'class': ['part', 'activitybar', this.sideBarPosition === Position.LEFT ? 'left' : 'right'],
1171 1172
				id: Identifiers.ACTIVITYBAR_PART,
				role: 'navigation'
E
Erich Gamma 已提交
1173 1174 1175 1176 1177 1178
			});

		this.activitybarPart.create(activitybarPartContainer);
	}

	private createSidebarPart(): void {
B
Benjamin Pasero 已提交
1179
		const sidebarPartContainer = $(this.workbench)
E
Erich Gamma 已提交
1180 1181
			.div({
				'class': ['part', 'sidebar', this.sideBarPosition === Position.LEFT ? 'left' : 'right'],
1182 1183
				id: Identifiers.SIDEBAR_PART,
				role: 'complementary'
E
Erich Gamma 已提交
1184 1185 1186 1187 1188
			});

		this.sidebarPart.create(sidebarPartContainer);
	}

I
isidor 已提交
1189
	private createPanelPart(): void {
B
Benjamin Pasero 已提交
1190
		const panelPartContainer = $(this.workbench)
I
isidor 已提交
1191
			.div({
1192
				'class': ['part', 'panel'],
1193 1194
				id: Identifiers.PANEL_PART,
				role: 'complementary'
I
isidor 已提交
1195 1196 1197 1198 1199
			});

		this.panelPart.create(panelPartContainer);
	}

E
Erich Gamma 已提交
1200
	private createEditorPart(): void {
B
Benjamin Pasero 已提交
1201
		const editorContainer = $(this.workbench)
E
Erich Gamma 已提交
1202
			.div({
1203
				'class': ['part', 'editor', 'empty'],
1204 1205
				id: Identifiers.EDITOR_PART,
				role: 'main'
E
Erich Gamma 已提交
1206 1207 1208 1209 1210 1211
			});

		this.editorPart.create(editorContainer);
	}

	private createStatusbarPart(): void {
B
Benjamin Pasero 已提交
1212
		const statusbarContainer = $(this.workbench).div({
E
Erich Gamma 已提交
1213
			'class': ['part', 'statusbar'],
1214 1215
			id: Identifiers.STATUSBAR_PART,
			role: 'contentinfo'
E
Erich Gamma 已提交
1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232
		});

		this.statusbarPart.create(statusbarContainer);
	}

	public getEditorPart(): EditorPart {
		assert.ok(this.workbenchStarted, 'Workbench is not started. Call startup() first.');

		return this.editorPart;
	}

	public getSidebarPart(): SidebarPart {
		assert.ok(this.workbenchStarted, 'Workbench is not started. Call startup() first.');

		return this.sidebarPart;
	}

I
isidor 已提交
1233 1234 1235 1236 1237 1238
	public getPanelPart(): PanelPart {
		assert.ok(this.workbenchStarted, 'Workbench is not started. Call startup() first.');

		return this.panelPart;
	}

E
Erich Gamma 已提交
1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255
	public getInstantiationService(): IInstantiationService {
		assert.ok(this.workbenchStarted, 'Workbench is not started. Call startup() first.');

		return this.instantiationService;
	}

	public addClass(clazz: string): void {
		if (this.workbench) {
			this.workbench.addClass(clazz);
		}
	}

	public removeClass(clazz: string): void {
		if (this.workbench) {
			this.workbench.removeClass(clazz);
		}
	}
1256 1257 1258 1259

	public getWorkbenchElementId(): string {
		return Identifiers.WORKBENCH_CONTAINER;
	}
1260

I
isidor 已提交
1261
	public toggleZenMode(skipLayout?: boolean): void {
I
isidor 已提交
1262 1263
		this.zenMode.active = !this.zenMode.active;
		// 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
1264
		let toggleFullScreen = false;
I
isidor 已提交
1265
		if (this.zenMode.active) {
I
isidor 已提交
1266 1267
			const config = this.configurationService.getConfiguration<IZenModeSettings>('zenMode');
			toggleFullScreen = !browser.isFullscreen() && config.fullScreen;
I
isidor 已提交
1268
			this.zenMode.transitionedToFullScreen = toggleFullScreen;
1269 1270
			this.zenMode.wasSideBarVisible = this.isVisible(Parts.SIDEBAR_PART);
			this.zenMode.wasPanelVisible = this.isVisible(Parts.PANEL_PART);
1271
			this.setPanelHidden(true, true).done(undefined, errors.onUnexpectedError);
1272
			this.setSideBarHidden(true, true).done(undefined, errors.onUnexpectedError);
I
isidor 已提交
1273

1274 1275 1276
			if (config.hideActivityBar) {
				this.setActivityBarHidden(true, true);
			}
I
isidor 已提交
1277
			if (config.hideStatusBar) {
I
isidor 已提交
1278 1279
				this.setStatusBarHidden(true, true);
			}
I
isidor 已提交
1280
			if (config.hideTabs) {
I
isidor 已提交
1281 1282
				this.editorPart.hideTabs(true);
			}
1283
		} else {
1284
			if (this.zenMode.wasPanelVisible) {
1285
				this.setPanelHidden(false, true).done(undefined, errors.onUnexpectedError);
1286
			}
1287
			if (this.zenMode.wasSideBarVisible) {
1288
				this.setSideBarHidden(false, true).done(undefined, errors.onUnexpectedError);
1289
			}
1290 1291
			// Status bar and activity bar visibility come from settings -> update their visibility.
			this.onDidUpdateConfiguration(true);
I
isidor 已提交
1292
			this.editorPart.hideTabs(false);
I
isidor 已提交
1293 1294 1295 1296
			const activeEditor = this.editorPart.getActiveEditor();
			if (activeEditor) {
				activeEditor.focus();
			}
1297
			toggleFullScreen = this.zenMode.transitionedToFullScreen && browser.isFullscreen();
I
isidor 已提交
1298
		}
1299
		this.inZenMode.set(this.zenMode.active);
I
isidor 已提交
1300

I
isidor 已提交
1301
		if (!skipLayout) {
1302
			this.layout();
I
isidor 已提交
1303
		}
1304 1305 1306
		if (toggleFullScreen) {
			this.windowService.toggleFullScreen().done(undefined, errors.onUnexpectedError);
		}
I
isidor 已提交
1307 1308
	}

1309 1310 1311 1312 1313 1314 1315 1316 1317 1318
	// Resize requested part along the main axis
	// layout will do all the math for us and adjusts the other Parts
	public resizePart(part: Parts, sizeChange: number): void {
		switch (part) {
			case Parts.SIDEBAR_PART:
			case Parts.PANEL_PART:
			case Parts.EDITOR_PART:
				this.workbenchLayout.resizePart(part, sizeChange);
				break;
			default:
B
Benjamin Pasero 已提交
1319
				return; // Cannot resize other parts
1320 1321 1322 1323
		}
	}


1324
	private shouldRestoreLastOpenedViewlet(): boolean {
1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335
		if (!this.environmentService.isBuilt) {
			return true; // always restore sidebar when we are in development mode
		}

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

		return restore;
	}
J
Johannes Rieken 已提交
1336
}