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

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

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

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

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

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

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

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

143 144
const Identifiers = {
	WORKBENCH_CONTAINER: 'workbench.main.container',
B
Benjamin Pasero 已提交
145
	TITLEBAR_PART: 'workbench.parts.titlebar',
146 147 148 149
	ACTIVITYBAR_PART: 'workbench.parts.activitybar',
	SIDEBAR_PART: 'workbench.parts.sidebar',
	PANEL_PART: 'workbench.parts.panel',
	EDITOR_PART: 'workbench.parts.editor',
S
SteVen Batten 已提交
150
	STATUSBAR_PART: 'workbench.parts.statusbar'
151 152
};

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

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

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

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

186
	_serviceBrand: any;
187

E
Erich Gamma 已提交
188
	private workbenchParams: WorkbenchParams;
B
Benjamin Pasero 已提交
189
	private workbench: HTMLElement;
E
Erich Gamma 已提交
190 191 192
	private workbenchStarted: boolean;
	private workbenchCreated: boolean;
	private workbenchShutdown: boolean;
193

194 195
	private editorService: EditorService;
	private editorGroupService: IEditorGroupsService;
P
Pine Wu 已提交
196
	private viewletService: IViewletService;
J
Joao Moreno 已提交
197
	private contextViewService: ContextViewService;
198
	private contextKeyService: IContextKeyService;
199
	private keybindingService: IKeybindingService;
200
	private backupFileService: IBackupFileService;
201
	private fileService: IFileService;
202 203 204 205
	private quickInput: QuickInputService;

	private workbenchLayout: WorkbenchLayout;

B
Benjamin Pasero 已提交
206
	private titlebarPart: TitlebarPart;
E
Erich Gamma 已提交
207 208
	private activitybarPart: ActivitybarPart;
	private sidebarPart: SidebarPart;
I
isidor 已提交
209
	private panelPart: PanelPart;
E
Erich Gamma 已提交
210 211 212
	private editorPart: EditorPart;
	private statusbarPart: StatusbarPart;
	private quickOpen: QuickOpenController;
213
	private notificationsCenter: NotificationsCenter;
214
	private notificationsToasts: NotificationsToasts;
215

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

I
isidor 已提交
228
	private inZenMode: IContextKey<boolean>;
229
	private sideBarVisibleContext: IContextKey<boolean>;
230

B
Benjamin Pasero 已提交
231
	private closeEmptyWindowScheduler: RunOnceScheduler = this._register(new RunOnceScheduler(() => this.onAllEditorsClosed(), 50));
E
Erich Gamma 已提交
232

233
	constructor(
234
		private container: HTMLElement,
J
Joao Moreno 已提交
235
		private configuration: IWindowConfiguration,
236
		serviceCollection: ServiceCollection,
237
		private lifecycleService: LifecycleService,
J
Joao Moreno 已提交
238
		private mainProcessClient: IPCClient,
239
		@IInstantiationService private instantiationService: IInstantiationService,
240
		@IWorkspaceContextService private contextService: IWorkspaceContextService,
241
		@IStorageService private storageService: IStorageService,
242
		@IConfigurationService private configurationService: WorkspaceService,
A
Alex Dima 已提交
243
		@IWorkbenchThemeService private themeService: WorkbenchThemeService,
I
isidor 已提交
244
		@IEnvironmentService private environmentService: IEnvironmentService,
245
		@IWindowService private windowService: IWindowService,
B
Benjamin Pasero 已提交
246
		@INotificationService private notificationService: NotificationService
247
	) {
248
		super();
E
Erich Gamma 已提交
249

250
		this.workbenchParams = { configuration, serviceCollection };
E
Erich Gamma 已提交
251

252
		this.hasInitialFilesToOpen =
B
Benjamin Pasero 已提交
253 254 255
			(configuration.filesToCreate && configuration.filesToCreate.length > 0) ||
			(configuration.filesToOpen && configuration.filesToOpen.length > 0) ||
			(configuration.filesToDiff && configuration.filesToDiff.length > 0);
256 257
	}

258
	startup(): TPromise<IWorkbenchStartedInfo> {
259
		this.workbenchStarted = true;
E
Erich Gamma 已提交
260

B
Benjamin Pasero 已提交
261
		// Create Workbench Container
262
		this.createWorkbench();
E
Erich Gamma 已提交
263

264 265
		// Install some global actions
		this.createGlobalActions();
266

267 268
		// Services
		this.initServices();
E
Erich Gamma 已提交
269

270 271
		// Context Keys
		this.handleContextKeys();
J
Joao Moreno 已提交
272

273 274
		// Register Listeners
		this.registerListeners();
E
Erich Gamma 已提交
275

276 277
		// Settings
		this.initSettings();
E
Erich Gamma 已提交
278

279 280
		// Create Workbench and Parts
		this.renderWorkbench();
281

282 283
		// Workbench Layout
		this.createWorkbenchLayout();
B
polish  
Benjamin Pasero 已提交
284

J
Joao Moreno 已提交
285 286
		// Driver
		if (this.environmentService.driverHandle) {
287
			registerWindowDriver(this.mainProcessClient, this.configuration.windowId, this.instantiationService).then(disposable => this._register(disposable));
J
Joao Moreno 已提交
288 289
		}

290
		// Restore Parts
B
Benjamin Pasero 已提交
291 292
		return this.restoreParts();
	}
293

B
Benjamin Pasero 已提交
294
	private createWorkbench(): void {
B
Benjamin Pasero 已提交
295 296 297
		this.workbench = document.createElement('div');
		this.workbench.id = Identifiers.WORKBENCH_CONTAINER;
		DOM.addClasses(this.workbench, 'monaco-workbench', isWindows ? 'windows' : isLinux ? 'linux' : 'mac');
S
SteVen Batten 已提交
298

B
Benjamin Pasero 已提交
299 300 301
		this._register(DOM.addDisposableListener(this.workbench, DOM.EventType.SCROLL, () => {
			this.workbench.scrollTop = 0; // Prevent workbench from scrolling #55456
		}));
302
	}
E
Erich Gamma 已提交
303

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

B
Benjamin Pasero 已提交
307
		// Actions registered here to adjust for developing vs built workbench
308 309 310 311 312
		const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
		registry.registerWorkbenchAction(new SyncActionDescriptor(ReloadWindowAction, ReloadWindowAction.ID, ReloadWindowAction.LABEL, isDeveloping ? { primary: KeyMod.CtrlCmd | KeyCode.KEY_R } : void 0), 'Reload Window');
		registry.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"));
		registry.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"));
		registry.registerWorkbenchAction(new SyncActionDescriptor(ReloadWindowWithExtensionsDisabledAction, ReloadWindowWithExtensionsDisabledAction.ID, ReloadWindowWithExtensionsDisabledAction.LABEL), 'Reload Window Without Extensions');
313

314
		// Actions for macOS native tabs management (only when enabled)
315
		const windowConfig = this.configurationService.getValue<IWindowConfiguration>();
