workbench.ts 52.1 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';
18
import { StopWatch } from 'vs/base/common/stopwatch';
19
import { time } from 'vs/base/common/performance';
E
Erich Gamma 已提交
20
import errors = require('vs/base/common/errors');
21
import { BackupFileService } from 'vs/workbench/services/backup/node/backupFileService';
22
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
J
Johannes Rieken 已提交
23
import { toErrorMessage } from 'vs/base/common/errorMessage';
24
import { Registry } from 'vs/platform/registry/common/platform';
B
Benjamin Pasero 已提交
25
import { isWindows, isLinux, isMacintosh } from 'vs/base/common/platform';
B
Benjamin Pasero 已提交
26
import { Position as EditorPosition, IResourceDiffInput, IUntitledResourceInput, IEditor, IResourceInput } from 'vs/platform/editor/common/editor';
J
Johannes Rieken 已提交
27
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
28
import { IEditorInputFactoryRegistry, Extensions as EditorExtensions } from 'vs/workbench/common/editor';
J
Johannes Rieken 已提交
29 30 31 32 33 34
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 已提交
35 36
import { TitlebarPart } from 'vs/workbench/browser/parts/titlebar/titlebarPart';
import { WorkbenchLayout } from 'vs/workbench/browser/layout';
37
import { IActionBarRegistry, Extensions as ActionBarExtensions } from 'vs/workbench/browser/actions';
J
Johannes Rieken 已提交
38 39 40
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';
41
import { Position, Parts, IPartService, ILayoutOptions } from 'vs/workbench/services/part/common/partService';
42
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
J
Johannes Rieken 已提交
43 44 45 46
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';
47
import { WorkspaceService, DefaultConfigurationExportHelper } from 'vs/workbench/services/configuration/node/configurationService';
48 49
import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing';
import { JSONEditingService } from 'vs/workbench/services/configuration/node/jsonEditingService';
J
Johannes Rieken 已提交
50 51
import { ContextKeyService } from 'vs/platform/contextkey/browser/contextKeyService';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
52
import { IKeybindingEditingService, KeybindingsEditingService } from 'vs/workbench/services/keybinding/common/keybindingEditing';
J
Johannes Rieken 已提交
53
import { ContextKeyExpr, RawContextKey, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
I
isidor 已提交
54
import { IActivityService } from 'vs/workbench/services/activity/common/activity';
B
Benjamin Pasero 已提交
55
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
P
Pine Wu 已提交
56
import { ViewletService } from 'vs/workbench/services/viewlet/browser/viewletService';
57
import { RemoteFileService } from 'vs/workbench/services/files/electron-browser/remoteFileService';
J
Johannes Rieken 已提交
58
import { IFileService } from 'vs/platform/files/common/files';
59
import { IListService, ListService } from 'vs/platform/list/browser/listService';
J
Johannes Rieken 已提交
60 61 62
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 已提交
63
import { ITitleService } from 'vs/workbench/services/title/common/titleService';
J
Johannes Rieken 已提交
64
import { WorkbenchMessageService } from 'vs/workbench/services/message/browser/messageService';
B
Benjamin Pasero 已提交
65
import { IWorkbenchEditorService, IResourceInputType, WorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
J
Johannes Rieken 已提交
66
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
67 68
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { ClipboardService } from 'vs/platform/clipboard/electron-browser/clipboardService';
J
Johannes Rieken 已提交
69 70 71 72 73 74
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 已提交
75 76
import { ISCMService } from 'vs/workbench/services/scm/common/scm';
import { SCMService } from 'vs/workbench/services/scm/common/scmService';
77 78
import { IProgressService2 } from 'vs/platform/progress/common/progress';
import { ProgressService2 } from 'vs/workbench/services/progress/browser/progressService2';
79
import { TextModelResolverService } from 'vs/workbench/services/textmodelResolver/common/textModelResolverService';
80
import { ITextModelService } from 'vs/editor/common/services/resolverService';
J
Johannes Rieken 已提交
81
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
82 83
import { ShutdownReason, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { LifecycleService } from 'vs/workbench/services/lifecycle/electron-browser/lifecycleService';
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);
105
export const SidebarVisibleContext = new RawContextKey<boolean>('sidebarVisible', false);
J
Johannes Rieken 已提交
106
export const NoEditorsVisibleContext: ContextKeyExpr = EditorsVisibleContext.toNegated();
A
Alex Dima 已提交
107

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

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

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

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

135 136
const Identifiers = {
	WORKBENCH_CONTAINER: 'workbench.main.container',
B
Benjamin Pasero 已提交
137
	TITLEBAR_PART: 'workbench.parts.titlebar',
138 139 140 141 142 143 144
	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 已提交
145
/**
B
Benjamin Pasero 已提交
146
 * The workbench creates and lays out all parts that make up the workbench.
E
Erich Gamma 已提交
147 148 149 150
 */
export class Workbench implements IPartService {

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

155
	private static sidebarPositionConfigurationKey = 'workbench.sideBar.location';
I
isidor 已提交
156
	private static panelPositionConfigurationKey = 'workbench.panel.location';
157
	private static statusbarVisibleConfigurationKey = 'workbench.statusBar.visible';
S
Sanders Lauture 已提交
158
	private static activityBarVisibleConfigurationKey = 'workbench.activityBar.visible';
159

160 161
	private static closeWhenEmptyConfigurationKey = 'window.closeWhenEmpty';

162 163
	private static fontAliasingConfigurationKey = 'workbench.fontAliasing';

164 165
	private _onTitleBarVisibilityChange: Emitter<void>;

166
	public _serviceBrand: any;
E
Erich Gamma 已提交
167

B
Benjamin Pasero 已提交
168
	private parent: HTMLElement;
E
Erich Gamma 已提交
169 170 171 172 173 174 175
	private container: HTMLElement;
	private workbenchParams: WorkbenchParams;
	private workbenchContainer: Builder;
	private workbench: Builder;
	private workbenchStarted: boolean;
	private workbenchCreated: boolean;
	private workbenchShutdown: boolean;
176
	private editorService: WorkbenchEditorService;
P
Pine Wu 已提交
177
	private viewletService: IViewletService;
178
	private contextKeyService: IContextKeyService;
179
	private keybindingService: IKeybindingService;
180
	private backupFileService: IBackupFileService;
181
	private fileService: IFileService;
B
Benjamin Pasero 已提交
182
	private titlebarPart: TitlebarPart;
E
Erich Gamma 已提交
183 184
	private activitybarPart: ActivitybarPart;
	private sidebarPart: SidebarPart;
I
isidor 已提交
185
	private panelPart: PanelPart;
E
Erich Gamma 已提交
186 187 188 189 190 191 192 193 194 195
	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;
196
	private statusBarHidden: boolean;
S
Sanders Lauture 已提交
197
	private activityBarHidden: boolean;
E
Erich Gamma 已提交
198
	private sideBarPosition: Position;
I
isidor 已提交
199
	private panelPosition: Position;
I
isidor 已提交
200
	private panelHidden: boolean;
E
Erich Gamma 已提交
201
	private editorBackgroundDelayer: Delayer<void>;
202
	private closeEmptyWindowScheduler: RunOnceScheduler;
A
Alex Dima 已提交
203 204
	private messagesVisibleContext: IContextKey<boolean>;
	private editorsVisibleContext: IContextKey<boolean>;
I
isidor 已提交
205
	private inZenMode: IContextKey<boolean>;
206
	private sideBarVisibleContext: IContextKey<boolean>;
207
	private hasFilesToCreateOpenOrDiff: boolean;
208
	private fontAliasing: string;
I
isidor 已提交
209
	private zenMode: {
I
isidor 已提交
210 211
		active: boolean;
		transitionedToFullScreen: boolean;
212 213
		wasSideBarVisible: boolean;
		wasPanelVisible: boolean;
I
isidor 已提交
214
	};
E
Erich Gamma 已提交
215

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

		this.workbenchParams = {
235
			configuration,
236
			serviceCollection
E
Erich Gamma 已提交
237 238
		};

239
		this.hasFilesToCreateOpenOrDiff =
B
Benjamin Pasero 已提交
240 241 242
			(configuration.filesToCreate && configuration.filesToCreate.length > 0) ||
			(configuration.filesToOpen && configuration.filesToOpen.length > 0) ||
			(configuration.filesToDiff && configuration.filesToDiff.length > 0);
243

E
Erich Gamma 已提交
244 245
		this.toDispose = [];
		this.toShutdown = [];
246

E
Erich Gamma 已提交
247
		this.editorBackgroundDelayer = new Delayer<void>(50);
248
		this.closeEmptyWindowScheduler = new RunOnceScheduler(() => this.onAllEditorsClosed(), 50);
E
Erich Gamma 已提交
249

250 251
		this._onTitleBarVisibilityChange = new Emitter<void>();

252
		this.creationPromise = new TPromise<boolean>(c => {
E
Erich Gamma 已提交
253 254 255 256
			this.creationPromiseComplete = c;
		});
	}

257 258 259 260
	public get onTitleBarVisibilityChange(): Event<void> {
		return this._onTitleBarVisibilityChange.event;
	}

261 262 263 264 265 266
	public get onEditorLayout(): Event<void> {
		return chain(this.editorPart.onLayout)
			.map(() => void 0)
			.event;
	}

E
Erich Gamma 已提交
267 268 269 270 271 272 273 274 275 276 277 278
	/**
	 * 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 {
		try {
			this.workbenchStarted = true;
			this.callbacks = callbacks;

			// Create Workbench
			this.createWorkbench();

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

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

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

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

			// Settings
			this.initSettings();

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

			// Workbench Layout
			this.createWorkbenchLayout();

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

P
Pine Wu 已提交
309
			// Restore last opened viewlet
310
			let viewletRestoreStopWatch: StopWatch;
311
			let viewletIdToRestore: string;
312
			if (!this.sideBarHidden) {
313
				this.sideBarVisibleContext.set(true);
314

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

				if (!viewletIdToRestore) {
320
					viewletIdToRestore = this.viewletService.getDefaultViewletId();
P
Pine Wu 已提交
321
				}
322

323
				viewletRestoreStopWatch = StopWatch.create();
324 325
				const viewletRestoreClock = time('restore:viewlet');
				compositeAndEditorPromises.push(this.viewletService.openViewlet(viewletIdToRestore).then(() => {
326
					viewletRestoreStopWatch.stop();
327
					viewletRestoreClock.stop();
328
				}));
E
Erich Gamma 已提交
329 330
			}

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

B
Benjamin Pasero 已提交
338
			// Load Editors
339
			const editorRestoreStopWatch = StopWatch.create();
340
			const editorRestoreClock = time('restore:editors');
341
			const restoredEditors: string[] = [];
342
			compositeAndEditorPromises.push(this.resolveEditorsToOpen().then(inputs => {
343
				this.lifecycleService.phase = LifecyclePhase.Restoring;
344
				let editorOpenPromise: TPromise<IEditor[]>;
345 346
				if (inputs.length) {
					editorOpenPromise = this.editorService.openEditors(inputs.map(input => { return { input, position: EditorPosition.ONE }; }));
B
Benjamin Pasero 已提交
347
				} else {
B
Benjamin Pasero 已提交
348
					editorOpenPromise = this.editorPart.restoreEditors();
349
				}
350

351
				return editorOpenPromise.then(editors => {
B
Benjamin Pasero 已提交
352
					this.handleEditorBackground(); // make sure we show the proper background in the editor area
353
					editorRestoreClock.stop();
354
					editorRestoreStopWatch.stop();
355
					for (const editor of editors) {
B
Benjamin Pasero 已提交
356 357 358 359 360 361
						if (editor) {
							if (editor.input) {
								restoredEditors.push(editor.input.getName());
							} else {
								restoredEditors.push(`other:${editor.getId()}`);
							}
362 363
						}
					}
E
Erich Gamma 已提交
364
				});
365
			}));
E
Erich Gamma 已提交
366

367
			if (this.storageService.getBoolean(Workbench.zenModeActiveSettingKey, StorageScope.WORKSPACE, false)) {
I
isidor 已提交
368 369 370
				this.toggleZenMode(true);
			}

E
Erich Gamma 已提交
371
			// Flag workbench as created once done
372
			const workbenchDone = (error?: Error) => {
E
Erich Gamma 已提交
373 374 375
				this.workbenchCreated = true;
				this.creationPromiseComplete(true);

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

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

B
polish  
Benjamin Pasero 已提交
392
			// Join viewlet, panel and editor promises
393
			TPromise.join(compositeAndEditorPromises).then(() => workbenchDone(), error => workbenchDone(error));
E
Erich Gamma 已提交
394 395 396
		} catch (error) {

			// Print out error
397
			console.error(toErrorMessage(error, true));
E
Erich Gamma 已提交
398 399 400 401 402 403

			// Rethrow
			throw error;
		}
	}

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

B
Benjamin Pasero 已提交
407
		// Actions registered here to adjust for developing vs built workbench
408 409
		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 已提交
410
		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 已提交
411
		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"));
412

413
		// Actions for macOS native tabs management (only when enabled)
414
		const windowConfig = this.configurationService.getConfiguration<IWindowConfiguration>();
415 416 417 418 419 420 421
		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');
		}
422 423
	}

424
	private resolveEditorsToOpen(): TPromise<IResourceInputType[]> {
425
		const config = this.workbenchParams.configuration;
B
Benjamin Pasero 已提交
426 427

		// Files to open, diff or create
428
		if (this.hasFilesToCreateOpenOrDiff) {
B
Benjamin Pasero 已提交
429 430

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

440 441
			const filesToCreate = this.toInputs(config.filesToCreate, true);
			const filesToOpen = this.toInputs(config.filesToOpen, false);
442

443 444
			// Otherwise: Open/Create files
			return TPromise.as([...filesToOpen, ...filesToCreate]);
B
Benjamin Pasero 已提交
445 446
		}

447
		// Empty workbench
448
		else if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY && this.openUntitledFile()) {
449 450 451 452
			if (this.editorPart.hasEditorsToRestore()) {
				return TPromise.as([]); // do not open any empty untitled file if we have editors to restore
			}

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

458
				return TPromise.as([<IUntitledResourceInput>{}]);
459
			});
B
Benjamin Pasero 已提交
460 461 462 463 464
		}

		return TPromise.as([]);
	}

465
	private toInputs(paths: IPath[], isNew: boolean): (IResourceInput | IUntitledResourceInput)[] {
B
Benjamin Pasero 已提交
466 467 468 469 470
		if (!paths || !paths.length) {
			return [];
		}

		return paths.map(p => {
471 472 473 474 475 476 477
			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 已提交
478

479
			if (!isNew && p.lineNumber) {
B
Benjamin Pasero 已提交
480 481 482 483 484 485 486 487 488 489
				input.options.selection = {
					startLineNumber: p.lineNumber,
					startColumn: p.columnNumber
				};
			}

			return input;
		});
	}

490
	private openUntitledFile() {
491
		const startupEditor = this.configurationService.inspect('workbench.startupEditor');
B
Benjamin Pasero 已提交
492 493

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

501
		return startupEditor.value === 'newUntitledFile';
502 503
	}

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

507
		this.toDispose.push(this.lifecycleService.onShutdown(this.shutdownComponents, this));
E
Erich Gamma 已提交
508 509

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

512 513 514
		// Clipboard
		serviceCollection.set(IClipboardService, new ClipboardService());

515 516 517 518 519 520
		// 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);

521 522 523
		// Progress 2
		serviceCollection.set(IProgressService2, new SyncDescriptor(ProgressService2));

524
		// Keybindings
A
Alex Dima 已提交
525
		this.contextKeyService = this.instantiationService.createInstance(ContextKeyService);
526
		serviceCollection.set(IContextKeyService, this.contextKeyService);
527

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

531 532 533
		// List
		serviceCollection.set(IListService, this.instantiationService.createInstance(ListService));

534
		// Context Menu
535
		serviceCollection.set(IContextMenuService, new SyncDescriptor(ContextMenuService));
536

537 538
		// Menus/Actions
		serviceCollection.set(IMenuService, new SyncDescriptor(MenuService));
539

P
Pine Wu 已提交
540
		// Sidebar part
541
		this.sidebarPart = this.instantiationService.createInstance(SidebarPart, Identifiers.SIDEBAR_PART);
E
Erich Gamma 已提交
542 543
		this.toDispose.push(this.sidebarPart);
		this.toShutdown.push(this.sidebarPart);
P
Pine Wu 已提交
544 545 546 547

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

I
isidor 已提交
549
		// Panel service (panel part)
550
		this.panelPart = this.instantiationService.createInstance(PanelPart, Identifiers.PANEL_PART);
I
isidor 已提交
551 552
		this.toDispose.push(this.panelPart);
		this.toShutdown.push(this.panelPart);
553
		serviceCollection.set(IPanelService, this.panelPart);
I
isidor 已提交
554

E
Erich Gamma 已提交
555
		// Activity service (activitybar part)
556
		this.activitybarPart = this.instantiationService.createInstance(ActivitybarPart, Identifiers.ACTIVITYBAR_PART);
E
Erich Gamma 已提交
557 558
		this.toDispose.push(this.activitybarPart);
		this.toShutdown.push(this.activitybarPart);
I
isidor 已提交
559 560
		const activityService = this.instantiationService.createInstance(ActivityService, this.activitybarPart, this.panelPart);
		serviceCollection.set(IActivityService, activityService);
E
Erich Gamma 已提交
561

562 563 564 565 566
		// 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 已提交
567
		// Editor service (editor part)
568
		this.editorPart = this.instantiationService.createInstance(EditorPart, Identifiers.EDITOR_PART, !this.hasFilesToCreateOpenOrDiff);
E
Erich Gamma 已提交
569 570
		this.toDispose.push(this.editorPart);
		this.toShutdown.push(this.editorPart);
571
		this.editorService = this.instantiationService.createInstance(WorkbenchEditorService, this.editorPart);
572
		serviceCollection.set(IWorkbenchEditorService, this.editorService);
573
		serviceCollection.set(IEditorGroupService, this.editorPart);
E
Erich Gamma 已提交
574

575 576 577 578 579 580
		// 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);

581
		// History
582
		serviceCollection.set(IHistoryService, new SyncDescriptor(HistoryService));
583

584
		// Backup File Service
585
		this.backupFileService = this.instantiationService.createInstance(BackupFileService, this.workbenchParams.configuration.backupPath);
586
		serviceCollection.set(IBackupFileService, this.backupFileService);
587

588
		// Text File Service
589
		serviceCollection.set(ITextFileService, new SyncDescriptor(TextFileService));
590

591
		// File Decorations
J
Johannes Rieken 已提交
592
		serviceCollection.set(IDecorationsService, new SyncDescriptor(FileDecorationsService));
593

J
Joao Moreno 已提交
594
		// SCM Service
595
		serviceCollection.set(ISCMService, new SyncDescriptor(SCMService));
596

B
Benjamin Pasero 已提交
597
		// Text Model Resolver Service
598
		serviceCollection.set(ITextModelService, new SyncDescriptor(TextModelResolverService));
B
Benjamin Pasero 已提交
599

600 601 602 603
		// JSON Editing
		const jsonEditingService = this.instantiationService.createInstance(JSONEditingService);
		serviceCollection.set(IJSONEditingService, jsonEditingService);

604 605 606
		// Workspace Editing
		serviceCollection.set(IWorkspaceEditingService, new SyncDescriptor(WorkspaceEditingService));

607 608 609
		// Keybinding Editing
		serviceCollection.set(IKeybindingEditingService, this.instantiationService.createInstance(KeybindingsEditingService));

610
		// Configuration Resolver
B
Benjamin Pasero 已提交
611
		serviceCollection.set(IConfigurationResolverService, new SyncDescriptor(ConfigurationResolverService, process.env));
612

E
Erich Gamma 已提交
613
		// Quick open service (quick open controller)
614
		this.quickOpen = this.instantiationService.createInstance(QuickOpenController);
E
Erich Gamma 已提交
615 616
		this.toDispose.push(this.quickOpen);
		this.toShutdown.push(this.quickOpen);
617
		serviceCollection.set(IQuickOpenService, this.quickOpen);
618

B
polish  
Benjamin Pasero 已提交
619
		// Contributed services
B
Benjamin Pasero 已提交
620
		const contributedServices = getServices();
E
Erich Gamma 已提交
621
		for (let contributedService of contributedServices) {
622
			serviceCollection.set(contributedService.id, contributedService.descriptor);
E
Erich Gamma 已提交
623 624 625
		}

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

630
		this.instantiationService.createInstance(DefaultConfigurationExportHelper);
631 632

		this.configurationService.setInstantiationService(this.getInstantiationService());
E
Erich Gamma 已提交
633 634 635 636 637
	}

	private initSettings(): void {

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

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

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

I
isidor 已提交
651 652 653 654
		// Panel position
		const panelPosition = this.configurationService.getValue<string>(Workbench.panelPositionConfigurationKey);
		this.panelPosition = (panelPosition === 'right') ? Position.RIGHT : Position.BOTTOM;

B
Benjamin Pasero 已提交
655
		// Statusbar visibility
656
		const statusBarVisible = this.configurationService.getValue<string>(Workbench.statusbarVisibleConfigurationKey);
657
		this.statusBarHidden = !statusBarVisible;
S
Sanders Lauture 已提交
658 659

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

663
		// Font aliasing
664
		this.fontAliasing = this.configurationService.getValue<string>(Workbench.fontAliasingConfigurationKey);
665

I
isidor 已提交
666 667
		// Zen mode
		this.zenMode = {
I
isidor 已提交
668
			active: false,
669 670 671
			transitionedToFullScreen: false,
			wasSideBarVisible: false,
			wasPanelVisible: false
I
isidor 已提交
672
		};
E
Erich Gamma 已提交
673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693
	}

	/**
	 * 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 已提交
694
		const activeElement = document.activeElement;
E
Erich Gamma 已提交
695 696 697 698
		if (!activeElement) {
			return false;
		}

699 700 701 702 703
		const container = this.getContainer(part);
		return DOM.isAncestor(activeElement, container);
	}

	public getContainer(part: Parts): HTMLElement {
E
Erich Gamma 已提交
704 705
		let container: Builder = null;
		switch (part) {
B
Benjamin Pasero 已提交
706 707 708
			case Parts.TITLEBAR_PART:
				container = this.titlebarPart.getContainer();
				break;
E
Erich Gamma 已提交
709 710 711 712 713 714
			case Parts.ACTIVITYBAR_PART:
				container = this.activitybarPart.getContainer();
				break;
			case Parts.SIDEBAR_PART:
				container = this.sidebarPart.getContainer();
				break;
I
isidor 已提交
715 716 717
			case Parts.PANEL_PART:
				container = this.panelPart.getContainer();
				break;
E
Erich Gamma 已提交
718 719 720 721 722 723 724
			case Parts.EDITOR_PART:
				container = this.editorPart.getContainer();
				break;
			case Parts.STATUSBAR_PART:
				container = this.statusbarPart.getContainer();
				break;
		}
725
		return container && container.getHTMLElement();
E
Erich Gamma 已提交
726 727 728
	}

	public isVisible(part: Parts): boolean {
B
Benjamin Pasero 已提交
729
		switch (part) {
B
Benjamin Pasero 已提交
730
			case Parts.TITLEBAR_PART:
731
				return this.getCustomTitleBarStyle() && !browser.isFullscreen();
B
Benjamin Pasero 已提交
732
			case Parts.SIDEBAR_PART:
733
				return !this.sideBarHidden;
B
Benjamin Pasero 已提交
734
			case Parts.PANEL_PART:
735
				return !this.panelHidden;
B
Benjamin Pasero 已提交
736
			case Parts.STATUSBAR_PART:
737
				return !this.statusBarHidden;
S
Sanders Lauture 已提交
738
			case Parts.ACTIVITYBAR_PART:
739
				return !this.activityBarHidden;
740
		}
E
Erich Gamma 已提交
741 742 743 744

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

745 746
	public getTitleBarOffset(): number {
		let offset = 0;
747
		if (this.isVisible(Parts.TITLEBAR_PART)) {
748 749 750 751 752 753
			offset = 22 / browser.getZoomFactor(); // adjust the position based on title bar size and zoom factor
		}

		return offset;
	}

754
	private getCustomTitleBarStyle(): 'custom' {
B
Benjamin Pasero 已提交
755
		if (!isMacintosh) {
756
			return null; // custom title bar is only supported on Mac currently
B
Benjamin Pasero 已提交
757 758
		}

759
		const isDev = !this.environmentService.isBuilt || this.environmentService.isExtensionDevelopment;
B
Benjamin Pasero 已提交
760
		if (isDev) {
761
			return null; // not enabled when developing due to https://github.com/electron/electron/issues/3647
B
Benjamin Pasero 已提交
762 763
		}

764
		const windowConfig = this.configurationService.getConfiguration<IWindowSettings>();
765 766 767 768 769
		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 已提交
770

771 772 773 774
			const style = windowConfig.window.titleBarStyle;
			if (style === 'custom') {
				return style;
			}
775 776 777
		}

		return null;
B
Benjamin Pasero 已提交
778 779
	}

780
	private setStatusBarHidden(hidden: boolean, skipLayout?: boolean): void {
781 782
		this.statusBarHidden = hidden;

I
isidor 已提交
783

784 785
		// Layout
		if (!skipLayout) {
786
			this.workbenchLayout.layout();
787 788 789
		}
	}

S
Sanders Lauture 已提交
790 791 792
	public setActivityBarHidden(hidden: boolean, skipLayout?: boolean): void {
		this.activityBarHidden = hidden;

I
isidor 已提交
793

S
Sanders Lauture 已提交
794 795
		// Layout
		if (!skipLayout) {
796
			this.workbenchLayout.layout();
S
Sanders Lauture 已提交
797 798 799
		}
	}

800
	public setSideBarHidden(hidden: boolean, skipLayout?: boolean): TPromise<void> {
E
Erich Gamma 已提交
801
		this.sideBarHidden = hidden;
802
		this.sideBarVisibleContext.set(!hidden);
E
Erich Gamma 已提交
803 804 805 806 807 808 809 810

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

B
Benjamin Pasero 已提交
811
		// If sidebar becomes hidden, also hide the current active Viewlet if any
B
Benjamin Pasero 已提交
812
		let promise = TPromise.as<any>(null);
E
Erich Gamma 已提交
813
		if (hidden && this.sidebarPart.getActiveViewlet()) {
814 815 816
			promise = this.sidebarPart.hideActiveViewlet().then(() => {
				const activeEditor = this.editorPart.getActiveEditor();
				const activePanel = this.panelPart.getActivePanel();
B
Benjamin Pasero 已提交
817

818 819 820 821 822 823 824
				// 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 已提交
825 826
		}

B
Benjamin Pasero 已提交
827
		// If sidebar becomes visible, show last active Viewlet or default viewlet
E
Erich Gamma 已提交
828
		else if (!hidden && !this.sidebarPart.getActiveViewlet()) {
829
			const viewletToOpen = this.sidebarPart.getLastActiveViewletId();
E
Erich Gamma 已提交
830
			if (viewletToOpen) {
831
				promise = this.sidebarPart.openViewlet(viewletToOpen, true);
E
Erich Gamma 已提交
832 833 834
			}
		}

835
		return promise.then(() => {
836

837
			// Remember in settings
838
			const defaultHidden = this.contextService.getWorkbenchState() === WorkbenchState.EMPTY;
839 840 841 842 843
			if (hidden !== defaultHidden) {
				this.storageService.store(Workbench.sidebarHiddenSettingKey, hidden ? 'true' : 'false', StorageScope.WORKSPACE);
			} else {
				this.storageService.remove(Workbench.sidebarHiddenSettingKey, StorageScope.WORKSPACE);
			}
844 845 846

			// Layout
			if (!skipLayout) {
847
				this.workbenchLayout.layout();
848 849
			}
		});
E
Erich Gamma 已提交
850 851
	}

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

855 856 857 858 859 860 861
		// Adjust CSS
		if (hidden) {
			this.workbench.addClass('nopanel');
		} else {
			this.workbench.removeClass('nopanel');
		}

I
isidor 已提交
862
		// If panel part becomes hidden, also hide the current active panel if any
863
		let promise = TPromise.as<any>(null);
I
isidor 已提交
864
		if (hidden && this.panelPart.getActivePanel()) {
865 866 867 868 869 870 871
			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 已提交
872 873 874 875
		}

		// If panel part becomes visible, show last active panel or default panel
		else if (!hidden && !this.panelPart.getActivePanel()) {
876
			const panelToOpen = this.panelPart.getLastActivePanelId();
I
isidor 已提交
877
			if (panelToOpen) {
878
				promise = this.panelPart.openPanel(panelToOpen, true);
I
isidor 已提交
879 880 881
			}
		}

882
		return promise.then(() => {
883

884
			// Remember in settings
885 886 887 888 889
			if (!hidden) {
				this.storageService.store(Workbench.panelHiddenSettingKey, 'false', StorageScope.WORKSPACE);
			} else {
				this.storageService.remove(Workbench.panelHiddenSettingKey, StorageScope.WORKSPACE);
			}
890 891 892

			// Layout
			if (!skipLayout) {
893
				this.workbenchLayout.layout();
894 895
			}
		});
I
isidor 已提交
896 897
	}

898 899 900 901 902 903 904 905
	public toggleMaximizedPanel(): void {
		this.workbenchLayout.layout({ toggleMaximizedPanel: true });
	}

	public isPanelMaximized(): boolean {
		return this.workbenchLayout.isPanelMaximized();
	}

E
Erich Gamma 已提交
906 907 908 909
	public getSideBarPosition(): Position {
		return this.sideBarPosition;
	}

910
	private setSideBarPosition(position: Position): void {
E
Erich Gamma 已提交
911
		if (this.sideBarHidden) {
912
			this.setSideBarHidden(false, true /* Skip Layout */).done(undefined, errors.onUnexpectedError);
E
Erich Gamma 已提交
913 914
		}

B
Benjamin Pasero 已提交
915 916
		const newPositionValue = (position === Position.LEFT) ? 'left' : 'right';
		const oldPositionValue = (this.sideBarPosition === Position.LEFT) ? 'left' : 'right';
E
Erich Gamma 已提交
917 918 919 920 921 922 923 924
		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);