316
		if (windowConfig && windowConfig.window && windowConfig.window.nativeTabs) {
317
			registry.registerWorkbenchAction(new SyncActionDescriptor(NewWindowTab, NewWindowTab.ID, NewWindowTab.LABEL), 'New Window Tab');
318 319 320 321 322
			registry.registerWorkbenchAction(new SyncActionDescriptor(ShowPreviousWindowTab, ShowPreviousWindowTab.ID, ShowPreviousWindowTab.LABEL), 'Show Previous Window Tab');
			registry.registerWorkbenchAction(new SyncActionDescriptor(ShowNextWindowTab, ShowNextWindowTab.ID, ShowNextWindowTab.LABEL), 'Show Next Window Tab');
			registry.registerWorkbenchAction(new SyncActionDescriptor(MoveWindowTabToNewWindow, MoveWindowTabToNewWindow.ID, MoveWindowTabToNewWindow.LABEL), 'Move Window Tab to New Window');
			registry.registerWorkbenchAction(new SyncActionDescriptor(MergeAllWindowTabs, MergeAllWindowTabs.ID, MergeAllWindowTabs.LABEL), 'Merge All Windows');
			registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleWindowTabsBar, ToggleWindowTabsBar.ID, ToggleWindowTabsBar.LABEL), 'Toggle Window Tabs Bar');
323
		}
324 325
	}

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

E
Erich Gamma 已提交
329
		// Services we contribute
330
		serviceCollection.set(IPartService, this);
E
Erich Gamma 已提交
331

332
		// Clipboard
J
Johannes Rieken 已提交
333
		serviceCollection.set(IClipboardService, new SyncDescriptor(ClipboardService));
334

335 336
		// Status bar
		this.statusbarPart = this.instantiationService.createInstance(StatusbarPart, Identifiers.STATUSBAR_PART);
337
		this._register(toDisposable(() => this.statusbarPart.shutdown()));
338 339
		serviceCollection.set(IStatusbarService, this.statusbarPart);

340 341 342
		// Progress 2
		serviceCollection.set(IProgressService2, new SyncDescriptor(ProgressService2));

343
		// Keybindings
A
Alex Dima 已提交
344
		this.contextKeyService = this.instantiationService.createInstance(ContextKeyService);
345
		serviceCollection.set(IContextKeyService, this.contextKeyService);
346

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

350 351 352
		// List
		serviceCollection.set(IListService, this.instantiationService.createInstance(ListService));

J
Joao Moreno 已提交
353
		// Context view service
B
Benjamin Pasero 已提交
354
		this.contextViewService = this.instantiationService.createInstance(ContextViewService, this.workbench);
J
Joao Moreno 已提交
355 356
		serviceCollection.set(IContextViewService, this.contextViewService);

S
SteVen Batten 已提交
357
		// Use themable context menus when custom titlebar is enabled to match custom menubar
B
Benjamin Pasero 已提交
358
		if (!isMacintosh && this.getCustomTitleBarStyle() === 'custom') {
359
			serviceCollection.set(IContextMenuService, new SyncDescriptor(HTMLContextMenuService, null));
S
SteVen Batten 已提交
360 361 362
		} else {
			serviceCollection.set(IContextMenuService, new SyncDescriptor(NativeContextMenuService));
		}
363

364 365
		// Menus/Actions
		serviceCollection.set(IMenuService, new SyncDescriptor(MenuService));
366

P
Pine Wu 已提交
367
		// Sidebar part
368
		this.sidebarPart = this.instantiationService.createInstance(SidebarPart, Identifiers.SIDEBAR_PART);
369
		this._register(toDisposable(() => this.sidebarPart.shutdown()));
P
Pine Wu 已提交
370 371 372 373

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

I
isidor 已提交
375
		// Panel service (panel part)
376
		this.panelPart = this.instantiationService.createInstance(PanelPart, Identifiers.PANEL_PART);
377
		this._register(toDisposable(() => this.panelPart.shutdown()));
378
		serviceCollection.set(IPanelService, this.panelPart);
I
isidor 已提交
379

380 381 382
		// views service
		const viewsService = this.instantiationService.createInstance(ViewsService);
		serviceCollection.set(IViewsService, viewsService);
S
Sandeep Somavarapu 已提交
383

E
Erich Gamma 已提交
384
		// Activity service (activitybar part)
385
		this.activitybarPart = this.instantiationService.createInstance(ActivitybarPart, Identifiers.ACTIVITYBAR_PART);
386
		this._register(toDisposable(() => this.activitybarPart.shutdown()));
I
isidor 已提交
387 388
		const activityService = this.instantiationService.createInstance(ActivityService, this.activitybarPart, this.panelPart);
		serviceCollection.set(IActivityService, activityService);
E
Erich Gamma 已提交
389

390 391 392
		// File Service
		this.fileService = this.instantiationService.createInstance(RemoteFileService);
		serviceCollection.set(IFileService, this.fileService);
S
#47154  
Sandeep Somavarapu 已提交
393
		this.configurationService.acquireFileService(this.fileService);
A
Alex Dima 已提交
394
		this.themeService.acquireFileService(this.fileService);
395

396 397
		// Editor and Group services
		const restorePreviousEditorState = !this.hasInitialFilesToOpen;
398
		this.editorPart = this.instantiationService.createInstance(EditorPart, Identifiers.EDITOR_PART, restorePreviousEditorState);
399
		this._register(toDisposable(() => this.editorPart.shutdown()));
B
Benjamin Pasero 已提交
400
		this.editorGroupService = this.editorPart;
401 402 403
		serviceCollection.set(IEditorGroupsService, this.editorPart);
		this.editorService = this.instantiationService.createInstance(EditorService);
		serviceCollection.set(IEditorService, this.editorService);
E
Erich Gamma 已提交
404

405 406
		// Title bar
		this.titlebarPart = this.instantiationService.createInstance(TitlebarPart, Identifiers.TITLEBAR_PART);
407
		this._register(toDisposable(() => this.titlebarPart.shutdown()));
408
		serviceCollection.set(ITitleService, this.titlebarPart);
B
Benjamin Pasero 已提交
409

410
		// History
411
		serviceCollection.set(IHistoryService, new SyncDescriptor(HistoryService));
412

M
Martin Aeschlimann 已提交
413 414 415
		// File Dialogs
		serviceCollection.set(IFileDialogService, new SyncDescriptor(FileDialogService));

416
		// Backup File Service
B
Benjamin Pasero 已提交
417 418 419 420 421
		if (this.workbenchParams.configuration.backupPath) {
			this.backupFileService = this.instantiationService.createInstance(BackupFileService, this.workbenchParams.configuration.backupPath);
		} else {
			this.backupFileService = new InMemoryBackupFileService();
		}
422
		serviceCollection.set(IBackupFileService, this.backupFileService);
423

424
		// Text File Service
425
		serviceCollection.set(ITextFileService, new SyncDescriptor(TextFileService));
426

427
		// File Decorations
J
Johannes Rieken 已提交
428
		serviceCollection.set(IDecorationsService, new SyncDescriptor(FileDecorationsService));
429

J
Joao Moreno 已提交
430
		// SCM Service
431
		serviceCollection.set(ISCMService, new SyncDescriptor(SCMService));
432

J
Joao Moreno 已提交
433
		// Inactive extension URL handler
J
Joao Moreno 已提交
434
		serviceCollection.set(IExtensionUrlHandler, new SyncDescriptor(ExtensionUrlHandler));
J
Joao Moreno 已提交
435

B
Benjamin Pasero 已提交
436
		// Text Model Resolver Service
437
		serviceCollection.set(ITextModelService, new SyncDescriptor(TextModelResolverService));
B
Benjamin Pasero 已提交
438

439 440 441 442
		// JSON Editing
		const jsonEditingService = this.instantiationService.createInstance(JSONEditingService);
		serviceCollection.set(IJSONEditingService, jsonEditingService);

443 444 445
		// Workspace Editing
		serviceCollection.set(IWorkspaceEditingService, new SyncDescriptor(WorkspaceEditingService));

446 447 448
		// Keybinding Editing
		serviceCollection.set(IKeybindingEditingService, this.instantiationService.createInstance(KeybindingsEditingService));

449
		// Configuration Resolver
B
Benjamin Pasero 已提交
450
		serviceCollection.set(IConfigurationResolverService, new SyncDescriptor(ConfigurationResolverService, process.env));
451

E
Erich Gamma 已提交
452
		// Quick open service (quick open controller)
453
		this.quickOpen = this.instantiationService.createInstance(QuickOpenController);
454
		this._register(toDisposable(() => this.quickOpen.shutdown()));
455
		serviceCollection.set(IQuickOpenService, this.quickOpen);
456

C
Christof Marti 已提交
457 458
		// Quick input service
		this.quickInput = this.instantiationService.createInstance(QuickInputService);
459
		this._register(toDisposable(() => this.quickInput.shutdown()));
C
Christof Marti 已提交
460 461
		serviceCollection.set(IQuickInputService, this.quickInput);

S
Sandeep Somavarapu 已提交
462 463 464
		// PreferencesService
		serviceCollection.set(IPreferencesService, this.instantiationService.createInstance(PreferencesService));

B
polish  
Benjamin Pasero 已提交
465
		// Contributed services
B
Benjamin Pasero 已提交
466
		const contributedServices = getServices();
E
Erich Gamma 已提交
467
		for (let contributedService of contributedServices) {
468
			serviceCollection.set(contributedService.id, contributedService.descriptor);
E
Erich Gamma 已提交
469 470 471
		}

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

476
		this.instantiationService.createInstance(DefaultConfigurationExportHelper);
477

S
#47154  
Sandeep Somavarapu 已提交
478
		this.configurationService.acquireInstantiationService(this.getInstantiationService());
E
Erich Gamma 已提交
479 480
	}

481
	//#region event handling
E
Erich Gamma 已提交
482

483
	private registerListeners(): void {
I
isidor 已提交
484

485
		// Listen to visible editor changes
486
		this._register(this.editorService.onDidVisibleEditorsChange(() => this.onDidVisibleEditorsChange()));
B
Benjamin Pasero 已提交
487

488 489 490
		// Listen to editor closing (if we run with --wait)
		const filesToWait = this.workbenchParams.configuration.filesToWait;
		if (filesToWait) {
491
			const resourcesToWaitFor = filesToWait.paths.map(p => p.fileUri);
492
			const waitMarkerFile = URI.file(filesToWait.waitMarkerFilePath);
493
			const listenerDispose = this.editorService.onDidCloseEditor(() => this.onEditorClosed(listenerDispose, resourcesToWaitFor, waitMarkerFile));
I
isidor 已提交
494

495
			this._register(listenerDispose);
496
		}
S
Sanders Lauture 已提交
497

498
		// Configuration changes
499
		this._register(this.configurationService.onDidChangeConfiguration(() => this.onDidUpdateConfiguration()));
I
isidor 已提交
500

501
		// Fullscreen changes
502
		this._register(browser.onDidChangeFullscreen(() => this.onFullscreenChanged()));
503
	}
504

505 506 507 508
	private onFullscreenChanged(): void {
		if (!this.isCreated) {
			return; // we need to be ready
		}
S
SrTobi 已提交
509

510 511 512
		// Apply as CSS class
		const isFullscreen = browser.isFullscreen();
		if (isFullscreen) {
B
Benjamin Pasero 已提交
513
			DOM.addClass(this.workbench, 'fullscreen');
514
		} else {
B
Benjamin Pasero 已提交
515 516
			DOM.removeClass(this.workbench, 'fullscreen');

517 518 519 520
			if (this.zenMode.transitionedToFullScreen && this.zenMode.active) {
				this.toggleZenMode();
			}
		}
E
Erich Gamma 已提交
521

522 523 524 525 526 527
		// 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
		}
528 529
	}

530 531 532 533 534
	private onMenubarToggled(visible: boolean) {
		if (visible !== this.menubarToggled) {
			this.menubarToggled = visible;

			if (this.menubarVisibility === 'toggle' || (browser.isFullscreen() && this.menubarVisibility === 'default')) {
S
SteVen Batten 已提交
535 536 537 538
				if (browser.isFullscreen() && this.menubarVisibility === 'default') {
					this._onTitleBarVisibilityChange.fire();
				}

539 540 541 542 543
				this.layout();
			}
		}
	}

544
	private onEditorClosed(listenerDispose: IDisposable, resourcesToWaitFor: URI[], waitMarkerFile: URI): void {
E
Erich Gamma 已提交
545

546 547 548
		// 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.
549
		if (resourcesToWaitFor.every(resource => !this.editorService.isOpen({ resource }))) {
550
			listenerDispose.dispose();
551
			this.fileService.del(waitMarkerFile);
552
		}
E
Erich Gamma 已提交
553 554
	}

555
	private onDidVisibleEditorsChange(): void {
556
		const visibleEditors = this.editorService.visibleControls;
E
Erich Gamma 已提交
557

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

569
	private onAllEditorsClosed(): void {
570
		const visibleEditors = this.editorService.visibleControls.length;
571 572
		if (visibleEditors === 0) {
			this.windowService.closeWindow();
E
Erich Gamma 已提交
573 574 575
		}
	}

576 577 578 579 580
	private onDidUpdateConfiguration(skipLayout?: boolean): void {
		const newSidebarPositionValue = this.configurationService.getValue<string>(Workbench.sidebarPositionConfigurationKey);
		const newSidebarPosition = (newSidebarPositionValue === 'right') ? Position.RIGHT : Position.LEFT;
		if (newSidebarPosition !== this.getSideBarPosition()) {
			this.setSideBarPosition(newSidebarPosition);
581
		}
E
Erich Gamma 已提交
582

583
		this.setPanelPositionFromStorageOrConfig();
E
Erich Gamma 已提交
584

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

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

596 597 598 599
			const newActivityBarHiddenValue = !this.configurationService.getValue<boolean>(Workbench.activityBarVisibleConfigurationKey);
			if (newActivityBarHiddenValue !== this.activityBarHidden) {
				this.setActivityBarHidden(newActivityBarHiddenValue, skipLayout);
			}
B
Benjamin Pasero 已提交
600
		}
S
SteVen Batten 已提交
601

602
		const newMenubarVisibility = this.configurationService.getValue<MenuBarVisibility>(Workbench.menubarVisibilityConfigurationKey);
S
SteVen Batten 已提交
603
		this.setMenubarVisibility(newMenubarVisibility, skipLayout);
604
	}
B
Benjamin Pasero 已提交
605

606
	//#endregion
B
Benjamin Pasero 已提交
607