925 926 927 928
		// Update Styles
		this.activitybarPart.updateStyles();
		this.sidebarPart.updateStyles();

E
Erich Gamma 已提交
929
		// Layout
930
		this.workbenchLayout.layout();
E
Erich Gamma 已提交
931 932
	}

I
isidor 已提交
933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956
	public getPanelPosition(): Position {
		return this.panelPosition;
	}

	private setPanelPosition(position: Position): void {
		if (this.panelHidden) {
			this.setPanelHidden(false, true /* Skip Layout */).done(undefined, errors.onUnexpectedError);
		}

		const newPositionValue = (position === Position.BOTTOM) ? 'bottom' : 'right';
		const oldPositionValue = (this.panelPosition === Position.BOTTOM) ? 'bottom' : 'right';
		this.panelPosition = position;

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

		// Update Styles
		this.panelPart.updateStyles();

		// Layout
		this.workbenchLayout.layout();
	}

957 958
	private setFontAliasing(aliasing: string) {
		this.fontAliasing = aliasing;
B
Benjamin Pasero 已提交
959

960 961 962
		document.body.style['-webkit-font-smoothing'] = (aliasing === 'default' ? '' : aliasing);
	}

B
Benjamin Pasero 已提交
963
	public dispose(): void {
E
Erich Gamma 已提交
964
		if (this.isStarted()) {
B
Benjamin Pasero 已提交
965
			this.shutdownComponents();
E
Erich Gamma 已提交
966 967 968
			this.workbenchShutdown = true;
		}

J
Joao Moreno 已提交
969
		this.toDispose = dispose(this.toDispose);
E
Erich Gamma 已提交
970 971 972 973 974 975
	}

	/**
	 * Asks the workbench and all its UI components inside to lay out according to
	 * the containers dimension the workbench is living in.
	 */