608 609
	private handleContextKeys(): void {
		this.inZenMode = InEditorZenModeContext.bindTo(this.contextKeyService);
610

I
isidor 已提交
611 612 613
		IsMacContext.bindTo(this.contextKeyService);
		IsLinuxContext.bindTo(this.contextKeyService);
		IsWindowsContext.bindTo(this.contextKeyService);
614

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

618
		const activeEditorContext = ActiveEditorContext.bindTo(this.contextKeyService);
619 620
		const editorsVisibleContext = EditorsVisibleContext.bindTo(this.contextKeyService);
		const textCompareEditorVisible = TextCompareEditorVisibleContext.bindTo(this.contextKeyService);
621
		const textCompareEditorActive = TextCompareEditorActiveContext.bindTo(this.contextKeyService);
622 623
		const activeEditorGroupEmpty = ActiveEditorGroupEmptyContext.bindTo(this.contextKeyService);
		const multipleEditorGroups = MultipleEditorGroupsContext.bindTo(this.contextKeyService);
624

625
		const updateEditorContextKeys = () => {
626
			const activeControl = this.editorService.activeControl;
627
			const visibleEditors = this.editorService.visibleControls;
E
Erich Gamma 已提交
628

629
			textCompareEditorActive.set(activeControl && activeControl.getId() === TEXT_DIFF_EDITOR_ID);
630
			textCompareEditorVisible.set(visibleEditors.some(control => control.getId() === TEXT_DIFF_EDITOR_ID));
I
isidor 已提交
631

632 633 634 635
			if (visibleEditors.length > 0) {
				editorsVisibleContext.set(true);
			} else {
				editorsVisibleContext.reset();
636
			}
B
Benjamin Pasero 已提交
637

638
			if (!this.editorService.activeEditor) {
639 640 641
				activeEditorGroupEmpty.set(true);
			} else {
				activeEditorGroupEmpty.reset();
642
			}
643

B
Benjamin Pasero 已提交
644
			if (this.editorGroupService.count > 1) {
645 646 647 648
				multipleEditorGroups.set(true);
			} else {
				multipleEditorGroups.reset();
			}
649 650 651 652 653 654

			if (activeControl) {
				activeEditorContext.set(activeControl.getId());
			} else {
				activeEditorContext.reset();
			}
655
		};
B
Benjamin Pasero 已提交
656

657
		this.editorPart.whenRestored.then(() => updateEditorContextKeys());
658 659
		this._register(this.editorService.onDidActiveEditorChange(() => updateEditorContextKeys()));
		this._register(this.editorService.onDidVisibleEditorsChange(() => updateEditorContextKeys()));
B
Benjamin Pasero 已提交
660 661
		this._register(this.editorGroupService.onDidAddGroup(() => updateEditorContextKeys()));
		this._register(this.editorGroupService.onDidRemoveGroup(() => updateEditorContextKeys()));
662

663 664 665 666 667 668 669 670 671 672
		const inputFocused = InputFocusedContext.bindTo(this.contextKeyService);
		this._register(DOM.addDisposableListener(window, 'focusin', () => {
			inputFocused.set(document.activeElement && (document.activeElement.tagName === 'INPUT' || document.activeElement.tagName === 'TEXTAREA'));
		}, true));

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

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

680
		const splitEditorsVerticallyContext = SplitEditorsVertically.bindTo(this.contextKeyService);
S
Sanders Lauture 已提交
681

682 683 684 685
		const updateSplitEditorsVerticallyContext = () => {
			const direction = preferredSideBySideGroupDirection(this.configurationService);
			splitEditorsVerticallyContext.set(direction === GroupDirection.DOWN);
		};
S
Sanders Lauture 已提交
686

687 688 689 690 691
		this._register(this.configurationService.onDidChangeConfiguration(e => {
			if (e.affectsConfiguration('workbench.editor.openSideBySideDirection')) {
				updateSplitEditorsVerticallyContext();
			}
		}));
E
Erich Gamma 已提交
692

693
		updateSplitEditorsVerticallyContext();
694
	}
E
Erich Gamma 已提交
695

696 697
	private restoreParts(): TPromise<IWorkbenchStartedInfo> {
		const restorePromises: Thenable<any>[] = [];
B
Benjamin Pasero 已提交
698

699 700
		// Restore Editorpart
		perf.mark('willRestoreEditors');
701
		restorePromises.push(this.editorPart.whenRestored.then(() => {
702 703
			return this.resolveEditorsToOpen().then(inputs => {
				if (inputs.length) {
704
					return this.editorService.openEditors(inputs);
705
				}
E
Erich Gamma 已提交
706

707 708 709 710 711
				return TPromise.as(void 0);
			});
		}).then(() => {
			perf.mark('didRestoreEditors');
		}));
E
Erich Gamma 已提交
712

713 714 715 716
		// Restore Sidebar
		let viewletIdToRestore: string;
		if (!this.sideBarHidden) {
			this.sideBarVisibleContext.set(true);
717

718 719
			if (this.shouldRestoreLastOpenedViewlet()) {
				viewletIdToRestore = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE);
720
			}
721

722 723
			if (!viewletIdToRestore) {
				viewletIdToRestore = this.viewletService.getDefaultViewletId();
724
			}
E
Erich Gamma 已提交
725

726
			perf.mark('willRestoreViewlet');
727 728 729 730 731
			restorePromises.push(this.viewletService.openViewlet(viewletIdToRestore)
				.then(viewlet => viewlet || this.viewletService.openViewlet(this.viewletService.getDefaultViewletId()))
				.then(() => {
					perf.mark('didRestoreViewlet');
				}));
732 733
		}

734 735 736 737
		// Restore Panel
		const panelRegistry = Registry.as<PanelRegistry>(PanelExtensions.Panels);
		const panelId = this.storageService.get(PanelPart.activePanelSettingsKey, StorageScope.WORKSPACE, panelRegistry.getDefaultPanelId());
		if (!this.panelHidden && !!panelId) {
738
			perf.mark('willRestorePanel');
739
			const isPanelToRestoreEnabled = !!this.panelPart.getPanels().filter(p => p.id === panelId).length;
740 741
			const panelIdToRestore = isPanelToRestoreEnabled ? panelId : panelRegistry.getDefaultPanelId();
			restorePromises.push(this.panelPart.openPanel(panelIdToRestore, false).then(() => perf.mark('didRestorePanel')));
I
isidor 已提交
742 743
		}

744
		// Restore Zen Mode if active
I
isidor 已提交
745
		if (this.storageService.getBoolean(Workbench.zenModeActiveStorageKey, StorageScope.WORKSPACE, false)) {
I
isidor 已提交
746
			this.toggleZenMode(true, true);
I
isidor 已提交
747 748
		}

B
Benjamin Pasero 已提交
749
		// Restore Forced Editor Center Mode
750
		if (this.storageService.getBoolean(Workbench.centeredEditorLayoutActiveStorageKey, StorageScope.WORKSPACE, false)) {
I
isidor 已提交
751
			this.centerEditorLayout(true);
S
SrTobi 已提交
752
		}
753

754
		const onRestored = (error?: Error): IWorkbenchStartedInfo => {
B
Benjamin Pasero 已提交
755
			this.workbenchCreated = true;
756

757 758
			if (error) {
				errors.onUnexpectedError(error);
759
			}
I
isidor 已提交
760

761 762 763 764
			return {
				customKeybindingsCount: this.keybindingService.customKeybindingsCount(),
				pinnedViewlets: this.activitybarPart.getPinned(),
				restoredViewlet: viewletIdToRestore,
765
				restoredEditorsCount: this.editorService.visibleEditors.length
766 767
			};
		};
768

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

772 773 774
	private shouldRestoreLastOpenedViewlet(): boolean {
		if (!this.environmentService.isBuilt) {
			return true; // always restore sidebar when we are in development mode
E
Erich Gamma 已提交
775 776
		}

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

782
		return restore;
E
Erich Gamma 已提交
783 784
	}

785
	private resolveEditorsToOpen(): TPromise<IResourceEditor[]> {
786
		const config = this.workbenchParams.configuration;
I
isidor 已提交
787

B
Benjamin Pasero 已提交
788
		// Files to open, diff or create
789
		if (this.hasInitialFilesToOpen) {
I
isidor 已提交
790

B
Benjamin Pasero 已提交
791
			// Files to diff is exclusive
792
			const filesToDiff = this.toInputs(config.filesToDiff, false);
793
			if (filesToDiff && filesToDiff.length === 2) {
794 795 796
				return TPromise.as([<IResourceDiffInput>{
					leftResource: filesToDiff[0].resource,
					rightResource: filesToDiff[1].resource,
B
Benjamin Pasero 已提交
797
					options: { pinned: true },
B
Benjamin Pasero 已提交
798
					forceFile: true
799
				}]);
B
Benjamin Pasero 已提交
800
			}
I
isidor 已提交
801

802 803
			const filesToCreate = this.toInputs(config.filesToCreate, true);
			const filesToOpen = this.toInputs(config.filesToOpen, false);
I
isidor 已提交
804

805 806
			// Otherwise: Open/Create files
			return TPromise.as([...filesToOpen, ...filesToCreate]);
B
Benjamin Pasero 已提交
807
		}
I
isidor 已提交
808

809
		// Empty workbench
810
		else if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY && this.openUntitledFile()) {
B
Benjamin Pasero 已提交
811
			const isEmpty = this.editorGroupService.count === 1 && this.editorGroupService.activeGroup.count === 0;
812 813
			if (!isEmpty) {
				return TPromise.as([]); // do not open any empty untitled file if we restored editors from previous session
814
			}
B
Benjamin Pasero 已提交
815

816 817 818 819
			return this.backupFileService.hasBackups().then(hasBackups => {
				if (hasBackups) {
					return TPromise.as([]); // do not open any empty untitled file if we have backups to restore
				}
B
Benjamin Pasero 已提交
820

821
				return TPromise.as([<IUntitledResourceInput>{}]);
822
			});
823
		}
824

B
Benjamin Pasero 已提交
825 826
		return TPromise.as([]);
	}
827

828
	private toInputs(paths: IPath[], isNew: boolean): (IResourceInput | IUntitledResourceInput)[] {
B
Benjamin Pasero 已提交
829 830
		if (!paths || !paths.length) {
			return [];
831
		}
I
isidor 已提交
832

B
Benjamin Pasero 已提交
833
		return paths.map(p => {
834
			const resource = p.fileUri;
835 836 837 838
			let input: IResourceInput | IUntitledResourceInput;
			if (isNew) {
				input = { filePath: resource.fsPath, options: { pinned: true } } as IUntitledResourceInput;
			} else {
B
Benjamin Pasero 已提交
839
				input = { resource, options: { pinned: true }, forceFile: true } as IResourceInput;
840
			}
E
Erich Gamma 已提交
841

842
			if (!isNew && p.lineNumber) {
B
Benjamin Pasero 已提交
843 844 845 846 847
				input.options.selection = {
					startLineNumber: p.lineNumber,
					startColumn: p.columnNumber
				};
			}
848

B
Benjamin Pasero 已提交
849 850
			return input;
		});
851 852
	}

853
	private openUntitledFile() {
854
		const startupEditor = this.configurationService.inspect('workbench.startupEditor');
B
Benjamin Pasero 已提交
855 856

		// Fallback to previous workbench.welcome.enabled setting in case startupEditor is not defined
857
		if (!startupEditor.user && !startupEditor.workspace) {
858 859 860
			const welcomeEnabledValue = this.configurationService.getValue('workbench.welcome.enabled');
			if (typeof welcomeEnabledValue === 'boolean') {
				return !welcomeEnabledValue;
861
			}
862
		}
E
Erich Gamma 已提交
863

864
		return startupEditor.value === 'newUntitledFile';
865
	}
E
Erich Gamma 已提交
866 867

	private initSettings(): void {
868

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

I
isidor 已提交
872
		// Panel part visibility
873
		const panelRegistry = Registry.as<PanelRegistry>(PanelExtensions.Panels);
I
isidor 已提交
874
		this.panelHidden = this.storageService.getBoolean(Workbench.panelHiddenStorageKey, StorageScope.WORKSPACE, true);
875 876
		if (!panelRegistry.getDefaultPanelId()) {
			this.panelHidden = true; // we hide panel part if there is no default panel
877 878
		}

E
Erich Gamma 已提交
879
		// Sidebar position
880
		const sideBarPosition = this.configurationService.getValue<string>(Workbench.sidebarPositionConfigurationKey);
881
		this.sideBarPosition = (sideBarPosition === 'right') ? Position.RIGHT : Position.LEFT;
882

I
isidor 已提交
883
		// Panel position
884
		this.setPanelPositionFromStorageOrConfig();
885

886
		// Menubar visibility
887
		const menuBarVisibility = this.configurationService.getValue<MenuBarVisibility>(Workbench.menubarVisibilityConfigurationKey);
S
SteVen Batten 已提交
888
		this.setMenubarVisibility(menuBarVisibility, true);
889

B
Benjamin Pasero 已提交
890
		// Statusbar visibility
891
		const statusBarVisible = this.configurationService.getValue<string>(Workbench.statusbarVisibleConfigurationKey);
892
		this.statusBarHidden = !statusBarVisible;
893

S
Sanders Lauture 已提交
894
		// Activity bar visibility
895
		const activityBarVisible = this.configurationService.getValue<string>(Workbench.activityBarVisibleConfigurationKey);
S
Sanders Lauture 已提交
896
		this.activityBarHidden = !activityBarVisible;
897

898
		// Font aliasing
899
		this.fontAliasing = this.configurationService.getValue<FontAliasingOption>(Workbench.fontAliasingConfigurationKey);
900

I
isidor 已提交
901 902
		// Zen mode
		this.zenMode = {
I
isidor 已提交
903
			active: false,
904
			transitionedToFullScreen: false,
905
			transitionedToCenteredEditorLayout: false,
906
			wasSideBarVisible: false,
907 908
			wasPanelVisible: false,
			transitionDisposeables: []
I
isidor 已提交
909
		};
E
Erich Gamma 已提交
910 911
	}

912 913 914 915 916
	private setPanelPositionFromStorageOrConfig() {
		const defaultPanelPosition = this.configurationService.getValue<string>(Workbench.defaultPanelPositionStorageKey);
		const panelPosition = this.storageService.get(Workbench.panelPositionStorageKey, StorageScope.WORKSPACE, defaultPanelPosition);
		this.panelPosition = (panelPosition === 'right') ? Position.RIGHT : Position.BOTTOM;
	}
917

918 919
	private getCustomTitleBarStyle(): 'custom' {
		const isDev = !this.environmentService.isBuilt || this.environmentService.isExtensionDevelopment;
B
Benjamin Pasero 已提交
920
		if (isMacintosh && isDev) {
921 922
			return null; // not enabled when developing due to https://github.com/electron/electron/issues/3647
		}
E
Erich Gamma 已提交
923

924 925 926 927 928 929 930 931 932 933
		const windowConfig = this.configurationService.getValue<IWindowSettings>();
		if (windowConfig && windowConfig.window) {
			const useNativeTabs = windowConfig.window.nativeTabs;
			if (useNativeTabs) {
				return null; // native tabs on sierra do not work with custom title style
			}

			const style = windowConfig.window.titleBarStyle;
			if (style === 'custom') {
				return style;
934 935 936
			}
		}

937
		return null;
B
Benjamin Pasero 已提交
938 939
	}