976
	public layout(options?: ILayoutOptions): void {
E
Erich Gamma 已提交
977
		if (this.isStarted()) {
978
			this.workbenchLayout.layout(options);
E
Erich Gamma 已提交
979 980 981
		}
	}

982 983 984 985 986 987
	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 已提交
988

I
isidor 已提交
989
		// Preserve zen mode only on reload. Real quit gets out of zen mode so novice users do not get stuck in zen mode.
990 991 992 993 994 995 996
		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 已提交
997 998 999 1000 1001 1002 1003 1004

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

	private registerListeners(): void {

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

1007 1008 1009 1010 1011 1012 1013 1014 1015 1016
		// 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);
		}

1017
		// Handle message service and quick open events
1018 1019
		this.toDispose.push((<WorkbenchMessageService>this.messageService).onMessagesShowing(() => this.messagesVisibleContext.set(true)));
		this.toDispose.push((<WorkbenchMessageService>this.messageService).onMessagesCleared(() => this.messagesVisibleContext.reset()));
1020

1021 1022 1023 1024
		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
1025
		this.toDispose.push(this.configurationService.onDidChangeConfiguration(() => this.onDidUpdateConfiguration()));
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035

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

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

1036
		// Apply as CSS class
1037 1038 1039 1040 1041
		const isFullscreen = browser.isFullscreen();
		if (isFullscreen) {
			this.addClass('fullscreen');
		} else {
			this.removeClass('fullscreen');
I
isidor 已提交
1042 1043
			if (this.zenMode.transitionedToFullScreen && this.zenMode.active) {
				this.toggleZenMode();
I
isidor 已提交
1044
			}
1045
		}
1046

1047 1048 1049 1050 1051
		// 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
1052
		}
E
Erich Gamma 已提交
1053 1054
	}

1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066
	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);
		}
	}

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

1070 1071
		// 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
1072
		// or setting is disabled. Also enabled when running with --wait from the command line.
1073
		if (visibleEditors === 0 && this.contextService.getWorkbenchState() === WorkbenchState.EMPTY && !this.environmentService.isExtensionDevelopment) {
1074
			const closeWhenEmpty = this.configurationService.getValue<boolean>(Workbench.closeWhenEmptyConfigurationKey);
1075
			if (closeWhenEmpty || this.environmentService.args.wait) {
1076 1077 1078 1079
				this.closeEmptyWindowScheduler.schedule();
			}
		}

E
Erich Gamma 已提交
1080 1081
		// 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 已提交
1082 1083 1084 1085 1086 1087
		this.handleEditorBackground();
	}

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

1088
		const editorContainer = this.editorPart.getContainer();
E
Erich Gamma 已提交
1089
		if (visibleEditors === 0) {
1090
			this.editorsVisibleContext.reset();
1091
			this.editorBackgroundDelayer.trigger(() => editorContainer.addClass('empty'));
E
Erich Gamma 已提交
1092
		} else {
1093
			this.editorsVisibleContext.set(true);
1094
			this.editorBackgroundDelayer.trigger(() => editorContainer.removeClass('empty'));
E
Erich Gamma 已提交
1095 1096 1097
		}
	}