940 941
	private setStatusBarHidden(hidden: boolean, skipLayout?: boolean): void {
		this.statusBarHidden = hidden;
B
Benjamin Pasero 已提交
942

943 944
		// Adjust CSS
		if (hidden) {
B
Benjamin Pasero 已提交
945
			DOM.addClass(this.workbench, 'nostatusbar');
E
Erich Gamma 已提交
946
		} else {
B
Benjamin Pasero 已提交
947
			DOM.removeClass(this.workbench, 'nostatusbar');
E
Erich Gamma 已提交
948 949
		}

950 951 952
		// Layout
		if (!skipLayout) {
			this.workbenchLayout.layout();
953 954 955
		}
	}

956
	private setFontAliasing(aliasing: FontAliasingOption) {
957
		this.fontAliasing = aliasing;
S
Sanders Lauture 已提交
958

B
Benjamin Pasero 已提交
959 960 961 962 963
		// Remove all
		document.body.classList.remove(...fontAliasingValues.map(value => `monaco-font-aliasing-${value}`));

		// Add specific
		if (fontAliasingValues.some(option => option === aliasing)) {
964
			document.body.classList.add(`monaco-font-aliasing-${aliasing}`);
S
Sanders Lauture 已提交
965
		}
966 967
	}

E
Erich Gamma 已提交
968
	private createWorkbenchLayout(): void {
969 970
		this.workbenchLayout = this.instantiationService.createInstance(
			WorkbenchLayout,
971
			this.container,
B
Benjamin Pasero 已提交
972
			this.workbench,
I
isidor 已提交
973
			{
974 975 976 977 978 979
				titlebar: this.titlebarPart,
				activitybar: this.activitybarPart,
				editor: this.editorPart,
				sidebar: this.sidebarPart,
				panel: this.panelPart,
				statusbar: this.statusbarPart,
I
isidor 已提交
980
			},
981 982 983 984
			this.quickOpen,
			this.quickInput,
			this.notificationsCenter,
			this.notificationsToasts
E
Erich Gamma 已提交
985 986 987 988 989 990 991
		);
	}

	private renderWorkbench(): void {

		// Apply sidebar state as CSS class
		if (this.sideBarHidden) {
B
Benjamin Pasero 已提交
992
			DOM.addClass(this.workbench, 'nosidebar');
E
Erich Gamma 已提交
993
		}
B
Benjamin Pasero 已提交
994

995
		if (this.panelHidden) {
B
Benjamin Pasero 已提交
996
			DOM.addClass(this.workbench, 'nopanel');
997
		}
B
Benjamin Pasero 已提交
998

999
		if (this.statusBarHidden) {
B
Benjamin Pasero 已提交
1000
			DOM.addClass(this.workbench, 'nostatusbar');
1001
		}
E
Erich Gamma 已提交
1002

B
Benjamin Pasero 已提交
1003
		// Apply font aliasing
1004 1005
		this.setFontAliasing(this.fontAliasing);

1006 1007
		// Apply fullscreen state
		if (browser.isFullscreen()) {
B
Benjamin Pasero 已提交
1008
			DOM.addClass(this.workbench, 'fullscreen');
B
Benjamin Pasero 已提交
1009 1010
		}

E
Erich Gamma 已提交
1011
		// Create Parts
B
Benjamin Pasero 已提交
1012
		this.createTitlebarPart();
E
Erich Gamma 已提交
1013 1014 1015
		this.createActivityBarPart();
		this.createSidebarPart();
		this.createEditorPart();
1016
		this.createPanelPart();
E
Erich Gamma 已提交
1017 1018
		this.createStatusbarPart();

1019 1020
		// Notification Handlers
		this.createNotificationsHandlers();
1021

1022 1023 1024 1025 1026 1027

		// Menubar visibility changes
		if ((isWindows || isLinux) && this.getCustomTitleBarStyle() === 'custom') {
			this.titlebarPart.onMenubarVisibilityChange()(e => this.onMenubarToggled(e));
		}

E
Erich Gamma 已提交
1028
		// Add Workbench to DOM
B
Benjamin Pasero 已提交
1029
		this.container.appendChild(this.workbench);
E
Erich Gamma 已提交
1030 1031
	}

B
Benjamin Pasero 已提交
1032
	private createTitlebarPart(): void {
B
Benjamin Pasero 已提交
1033
		const titlebarContainer = this.createPart(Identifiers.TITLEBAR_PART, ['part', 'titlebar'], 'contentinfo');
B
Benjamin Pasero 已提交
1034

B
Benjamin Pasero 已提交
1035
		this.titlebarPart.create(titlebarContainer);
B
Benjamin Pasero 已提交
1036 1037
	}

E
Erich Gamma 已提交
1038
	private createActivityBarPart(): void {
B
Benjamin Pasero 已提交
1039
		const activitybarPartContainer = this.createPart(Identifiers.ACTIVITYBAR_PART, ['part', 'activitybar', this.sideBarPosition === Position.LEFT ? 'left' : 'right'], 'navigation');
E
Erich Gamma 已提交
1040

B
Benjamin Pasero 已提交
1041
		this.activitybarPart.create(activitybarPartContainer);
E
Erich Gamma 已提交
1042 1043 1044
	}

	private createSidebarPart(): void {
B
Benjamin Pasero 已提交
1045
		const sidebarPartContainer = this.createPart(Identifiers.SIDEBAR_PART, ['part', 'sidebar', this.sideBarPosition === Position.LEFT ? 'left' : 'right'], 'complementary');
E
Erich Gamma 已提交
1046

B
Benjamin Pasero 已提交
1047
		this.sidebarPart.create(sidebarPartContainer);
E
Erich Gamma 已提交
1048 1049
	}

I
isidor 已提交
1050
	private createPanelPart(): void {
B
Benjamin Pasero 已提交
1051
		const panelPartContainer = this.createPart(Identifiers.PANEL_PART, ['part', 'panel', this.panelPosition === Position.BOTTOM ? 'bottom' : 'right'], 'complementary');
I
isidor 已提交
1052

B
Benjamin Pasero 已提交
1053
		this.panelPart.create(panelPartContainer);
I
isidor 已提交
1054 1055
	}

E
Erich Gamma 已提交
1056
	private createEditorPart(): void {
B
Benjamin Pasero 已提交
1057
		const editorContainer = this.createPart(Identifiers.EDITOR_PART, ['part', 'editor'], 'main');
E
Erich Gamma 已提交
1058

B
Benjamin Pasero 已提交
1059
		this.editorPart.create(editorContainer);
E
Erich Gamma 已提交
1060 1061 1062
	}

	private createStatusbarPart(): void {
B
Benjamin Pasero 已提交
1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073
		const statusbarContainer = this.createPart(Identifiers.STATUSBAR_PART, ['part', 'statusbar'], 'contentinfo');

		this.statusbarPart.create(statusbarContainer);
	}

	private createPart(id: string, classes: string[], role: string): HTMLElement {
		const part = document.createElement('div');
		classes.forEach(clazz => DOM.addClass(part, clazz));
		part.id = id;
		part.setAttribute('role', role);

S
SteVen Batten 已提交
1074 1075 1076
		// Insert all workbench parts at the beginning. Issue #52531
		// This is primarily for the title bar to allow overriding -webkit-app-region
		this.workbench.insertBefore(part, this.workbench.lastChild);
E
Erich Gamma 已提交
1077

B
Benjamin Pasero 已提交
1078
		return part;
E
Erich Gamma 已提交
1079 1080
	}