1098 1099 1100 1101 1102 1103 1104
	private onAllEditorsClosed(): void {
		const visibleEditors = this.editorService.getVisibleEditors().length;
		if (visibleEditors === 0) {
			this.windowService.closeWindow();
		}
	}

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

I
isidor 已提交
1112 1113
		const newPanelPositionValue = this.configurationService.getValue<string>(Workbench.panelPositionConfigurationKey);
		const newPanelPosition = (newPanelPositionValue === 'right') ? Position.RIGHT : Position.BOTTOM;
I
isidor 已提交
1114
		if (newPanelPosition !== this.getPanelPosition()) {
I
isidor 已提交
1115 1116 1117
			this.setPanelPosition(newPanelPosition);
		}

1118
		const fontAliasing = this.configurationService.getValue<string>(Workbench.fontAliasingConfigurationKey);
1119 1120 1121 1122
		if (fontAliasing !== this.fontAliasing) {
			this.setFontAliasing(fontAliasing);
		}

1123
		if (!this.zenMode.active) {
1124
			const newStatusbarHiddenValue = !this.configurationService.getValue<boolean>(Workbench.statusbarVisibleConfigurationKey);
1125 1126 1127
			if (newStatusbarHiddenValue !== this.statusBarHidden) {
				this.setStatusBarHidden(newStatusbarHiddenValue, skipLayout);
			}
S
Sanders Lauture 已提交
1128

1129
			const newActivityBarHiddenValue = !this.configurationService.getValue<boolean>(Workbench.activityBarVisibleConfigurationKey);
1130 1131 1132
			if (newActivityBarHiddenValue !== this.activityBarHidden) {
				this.setActivityBarHidden(newActivityBarHiddenValue, skipLayout);
			}
S
Sanders Lauture 已提交
1133
		}
1134 1135
	}

E
Erich Gamma 已提交
1136 1137 1138 1139
	private createWorkbenchLayout(): void {
		this.workbenchLayout = this.instantiationService.createInstance(WorkbenchLayout,
			$(this.container),							// Parent
			this.workbench,								// Workbench Container
I
isidor 已提交
1140
			{
B
Benjamin Pasero 已提交
1141
				titlebar: this.titlebarPart,			// Title Bar
I
isidor 已提交
1142 1143 1144 1145 1146 1147
				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 已提交
1148
			this.quickOpen								// Quickopen
E
Erich Gamma 已提交
1149 1150 1151 1152 1153 1154 1155 1156 1157
		);

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

	private createWorkbench(): void {

		// Create Workbench DIV Off-DOM
		this.workbenchContainer = $('.monaco-workbench-container');
1158
		this.workbench = $().div({ 'class': 'monaco-workbench ' + (isWindows ? 'windows' : isLinux ? 'linux' : 'mac'), id: Identifiers.WORKBENCH_CONTAINER }).appendTo(this.workbenchContainer);
E
Erich Gamma 已提交
1159 1160 1161 1162 1163 1164 1165 1166
	}

	private renderWorkbench(): void {

		// Apply sidebar state as CSS class
		if (this.sideBarHidden) {
			this.workbench.addClass('nosidebar');
		}
1167 1168 1169
		if (this.panelHidden) {
			this.workbench.addClass('nopanel');
		}
E
Erich Gamma 已提交
1170

B
Benjamin Pasero 已提交
1171
		// Apply font aliasing
1172 1173
		this.setFontAliasing(this.fontAliasing);

B
Benjamin Pasero 已提交
1174
		// Apply title style if shown
1175 1176 1177 1178 1179 1180 1181 1182
		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 已提交
1183 1184
		}

E
Erich Gamma 已提交
1185
		// Create Parts
B
Benjamin Pasero 已提交
1186
		this.createTitlebarPart();
E
Erich Gamma 已提交
1187 1188 1189
		this.createActivityBarPart();
		this.createSidebarPart();
		this.createEditorPart();
1190
		this.createPanelPart();
E
Erich Gamma 已提交
1191 1192 1193 1194 1195 1196
		this.createStatusbarPart();

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

B
Benjamin Pasero 已提交
1197 1198 1199 1200 1201 1202 1203 1204 1205 1206
	private createTitlebarPart(): void {
		const titlebarContainer = $(this.workbench).div({
			'class': ['part', 'titlebar'],
			id: Identifiers.TITLEBAR_PART,
			role: 'contentinfo'
		});

		this.titlebarPart.create(titlebarContainer);
	}

E
Erich Gamma 已提交
1207
	private createActivityBarPart(): void {
B
Benjamin Pasero 已提交
1208
		const activitybarPartContainer = $(this.workbench)
E
Erich Gamma 已提交
1209 1210
			.div({
				'class': ['part', 'activitybar', this.sideBarPosition === Position.LEFT ? 'left' : 'right'],
1211 1212
				id: Identifiers.ACTIVITYBAR_PART,
				role: 'navigation'
E
Erich Gamma 已提交
1213 1214 1215 1216 1217 1218
			});

		this.activitybarPart.create(activitybarPartContainer);
	}

	private createSidebarPart(): void {
B
Benjamin Pasero 已提交
1219
		const sidebarPartContainer = $(this.workbench)
E
Erich Gamma 已提交
1220 1221
			.div({
				'class': ['part', 'sidebar', this.sideBarPosition === Position.LEFT ? 'left' : 'right'],
1222 1223
				id: Identifiers.SIDEBAR_PART,
				role: 'complementary'
E
Erich Gamma 已提交
1224 1225 1226 1227 1228
			});

		this.sidebarPart.create(sidebarPartContainer);
	}

I
isidor 已提交
1229
	private createPanelPart(): void {
B
Benjamin Pasero 已提交
1230
		const panelPartContainer = $(this.workbench)
I
isidor 已提交
1231
			.div({
1232
				'class': ['part', 'panel', this.panelPosition === Position.BOTTOM ? 'bottom' : 'right'],
1233 1234
				id: Identifiers.PANEL_PART,
				role: 'complementary'
I
isidor 已提交
1235 1236 1237 1238 1239
			});

		this.panelPart.create(panelPartContainer);
	}

E
Erich Gamma 已提交
1240
	private createEditorPart(): void {
B
Benjamin Pasero 已提交
1241
		const editorContainer = $(this.workbench)
E
Erich Gamma 已提交
1242
			.div({
1243
				'class': ['part', 'editor', 'empty'],
1244 1245
				id: Identifiers.EDITOR_PART,
				role: 'main'
E
Erich Gamma 已提交
1246 1247 1248 1249 1250 1251
			});

		this.editorPart.create(editorContainer);
	}

	private createStatusbarPart(): void {
B
Benjamin Pasero 已提交
1252
		const statusbarContainer = $(this.workbench).div({
E
Erich Gamma 已提交
1253
			'class': ['part', 'statusbar'],
1254 1255
			id: Identifiers.STATUSBAR_PART,
			role: 'contentinfo'
E
Erich Gamma 已提交
1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268
		});

		this.statusbarPart.create(statusbarContainer);
	}

	public getEditorPart(): EditorPart {
		return this.editorPart;
	}

	public getSidebarPart(): SidebarPart {
		return this.sidebarPart;
	}

I
isidor 已提交
1269 1270 1271 1272
	public getPanelPart(): PanelPart {
		return this.panelPart;
	}

E
Erich Gamma 已提交
1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287
	public getInstantiationService(): IInstantiationService {
		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);
		}
	}