1081 1082
	private createNotificationsHandlers(): void {

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

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

1089
		// Notifications Alerts
1090
		this._register(this.instantiationService.createInstance(NotificationsAlerts, this.notificationService.model));
1091 1092 1093 1094

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

1095
		// Eventing
1096
		this._register(this.notificationsCenter.onDidChangeVisibility(() => {
1097 1098 1099 1100 1101 1102 1103 1104

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

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

1105
		// Register Commands
1106
		registerNotificationCommands(this.notificationsCenter, this.notificationsToasts);
1107 1108
	}

1109
	getInstantiationService(): IInstantiationService {
E
Erich Gamma 已提交
1110 1111 1112
		return this.instantiationService;
	}

1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137
	dispose(reason = ShutdownReason.QUIT): void {
		super.dispose();

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

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

		this.workbenchShutdown = true;
	}

	//#region IPartService

B
Benjamin Pasero 已提交
1138
	private _onTitleBarVisibilityChange: Emitter<void> = this._register(new Emitter<void>());
1139
	get onTitleBarVisibilityChange(): Event<void> { return this._onTitleBarVisibilityChange.event; }
1140

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

1143
	isCreated(): boolean {
1144
		return !!(this.workbenchCreated && this.workbenchStarted);
1145
	}
1146

1147 1148 1149 1150 1151
	hasFocus(part: Parts): boolean {
		const activeElement = document.activeElement;
		if (!activeElement) {
			return false;
		}
1152

1153 1154 1155
		const container = this.getContainer(part);
		return DOM.isAncestor(activeElement, container);
	}
1156

1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178
	getContainer(part: Parts): HTMLElement {
		let container: HTMLElement = null;
		switch (part) {
			case Parts.TITLEBAR_PART:
				container = this.titlebarPart.getContainer();
				break;
			case Parts.ACTIVITYBAR_PART:
				container = this.activitybarPart.getContainer();
				break;
			case Parts.SIDEBAR_PART:
				container = this.sidebarPart.getContainer();
				break;
			case Parts.PANEL_PART:
				container = this.panelPart.getContainer();
				break;
			case Parts.EDITOR_PART:
				container = this.editorPart.getContainer();
				break;
			case Parts.STATUSBAR_PART:
				container = this.statusbarPart.getContainer();
				break;
		}
1179

1180 1181
		return container;
	}
1182

1183 1184 1185
	isVisible(part: Parts): boolean {
		switch (part) {
			case Parts.TITLEBAR_PART:
1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198
				if (this.getCustomTitleBarStyle() !== 'custom') {
					return false;
				} else if (!browser.isFullscreen()) {
					return true;
				} else if (isMacintosh) {
					return false;
				} else if (this.menubarVisibility === 'visible') {
					return true;
				} else if (this.menubarVisibility === 'toggle' || this.menubarVisibility === 'default') {
					return this.menubarToggled;
				}

				return false;
1199 1200 1201 1202 1203 1204 1205 1206
			case Parts.SIDEBAR_PART:
				return !this.sideBarHidden;
			case Parts.PANEL_PART:
				return !this.panelHidden;
			case Parts.STATUSBAR_PART:
				return !this.statusBarHidden;
			case Parts.ACTIVITYBAR_PART:
				return !this.activityBarHidden;
E
Erich Gamma 已提交
1207
		}
1208

1209
		return true; // any other part cannot be hidden
E
Erich Gamma 已提交
1210 1211
	}

1212 1213 1214
	getTitleBarOffset(): number {
		let offset = 0;
		if (this.isVisible(Parts.TITLEBAR_PART)) {
S
SteVen Batten 已提交
1215
			offset = this.workbenchLayout.partLayoutInfo.titlebar.height;
1216 1217 1218
			if (isMacintosh || this.menubarVisibility === 'hidden') {
				offset /= browser.getZoomFactor();
			}
E
Erich Gamma 已提交
1219
		}
1220 1221

		return offset;
E
Erich Gamma 已提交
1222
	}
1223

1224 1225
	getWorkbenchElement(): HTMLElement {
		return this.workbench;
1226
	}
1227

I
isidor 已提交
1228
	toggleZenMode(skipLayout?: boolean, restoring = false): void {
I
isidor 已提交
1229
		this.zenMode.active = !this.zenMode.active;
1230
		this.zenMode.transitionDisposeables = dispose(this.zenMode.transitionDisposeables);
1231

1232 1233
		// Check if zen mode transitioned to full screen and if now we are out of zen mode
		// -> we need to go out of full screen (same goes for the centered editor layout)
1234
		let toggleFullScreen = false;
1235 1236

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

I
isidor 已提交
1240
			toggleFullScreen = !browser.isFullscreen() && config.fullScreen;
I
isidor 已提交
1241
			this.zenMode.transitionedToFullScreen = restoring ? config.fullScreen : toggleFullScreen;
1242
			this.zenMode.transitionedToCenteredEditorLayout = !this.isEditorLayoutCentered() && config.centerLayout;
1243 1244
			this.zenMode.wasSideBarVisible = this.isVisible(Parts.SIDEBAR_PART);
			this.zenMode.wasPanelVisible = this.isVisible(Parts.PANEL_PART);
1245

1246 1247
			this.setPanelHidden(true, true);
			this.setSideBarHidden(true, true);
I
isidor 已提交
1248

1249 1250 1251
			if (config.hideActivityBar) {
				this.setActivityBarHidden(true, true);
			}
1252

I
isidor 已提交
1253
			if (config.hideStatusBar) {
I
isidor 已提交
1254 1255
				this.setStatusBarHidden(true, true);
			}
1256

1257 1258
			if (config.hideTabs && this.editorPart.partOptions.showTabs) {
				this.zenMode.transitionDisposeables.push(this.editorPart.enforcePartOptions({ showTabs: false }));
I
isidor 已提交
1259
			}
1260 1261 1262 1263

			if (config.centerLayout) {
				this.centerEditorLayout(true, true);
			}
1264 1265 1266 1267
		}

		// Zen Mode Inactive
		else {
1268
			if (this.zenMode.wasPanelVisible) {
1269
				this.setPanelHidden(false, true);
1270
			}
1271

1272
			if (this.zenMode.wasSideBarVisible) {
1273
				this.setSideBarHidden(false, true);
1274
			}
1275

1276 1277 1278
			if (this.zenMode.transitionedToCenteredEditorLayout) {
				this.centerEditorLayout(false, true);
			}
1279

1280 1281
			// Status bar and activity bar visibility come from settings -> update their visibility.
			this.onDidUpdateConfiguration(true);
1282

B
Benjamin Pasero 已提交
1283
			this.editorGroupService.activeGroup.focus();
1284

1285
			toggleFullScreen = this.zenMode.transitionedToFullScreen && browser.isFullscreen();
I
isidor 已提交
1286
		}
1287

1288
		this.inZenMode.set(this.zenMode.active);
I
isidor 已提交
1289

I
isidor 已提交
1290
		if (!skipLayout) {
1291
			this.layout();
I
isidor 已提交
1292
		}
1293

1294
		if (toggleFullScreen) {
1295
			this.windowService.toggleFullScreen();
1296
		}
I
isidor 已提交
1297 1298
	}

1299
	layout(options?: ILayoutOptions): void {
J
Joao Moreno 已提交
1300 1301
		this.contextViewService.layout();

1302 1303 1304 1305 1306
		if (this.workbenchStarted && !this.workbenchShutdown) {
			this.workbenchLayout.layout(options);
		}
	}

1307
	isEditorLayoutCentered(): boolean {
I
isidor 已提交
1308
		return this.editorPart.isLayoutCentered();
S
SrTobi 已提交
1309 1310
	}

1311
	centerEditorLayout(active: boolean, skipLayout?: boolean): void {
I
isidor 已提交
1312
		this.storageService.store(Workbench.centeredEditorLayoutActiveStorageKey, active, StorageScope.WORKSPACE);
B
Benjamin Pasero 已提交
1313

1314
		// Enter Centered Editor Layout
I
isidor 已提交
1315
		this.editorPart.centerLayout(active);
1316

1317 1318 1319
		if (!skipLayout) {
			this.layout();
		}
S
SrTobi 已提交
1320 1321
	}

1322
	resizePart(part: Parts, sizeChange: number): void {
1323 1324 1325 1326 1327 1328 1329
		switch (part) {
			case Parts.SIDEBAR_PART:
			case Parts.PANEL_PART:
			case Parts.EDITOR_PART:
				this.workbenchLayout.resizePart(part, sizeChange);
				break;
			default:
B
Benjamin Pasero 已提交
1330
				return; // Cannot resize other parts
1331 1332 1333
		}
	}

1334 1335
	setActivityBarHidden(hidden: boolean, skipLayout?: boolean): void {
		this.activityBarHidden = hidden;
1336

1337 1338 1339
		// Layout
		if (!skipLayout) {
			this.workbenchLayout.layout();
1340
		}
1341
	}
1342

1343 1344 1345 1346 1347 1348
	setSideBarHidden(hidden: boolean, skipLayout?: boolean): TPromise<void> {
		this.sideBarHidden = hidden;
		this.sideBarVisibleContext.set(!hidden);

		// Adjust CSS
		if (hidden) {
B
Benjamin Pasero 已提交
1349
			DOM.addClass(this.workbench, 'nosidebar');
1350
		} else {
B
Benjamin Pasero 已提交
1351
			DOM.removeClass(this.workbench, 'nosidebar');
1352 1353
		}

1354 1355 1356 1357 1358 1359 1360 1361 1362
		// If sidebar becomes hidden, also hide the current active Viewlet if any
		let promise = TPromise.wrap<any>(null);
		if (hidden && this.sidebarPart.getActiveViewlet()) {
			promise = this.sidebarPart.hideActiveViewlet().then(() => {
				const activePanel = this.panelPart.getActivePanel();

				// Pass Focus to Editor or Panel if Sidebar is now hidden
				if (this.hasFocus(Parts.PANEL_PART) && activePanel) {
					activePanel.focus();
B
Benjamin Pasero 已提交
1363 1364
				} else {
					this.editorGroupService.activeGroup.focus();
1365 1366 1367 1368 1369 1370 1371 1372
				}
			});
		}

		// If sidebar becomes visible, show last active Viewlet or default viewlet
		else if (!hidden && !this.sidebarPart.getActiveViewlet()) {
			const viewletToOpen = this.sidebarPart.getLastActiveViewletId();
			if (viewletToOpen) {
1373 1374
				promise = this.viewletService.openViewlet(viewletToOpen, true)
					.then(viewlet => viewlet || this.viewletService.openViewlet(this.viewletService.getDefaultViewletId(), true));
1375
			}
1376 1377
		}

1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392
		return promise.then(() => {

			// Remember in settings
			const defaultHidden = this.contextService.getWorkbenchState() === WorkbenchState.EMPTY;
			if (hidden !== defaultHidden) {
				this.storageService.store(Workbench.sidebarHiddenStorageKey, hidden ? 'true' : 'false', StorageScope.WORKSPACE);
			} else {
				this.storageService.remove(Workbench.sidebarHiddenStorageKey, StorageScope.WORKSPACE);
			}

			// Layout
			if (!skipLayout) {
				this.workbenchLayout.layout();
			}
		});
1393
	}
1394 1395 1396 1397 1398 1399

	setPanelHidden(hidden: boolean, skipLayout?: boolean): TPromise<void> {
		this.panelHidden = hidden;

		// Adjust CSS
		if (hidden) {
B
Benjamin Pasero 已提交
1400
			DOM.addClass(this.workbench, 'nopanel');
1401
		} else {
B
Benjamin Pasero 已提交
1402
			DOM.removeClass(this.workbench, 'nopanel');
1403 1404 1405 1406 1407 1408
		}

		// If panel part becomes hidden, also hide the current active panel if any
		let promise = TPromise.wrap<any>(null);
		if (hidden && this.panelPart.getActivePanel()) {
			promise = this.panelPart.hideActivePanel().then(() => {
B
Benjamin Pasero 已提交
1409
				this.editorGroupService.activeGroup.focus(); // Pass focus to editor group if panel part is now hidden
1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450
			});
		}

		// If panel part becomes visible, show last active panel or default panel
		else if (!hidden && !this.panelPart.getActivePanel()) {
			const panelToOpen = this.panelPart.getLastActivePanelId();
			if (panelToOpen) {
				promise = this.panelPart.openPanel(panelToOpen, true);
			}
		}

		return promise.then(() => {

			// Remember in settings
			if (!hidden) {
				this.storageService.store(Workbench.panelHiddenStorageKey, 'false', StorageScope.WORKSPACE);
			} else {
				this.storageService.remove(Workbench.panelHiddenStorageKey, StorageScope.WORKSPACE);
			}

			// Layout
			if (!skipLayout) {
				this.workbenchLayout.layout();
			}
		});
	}

	toggleMaximizedPanel(): void {
		this.workbenchLayout.layout({ toggleMaximizedPanel: true, source: Parts.PANEL_PART });
	}

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

	getSideBarPosition(): Position {
		return this.sideBarPosition;
	}

	setSideBarPosition(position: Position): void {
		if (this.sideBarHidden) {
1451
			this.setSideBarHidden(false, true /* Skip Layout */);
1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471
		}

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

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

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

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

S
SteVen Batten 已提交
1472
	setMenubarVisibility(visibility: MenuBarVisibility, skipLayout: boolean): void {
S
SteVen Batten 已提交
1473 1474
		if (this.menubarVisibility !== visibility) {
			this.menubarVisibility = visibility;
1475

S
SteVen Batten 已提交
1476 1477 1478
			if (!skipLayout) {
				this.workbenchLayout.layout();
			}
1479 1480 1481
		}
	}

S
SteVen Batten 已提交
1482 1483 1484 1485
	getMenubarVisibility(): MenuBarVisibility {
		return this.menubarVisibility;
	}

1486 1487 1488 1489 1490 1491 1492 1493 1494
	getPanelPosition(): Position {
		return this.panelPosition;
	}

	setPanelPosition(position: Position): TPromise<void> {
		return (this.panelHidden ? this.setPanelHidden(false, true /* Skip Layout */) : TPromise.as(undefined)).then(() => {
			const newPositionValue = (position === Position.BOTTOM) ? 'bottom' : 'right';
			const oldPositionValue = (this.panelPosition === Position.BOTTOM) ? 'bottom' : 'right';
			this.panelPosition = position;
A
Alex Dima 已提交
1495
			this.storageService.store(Workbench.panelPositionStorageKey, PositionToString(this.panelPosition).toLowerCase(), StorageScope.WORKSPACE);
1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506

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

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

			// Layout
			this.workbenchLayout.layout();
		});
1507
	}
1508 1509

	//#endregion
I
isidor 已提交
1510
}