1288 1289 1290 1291

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

I
isidor 已提交
1293
	public toggleZenMode(skipLayout?: boolean): void {
I
isidor 已提交
1294
		this.zenMode.active = !this.zenMode.active;
1295

I
isidor 已提交
1296
		// 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
1297
		let toggleFullScreen = false;
I
isidor 已提交
1298
		if (this.zenMode.active) {
I
isidor 已提交
1299 1300
			const config = this.configurationService.getConfiguration<IZenModeSettings>('zenMode');
			toggleFullScreen = !browser.isFullscreen() && config.fullScreen;
I
isidor 已提交
1301
			this.zenMode.transitionedToFullScreen = toggleFullScreen;
1302 1303
			this.zenMode.wasSideBarVisible = this.isVisible(Parts.SIDEBAR_PART);
			this.zenMode.wasPanelVisible = this.isVisible(Parts.PANEL_PART);
1304
			this.setPanelHidden(true, true).done(undefined, errors.onUnexpectedError);
1305
			this.setSideBarHidden(true, true).done(undefined, errors.onUnexpectedError);
I
isidor 已提交
1306

1307 1308 1309
			if (config.hideActivityBar) {
				this.setActivityBarHidden(true, true);
			}
1310

I
isidor 已提交
1311
			if (config.hideStatusBar) {
I
isidor 已提交
1312 1313
				this.setStatusBarHidden(true, true);
			}
1314

I
isidor 已提交
1315
			if (config.hideTabs) {
I
isidor 已提交
1316 1317
				this.editorPart.hideTabs(true);
			}
1318
		} else {
1319
			if (this.zenMode.wasPanelVisible) {
1320
				this.setPanelHidden(false, true).done(undefined, errors.onUnexpectedError);
1321
			}
1322

1323
			if (this.zenMode.wasSideBarVisible) {
1324
				this.setSideBarHidden(false, true).done(undefined, errors.onUnexpectedError);
1325
			}
1326

1327 1328
			// Status bar and activity bar visibility come from settings -> update their visibility.
			this.onDidUpdateConfiguration(true);
I
isidor 已提交
1329
			this.editorPart.hideTabs(false);
I
isidor 已提交
1330 1331 1332 1333
			const activeEditor = this.editorPart.getActiveEditor();
			if (activeEditor) {
				activeEditor.focus();
			}
1334

1335
			toggleFullScreen = this.zenMode.transitionedToFullScreen && browser.isFullscreen();
I
isidor 已提交
1336
		}
1337

1338
		this.inZenMode.set(this.zenMode.active);
I
isidor 已提交
1339

I
isidor 已提交
1340
		if (!skipLayout) {
1341
			this.layout();
I
isidor 已提交
1342
		}
1343

1344 1345 1346
		if (toggleFullScreen) {
			this.windowService.toggleFullScreen().done(undefined, errors.onUnexpectedError);
		}
I
isidor 已提交
1347 1348
	}

1349 1350 1351 1352 1353 1354 1355 1356 1357 1358
	// 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 已提交
1359
				return; // Cannot resize other parts
1360 1361 1362 1363
		}
	}


1364
	private shouldRestoreLastOpenedViewlet(): boolean {
1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375
		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 已提交
1376
}