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

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

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

135 136 137
export interface IWorkbenchStartedInfo {
	customKeybindingsCount: number;
	pinnedViewlets: string[];
138
	restoredViewlet: string;
139
	restoredEditorsCount: number;
140 141
}

142 143
type FontAliasingOption = 'default' | 'antialiased' | 'none' | 'auto';

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

146 147
type WorkbenchView = StatusbarPart | TitlebarPart | SidebarPart | EditorPart | ActivitybarPart | PanelPart;

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

J
Joao Moreno 已提交
158 159 160 161 162 163 164 165
function getWorkbenchStateString(state: WorkbenchState): string {
	switch (state) {
		case WorkbenchState.EMPTY: return 'empty';
		case WorkbenchState.FOLDER: return 'folder';
		case WorkbenchState.WORKSPACE: return 'workspace';
	}
}

166 167 168 169 170 171 172 173 174
interface IZenMode {
	active: boolean;
	transitionedToFullScreen: boolean;
	transitionedToCenteredEditorLayout: boolean;
	transitionDisposeables: IDisposable[];
	wasSideBarVisible: boolean;
	wasPanelVisible: boolean;
}

175 176 177 178 179 180
interface IWorkbenchUIState {
	lastPanelHeight?: number;
	lastPanelWidth?: number;
	lastSidebarDimension?: number;
}

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

183
	private static readonly workbenchGridUIStateStorageKey = 'workbench.layout.state';
184
	private static readonly sidebarHiddenStorageKey = 'workbench.sidebar.hidden';
185
	private static readonly menubarVisibilityConfigurationKey = 'window.menuBarVisibility';
186 187
	private static readonly panelHiddenStorageKey = 'workbench.panel.hidden';
	private static readonly zenModeActiveStorageKey = 'workbench.zenmode.active';
188
	private static readonly centeredEditorLayoutActiveStorageKey = 'workbench.centerededitorlayout.active';
189
	private static readonly panelPositionStorageKey = 'workbench.panel.location';
190
	private static readonly defaultPanelPositionStorageKey = 'workbench.panel.defaultLocation';
191 192 193 194 195
	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';
196

197
	_serviceBrand: any;
198

E
Erich Gamma 已提交
199
	private workbenchParams: WorkbenchParams;
B
Benjamin Pasero 已提交
200
	private workbench: HTMLElement;
E
Erich Gamma 已提交
201
	private workbenchStarted: boolean;
B
Benjamin Pasero 已提交
202
	private workbenchRestored: boolean;
E
Erich Gamma 已提交
203
	private workbenchShutdown: boolean;
204

205 206
	private editorService: EditorService;
	private editorGroupService: IEditorGroupsService;
J
Joao Moreno 已提交
207
	private contextViewService: ContextViewService;
208
	private contextKeyService: IContextKeyService;
209
	private keybindingService: IKeybindingService;
210
	private backupFileService: IBackupFileService;
211
	private fileService: IFileService;
212 213
	private quickInput: QuickInputService;

214
	private workbenchGrid: SerializableGrid<WorkbenchView> | WorkbenchLayout;
215

B
Benjamin Pasero 已提交
216
	private titlebarPart: TitlebarPart;
E
Erich Gamma 已提交
217 218
	private activitybarPart: ActivitybarPart;
	private sidebarPart: SidebarPart;
I
isidor 已提交
219
	private panelPart: PanelPart;
E
Erich Gamma 已提交
220 221 222
	private editorPart: EditorPart;
	private statusbarPart: StatusbarPart;
	private quickOpen: QuickOpenController;
223
	private notificationsCenter: NotificationsCenter;
224
	private notificationsToasts: NotificationsToasts;
225

E
Erich Gamma 已提交
226
	private sideBarHidden: boolean;
227
	private statusBarHidden: boolean;
S
Sanders Lauture 已提交
228
	private activityBarHidden: boolean;
229
	private menubarToggled: boolean;
E
Erich Gamma 已提交
230
	private sideBarPosition: Position;
I
isidor 已提交
231
	private panelPosition: Position;
I
isidor 已提交
232
	private panelHidden: boolean;
S
SteVen Batten 已提交
233
	private menubarVisibility: MenuBarVisibility;
234 235
	private zenMode: IZenMode;
	private fontAliasing: FontAliasingOption;
236
	private hasInitialFilesToOpen: boolean;
237
	private shouldCenterLayout = false;
238 239 240 241 242
	private uiState: IWorkbenchUIState = {
		lastPanelHeight: 350,
		lastPanelWidth: 350,
		lastSidebarDimension: 300,
	};
243

I
isidor 已提交
244
	private inZenMode: IContextKey<boolean>;
245
	private sideBarVisibleContext: IContextKey<boolean>;
246

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

249
	constructor(
250
		private container: HTMLElement,
J
Joao Moreno 已提交
251
		private configuration: IWindowConfiguration,
252
		serviceCollection: ServiceCollection,
253
		private lifecycleService: LifecycleService,
J
Joao Moreno 已提交
254
		private mainProcessClient: IPCClient,
255 256 257 258 259 260 261 262
		@IInstantiationService private readonly instantiationService: IInstantiationService,
		@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
		@IStorageService private readonly storageService: IStorageService,
		@IConfigurationService private readonly configurationService: WorkspaceService,
		@IWorkbenchThemeService private readonly themeService: WorkbenchThemeService,
		@IEnvironmentService private readonly environmentService: IEnvironmentService,
		@IWindowService private readonly windowService: IWindowService,
		@INotificationService private readonly notificationService: NotificationService
263
	) {
264
		super();
E
Erich Gamma 已提交
265

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

268
		this.hasInitialFilesToOpen =
B
Benjamin Pasero 已提交
269 270 271
			(configuration.filesToCreate && configuration.filesToCreate.length > 0) ||
			(configuration.filesToOpen && configuration.filesToOpen.length > 0) ||
			(configuration.filesToDiff && configuration.filesToDiff.length > 0);
272 273
	}

J
Johannes Rieken 已提交
274
	startup(): Promise<IWorkbenchStartedInfo> {
275
		this.workbenchStarted = true;
E
Erich Gamma 已提交
276

B
Benjamin Pasero 已提交
277
		// Create Workbench Container
278
		this.createWorkbench();
E
Erich Gamma 已提交
279

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

283 284
		// Services
		this.initServices();
E
Erich Gamma 已提交
285

286 287
		// Context Keys
		this.handleContextKeys();
J
Joao Moreno 已提交
288

289 290
		// Register Listeners
		this.registerListeners();
E
Erich Gamma 已提交
291

292 293
		// Settings
		this.initSettings();
E
Erich Gamma 已提交
294

295 296
		// Create Workbench and Parts
		this.renderWorkbench();
297

298 299
		// Workbench Layout
		this.createWorkbenchLayout();
B
polish  
Benjamin Pasero 已提交
300

J
Joao Moreno 已提交
301 302
		// Driver
		if (this.environmentService.driverHandle) {
303
			registerWindowDriver(this.mainProcessClient, this.configuration.windowId, this.instantiationService).then(disposable => this._register(disposable));
J
Joao Moreno 已提交
304 305
		}

306
		// Restore Parts
B
Benjamin Pasero 已提交
307 308
		return this.restoreParts();
	}
309

B
Benjamin Pasero 已提交
310
	private createWorkbench(): void {
B
Benjamin Pasero 已提交
311 312
		this.workbench = document.createElement('div');
		this.workbench.id = Identifiers.WORKBENCH_CONTAINER;
313
		DOM.addClass(this.workbench, 'monaco-workbench');
S
SteVen Batten 已提交
314

B
Benjamin Pasero 已提交
315 316 317
		this._register(DOM.addDisposableListener(this.workbench, DOM.EventType.SCROLL, () => {
			this.workbench.scrollTop = 0; // Prevent workbench from scrolling #55456
		}));
318
	}
E
Erich Gamma 已提交
319

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

B
Benjamin Pasero 已提交
323
		// Actions registered here to adjust for developing vs built workbench
324
		const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
R
Rob Lourens 已提交
325 326
		registry.registerWorkbenchAction(new SyncActionDescriptor(ReloadWindowAction, ReloadWindowAction.ID, ReloadWindowAction.LABEL, isDeveloping ? { primary: KeyMod.CtrlCmd | KeyCode.KEY_R } : undefined), '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 } } : undefined), 'Developer: Toggle Developer Tools', localize('developer', "Developer"));
327 328
		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');
329
		registry.registerWorkbenchAction(new SyncActionDescriptor(LogStorageAction, LogStorageAction.ID, LogStorageAction.LABEL), 'Developer: Log Storage', localize('developer', "Developer"));
330

331
		// Actions for macOS native tabs management (only when enabled)
332
		const windowConfig = this.configurationService.getValue<IWindowConfiguration>();
333
		if (windowConfig && windowConfig.window && windowConfig.window.nativeTabs) {
334
			registry.registerWorkbenchAction(new SyncActionDescriptor(NewWindowTab, NewWindowTab.ID, NewWindowTab.LABEL), 'New Window Tab');
335 336 337 338 339
			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');
340
		}
341 342
	}

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

E
Erich Gamma 已提交
346
		// Services we contribute
347
		serviceCollection.set(IPartService, this);
E
Erich Gamma 已提交
348

349
		// Clipboard
J
Johannes Rieken 已提交
350
		serviceCollection.set(IClipboardService, new SyncDescriptor(ClipboardService));
351

352 353 354 355
		// Status bar
		this.statusbarPart = this.instantiationService.createInstance(StatusbarPart, Identifiers.STATUSBAR_PART);
		serviceCollection.set(IStatusbarService, this.statusbarPart);

356 357 358
		// Progress 2
		serviceCollection.set(IProgressService2, new SyncDescriptor(ProgressService2));

359
		// Keybindings
A
Alex Dima 已提交
360
		this.contextKeyService = this.instantiationService.createInstance(ContextKeyService);
361
		serviceCollection.set(IContextKeyService, this.contextKeyService);
362

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

366 367 368
		// List
		serviceCollection.set(IListService, this.instantiationService.createInstance(ListService));

J
Joao Moreno 已提交
369
		// Context view service
B
Benjamin Pasero 已提交
370
		this.contextViewService = this.instantiationService.createInstance(ContextViewService, this.workbench);
J
Joao Moreno 已提交
371 372
		serviceCollection.set(IContextViewService, this.contextViewService);

S
SteVen Batten 已提交
373
		// Use themable context menus when custom titlebar is enabled to match custom menubar
B
Benjamin Pasero 已提交
374
		if (!isMacintosh && this.useCustomTitleBarStyle()) {
J
fix npe  
Johannes Rieken 已提交
375
			serviceCollection.set(IContextMenuService, new SyncDescriptor(HTMLContextMenuService, [null]));
S
SteVen Batten 已提交
376 377 378
		} else {
			serviceCollection.set(IContextMenuService, new SyncDescriptor(NativeContextMenuService));
		}
379

380 381
		// Menus/Actions
		serviceCollection.set(IMenuService, new SyncDescriptor(MenuService));
382

P
Pine Wu 已提交
383
		// Sidebar part
384
		this.sidebarPart = this.instantiationService.createInstance(SidebarPart, Identifiers.SIDEBAR_PART);
P
Pine Wu 已提交
385 386

		// Viewlet service
I
isidor 已提交
387
		serviceCollection.set(IViewletService, this.sidebarPart);
E
Erich Gamma 已提交
388

I
isidor 已提交
389
		// Panel service (panel part)
390 391
		this.panelPart = this.instantiationService.createInstance(PanelPart, Identifiers.PANEL_PART);
		serviceCollection.set(IPanelService, this.panelPart);
I
isidor 已提交
392

393 394 395
		// views service
		const viewsService = this.instantiationService.createInstance(ViewsService);
		serviceCollection.set(IViewsService, viewsService);
S
Sandeep Somavarapu 已提交
396

E
Erich Gamma 已提交
397
		// Activity service (activitybar part)
398
		this.activitybarPart = this.instantiationService.createInstance(ActivitybarPart, Identifiers.ACTIVITYBAR_PART);
I
isidor 已提交
399 400
		const activityService = this.instantiationService.createInstance(ActivityService, this.activitybarPart, this.panelPart);
		serviceCollection.set(IActivityService, activityService);
E
Erich Gamma 已提交
401

402 403 404
		// File Service
		this.fileService = this.instantiationService.createInstance(RemoteFileService);
		serviceCollection.set(IFileService, this.fileService);
S
#47154  
Sandeep Somavarapu 已提交
405
		this.configurationService.acquireFileService(this.fileService);
A
Alex Dima 已提交
406
		this.themeService.acquireFileService(this.fileService);
407

408 409
		// Editor and Group services
		const restorePreviousEditorState = !this.hasInitialFilesToOpen;
410
		this.editorPart = this.instantiationService.createInstance(EditorPart, Identifiers.EDITOR_PART, restorePreviousEditorState);
B
Benjamin Pasero 已提交
411
		this.editorGroupService = this.editorPart;
412 413 414
		serviceCollection.set(IEditorGroupsService, this.editorPart);
		this.editorService = this.instantiationService.createInstance(EditorService);
		serviceCollection.set(IEditorService, this.editorService);
E
Erich Gamma 已提交
415

416 417 418
		// Title bar
		this.titlebarPart = this.instantiationService.createInstance(TitlebarPart, Identifiers.TITLEBAR_PART);
		serviceCollection.set(ITitleService, this.titlebarPart);
B
Benjamin Pasero 已提交
419

420
		// History
421
		serviceCollection.set(IHistoryService, new SyncDescriptor(HistoryService));
422

M
Martin Aeschlimann 已提交
423 424 425
		// File Dialogs
		serviceCollection.set(IFileDialogService, new SyncDescriptor(FileDialogService));

426
		// Backup File Service
B
Benjamin Pasero 已提交
427 428 429 430 431
		if (this.workbenchParams.configuration.backupPath) {
			this.backupFileService = this.instantiationService.createInstance(BackupFileService, this.workbenchParams.configuration.backupPath);
		} else {
			this.backupFileService = new InMemoryBackupFileService();
		}
432
		serviceCollection.set(IBackupFileService, this.backupFileService);
433

434
		// Text File Service
435
		serviceCollection.set(ITextFileService, new SyncDescriptor(TextFileService));
436

437
		// File Decorations
J
Johannes Rieken 已提交
438
		serviceCollection.set(IDecorationsService, new SyncDescriptor(FileDecorationsService));
439

J
Joao Moreno 已提交
440
		// SCM Service
441
		serviceCollection.set(ISCMService, new SyncDescriptor(SCMService));
442

J
Joao Moreno 已提交
443
		// Inactive extension URL handler
J
Joao Moreno 已提交
444
		serviceCollection.set(IExtensionUrlHandler, new SyncDescriptor(ExtensionUrlHandler));
J
Joao Moreno 已提交
445

B
Benjamin Pasero 已提交
446
		// Text Model Resolver Service
447
		serviceCollection.set(ITextModelService, new SyncDescriptor(TextModelResolverService));
B
Benjamin Pasero 已提交
448

449 450 451 452
		// JSON Editing
		const jsonEditingService = this.instantiationService.createInstance(JSONEditingService);
		serviceCollection.set(IJSONEditingService, jsonEditingService);

453 454 455
		// Workspace Editing
		serviceCollection.set(IWorkspaceEditingService, new SyncDescriptor(WorkspaceEditingService));

456 457 458
		// Keybinding Editing
		serviceCollection.set(IKeybindingEditingService, this.instantiationService.createInstance(KeybindingsEditingService));

459
		// Configuration Resolver
460
		serviceCollection.set(IConfigurationResolverService, new SyncDescriptor(ConfigurationResolverService, [process.env]));
461

E
Erich Gamma 已提交
462
		// Quick open service (quick open controller)
463 464
		this.quickOpen = this.instantiationService.createInstance(QuickOpenController);
		serviceCollection.set(IQuickOpenService, this.quickOpen);
465

C
Christof Marti 已提交
466 467 468 469
		// Quick input service
		this.quickInput = this.instantiationService.createInstance(QuickInputService);
		serviceCollection.set(IQuickInputService, this.quickInput);

S
Sandeep Somavarapu 已提交
470 471 472
		// PreferencesService
		serviceCollection.set(IPreferencesService, this.instantiationService.createInstance(PreferencesService));

B
polish  
Benjamin Pasero 已提交
473
		// Contributed services
B
Benjamin Pasero 已提交
474
		const contributedServices = getServices();
E
Erich Gamma 已提交
475
		for (let contributedService of contributedServices) {
476
			serviceCollection.set(contributedService.id, contributedService.descriptor);
E
Erich Gamma 已提交
477 478 479
		}

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

484
		this.instantiationService.createInstance(DefaultConfigurationExportHelper);
485

S
#47154  
Sandeep Somavarapu 已提交
486
		this.configurationService.acquireInstantiationService(this.getInstantiationService());
E
Erich Gamma 已提交
487 488
	}

489
	//#region event handling
E
Erich Gamma 已提交
490

491
	private registerListeners(): void {
I
isidor 已提交
492

493
		// Storage
494
		this._register(this.storageService.onWillSaveState(e => this.saveState(e)));
495

496
		// Listen to visible editor changes
497
		this._register(this.editorService.onDidVisibleEditorsChange(() => this.onDidVisibleEditorsChange()));
B
Benjamin Pasero 已提交
498

499 500 501
		// Listen to editor closing (if we run with --wait)
		const filesToWait = this.workbenchParams.configuration.filesToWait;
		if (filesToWait) {
502
			const resourcesToWaitFor = filesToWait.paths.map(p => p.fileUri);
503
			const waitMarkerFile = URI.file(filesToWait.waitMarkerFilePath);
504
			const listenerDispose = this.editorService.onDidCloseEditor(() => this.onEditorClosed(listenerDispose, resourcesToWaitFor, waitMarkerFile));
I
isidor 已提交
505

506
			this._register(listenerDispose);
507
		}
S
Sanders Lauture 已提交
508

509
		// Configuration changes
510
		this._register(this.configurationService.onDidChangeConfiguration(() => this.onDidUpdateConfiguration()));
I
isidor 已提交
511

512
		// Fullscreen changes
513
		this._register(browser.onDidChangeFullscreen(() => this.onFullscreenChanged()));
B
Benjamin Pasero 已提交
514 515 516 517

		// Group changes
		this._register(this.editorGroupService.onDidAddGroup(() => this.centerEditorLayout(this.shouldCenterLayout)));
		this._register(this.editorGroupService.onDidRemoveGroup(() => this.centerEditorLayout(this.shouldCenterLayout)));
518
	}
519

520
	private onFullscreenChanged(): void {
S
SrTobi 已提交
521

522 523 524
		// Apply as CSS class
		const isFullscreen = browser.isFullscreen();
		if (isFullscreen) {
B
Benjamin Pasero 已提交
525
			DOM.addClass(this.workbench, 'fullscreen');
526
		} else {
B
Benjamin Pasero 已提交
527 528
			DOM.removeClass(this.workbench, 'fullscreen');

529 530 531 532
			if (this.zenMode.transitionedToFullScreen && this.zenMode.active) {
				this.toggleZenMode();
			}
		}
E
Erich Gamma 已提交
533

534
		// Changing fullscreen state of the window has an impact on custom title bar visibility, so we need to update
B
Benjamin Pasero 已提交
535
		if (this.useCustomTitleBarStyle()) {
536 537 538
			this._onTitleBarVisibilityChange.fire();
			this.layout(); // handle title bar when fullscreen changes
		}
539 540
	}

541 542 543 544
	private onMenubarToggled(visible: boolean) {
		if (visible !== this.menubarToggled) {
			this.menubarToggled = visible;

545 546
			if (browser.isFullscreen() && (this.menubarVisibility === 'toggle' || this.menubarVisibility === 'default')) {
				this._onTitleBarVisibilityChange.fire();
547 548 549 550 551
				this.layout();
			}
		}
	}

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

554 555 556
		// 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.
557
		if (resourcesToWaitFor.every(resource => !this.editorService.isOpen({ resource }))) {
558
			listenerDispose.dispose();
559
			this.fileService.del(waitMarkerFile);
560
		}
E
Erich Gamma 已提交
561 562
	}

563
	private onDidVisibleEditorsChange(): void {
564
		const visibleEditors = this.editorService.visibleControls;
E
Erich Gamma 已提交
565

566 567 568 569 570 571 572 573 574
		// 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();
			}
		}
575 576
	}

577
	private onAllEditorsClosed(): void {
578
		const visibleEditors = this.editorService.visibleControls.length;
579 580
		if (visibleEditors === 0) {
			this.windowService.closeWindow();
E
Erich Gamma 已提交
581 582 583
		}
	}

584 585 586 587 588
	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);
589
		}
E
Erich Gamma 已提交
590

591
		this.setPanelPositionFromStorageOrConfig();
E
Erich Gamma 已提交
592

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

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

604 605 606 607
			const newActivityBarHiddenValue = !this.configurationService.getValue<boolean>(Workbench.activityBarVisibleConfigurationKey);
			if (newActivityBarHiddenValue !== this.activityBarHidden) {
				this.setActivityBarHidden(newActivityBarHiddenValue, skipLayout);
			}
B
Benjamin Pasero 已提交
608
		}
S
SteVen Batten 已提交
609

610
		const newMenubarVisibility = this.configurationService.getValue<MenuBarVisibility>(Workbench.menubarVisibilityConfigurationKey);
S
SteVen Batten 已提交
611
		this.setMenubarVisibility(newMenubarVisibility, skipLayout);
612
	}
B
Benjamin Pasero 已提交
613

614
	//#endregion
B
Benjamin Pasero 已提交
615

616 617
	private handleContextKeys(): void {
		this.inZenMode = InEditorZenModeContext.bindTo(this.contextKeyService);
618

I
isidor 已提交
619 620 621
		IsMacContext.bindTo(this.contextKeyService);
		IsLinuxContext.bindTo(this.contextKeyService);
		IsWindowsContext.bindTo(this.contextKeyService);
622

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

626
		const activeEditorContext = ActiveEditorContext.bindTo(this.contextKeyService);
627 628
		const editorsVisibleContext = EditorsVisibleContext.bindTo(this.contextKeyService);
		const textCompareEditorVisible = TextCompareEditorVisibleContext.bindTo(this.contextKeyService);
629
		const textCompareEditorActive = TextCompareEditorActiveContext.bindTo(this.contextKeyService);
630 631
		const activeEditorGroupEmpty = ActiveEditorGroupEmptyContext.bindTo(this.contextKeyService);
		const multipleEditorGroups = MultipleEditorGroupsContext.bindTo(this.contextKeyService);
632

633
		const updateEditorContextKeys = () => {
634
			const activeControl = this.editorService.activeControl;
635
			const visibleEditors = this.editorService.visibleControls;
E
Erich Gamma 已提交
636

637
			textCompareEditorActive.set(activeControl && activeControl.getId() === TEXT_DIFF_EDITOR_ID);
638
			textCompareEditorVisible.set(visibleEditors.some(control => control.getId() === TEXT_DIFF_EDITOR_ID));
I
isidor 已提交
639

640 641 642 643
			if (visibleEditors.length > 0) {
				editorsVisibleContext.set(true);
			} else {
				editorsVisibleContext.reset();
644
			}
B
Benjamin Pasero 已提交
645

646
			if (!this.editorService.activeEditor) {
647 648 649
				activeEditorGroupEmpty.set(true);
			} else {
				activeEditorGroupEmpty.reset();
650
			}
651

B
Benjamin Pasero 已提交
652
			if (this.editorGroupService.count > 1) {
653 654 655 656
				multipleEditorGroups.set(true);
			} else {
				multipleEditorGroups.reset();
			}
657 658 659 660 661 662

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

665
		this.editorPart.whenRestored.then(() => updateEditorContextKeys());
666 667
		this._register(this.editorService.onDidActiveEditorChange(() => updateEditorContextKeys()));
		this._register(this.editorService.onDidVisibleEditorsChange(() => updateEditorContextKeys()));
B
Benjamin Pasero 已提交
668 669
		this._register(this.editorGroupService.onDidAddGroup(() => updateEditorContextKeys()));
		this._register(this.editorGroupService.onDidRemoveGroup(() => updateEditorContextKeys()));
670

671
		const inputFocused = InputFocusedContext.bindTo(this.contextKeyService);
B
Benjamin Pasero 已提交
672 673 674 675 676 677 678 679 680 681 682

		function activeElementIsInput(): boolean {
			return document.activeElement && (document.activeElement.tagName === 'INPUT' || document.activeElement.tagName === 'TEXTAREA');
		}

		function trackInputFocus(): void {
			const isInputFocused = activeElementIsInput();
			inputFocused.set(isInputFocused);

			if (isInputFocused) {
				const tracker = DOM.trackFocus(document.activeElement as HTMLElement);
J
Joao Moreno 已提交
683
				Event.once(tracker.onDidBlur)(() => {
B
Benjamin Pasero 已提交
684 685 686 687 688 689 690 691
					inputFocused.set(activeElementIsInput());

					tracker.dispose();
				});
			}
		}

		this._register(DOM.addDisposableListener(window, 'focusin', () => trackInputFocus(), true));
692 693 694 695 696 697

		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 已提交
698

699 700 701 702 703
		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);
		}));
704

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

707 708 709 710
		const updateSplitEditorsVerticallyContext = () => {
			const direction = preferredSideBySideGroupDirection(this.configurationService);
			splitEditorsVerticallyContext.set(direction === GroupDirection.DOWN);
		};
S
Sanders Lauture 已提交
711

712 713 714 715 716
		this._register(this.configurationService.onDidChangeConfiguration(e => {
			if (e.affectsConfiguration('workbench.editor.openSideBySideDirection')) {
				updateSplitEditorsVerticallyContext();
			}
		}));
E
Erich Gamma 已提交
717

718
		updateSplitEditorsVerticallyContext();
719
	}
E
Erich Gamma 已提交
720

J
Johannes Rieken 已提交
721 722
	private restoreParts(): Promise<IWorkbenchStartedInfo> {
		const restorePromises: Promise<any>[] = [];
B
Benjamin Pasero 已提交
723

724 725
		// Restore Editorpart
		perf.mark('willRestoreEditors');
726
		restorePromises.push(this.editorPart.whenRestored.then(() => {
B
Benjamin Pasero 已提交
727 728 729 730

			function openEditors(editors: IResourceEditor[], editorService: IEditorService) {
				if (editors.length) {
					return editorService.openEditors(editors);
731
				}
E
Erich Gamma 已提交
732

B
Benjamin Pasero 已提交
733 734 735 736 737 738 739 740 741 742 743
				return Promise.resolve();
			}

			const editorsToOpen = this.resolveEditorsToOpen();

			if (Array.isArray(editorsToOpen)) {
				return openEditors(editorsToOpen, this.editorService);
			}

			return editorsToOpen.then(editors => openEditors(editors, this.editorService));
		}).then(() => perf.mark('didRestoreEditors')));
E
Erich Gamma 已提交
744

745 746 747 748
		// Restore Sidebar
		let viewletIdToRestore: string;
		if (!this.sideBarHidden) {
			this.sideBarVisibleContext.set(true);
749

750
			if (this.shouldRestoreLastOpenedViewlet()) {
751
				viewletIdToRestore = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE);
752
			}
753

754
			if (!viewletIdToRestore) {
I
isidor 已提交
755
				viewletIdToRestore = this.sidebarPart.getDefaultViewletId();
756
			}
E
Erich Gamma 已提交
757

758
			perf.mark('willRestoreViewlet');
I
isidor 已提交
759 760
			restorePromises.push(this.sidebarPart.openViewlet(viewletIdToRestore)
				.then(viewlet => viewlet || this.sidebarPart.openViewlet(this.sidebarPart.getDefaultViewletId()))
B
Benjamin Pasero 已提交
761
				.then(() => perf.mark('didRestoreViewlet')));
762 763
		}

764 765
		// Restore Panel
		const panelRegistry = Registry.as<PanelRegistry>(PanelExtensions.Panels);
766
		const panelId = this.storageService.get(PanelPart.activePanelSettingsKey, StorageScope.WORKSPACE, panelRegistry.getDefaultPanelId());
767
		if (!this.panelHidden && !!panelId) {
768
			perf.mark('willRestorePanel');
769
			const isPanelToRestoreEnabled = !!this.panelPart.getPanels().filter(p => p.id === panelId).length;
770
			const panelIdToRestore = isPanelToRestoreEnabled ? panelId : panelRegistry.getDefaultPanelId();
771 772
			this.panelPart.openPanel(panelIdToRestore, false);
			perf.mark('didRestorePanel');
I
isidor 已提交
773 774
		}

775 776 777
		// Restore Zen Mode if active and supported for restore on startup
		const zenConfig = this.configurationService.getValue<IZenModeSettings>('zenMode');
		const wasZenActive = this.storageService.getBoolean(Workbench.zenModeActiveStorageKey, StorageScope.WORKSPACE, false);
778
		if (wasZenActive && zenConfig.restore) {
I
isidor 已提交
779
			this.toggleZenMode(true, true);
I
isidor 已提交
780 781
		}

B
Benjamin Pasero 已提交
782
		// Restore Forced Editor Center Mode
783
		if (this.storageService.getBoolean(Workbench.centeredEditorLayoutActiveStorageKey, StorageScope.WORKSPACE, false)) {
I
isidor 已提交
784
			this.centerEditorLayout(true);
S
SrTobi 已提交
785
		}
786

787
		const onRestored = (error?: Error): IWorkbenchStartedInfo => {
B
Benjamin Pasero 已提交
788 789 790 791 792
			this.workbenchRestored = true;

			// Set lifecycle phase to `Restored`
			this.lifecycleService.phase = LifecyclePhase.Restored;

793 794 795 796 797 798 799
			// Set lifecycle phase to `Eventually` after a short delay and when
			// idle (min 2.5sec, max 5sec)
			setTimeout(() => {
				this._register(runWhenIdle(() => {
					this.lifecycleService.phase = LifecyclePhase.Eventually;
				}, 2500));
			}, 2500);
800

801 802
			if (error) {
				errors.onUnexpectedError(error);
803
			}
I
isidor 已提交
804

805 806
			return {
				customKeybindingsCount: this.keybindingService.customKeybindingsCount(),
P
Pine Wu 已提交
807
				pinnedViewlets: this.activitybarPart.getPinnedViewletIds(),
808
				restoredViewlet: viewletIdToRestore,
809
				restoredEditorsCount: this.editorService.visibleEditors.length
810 811
			};
		};
812

B
Benjamin Pasero 已提交
813
		return Promise.all(restorePromises).then(() => onRestored(), error => onRestored(error));
E
Erich Gamma 已提交
814 815
	}

816 817 818
	private shouldRestoreLastOpenedViewlet(): boolean {
		if (!this.environmentService.isBuilt) {
			return true; // always restore sidebar when we are in development mode
E
Erich Gamma 已提交
819 820
		}

821 822
		// always restore sidebar when the window was reloaded
		return this.lifecycleService.startupKind === StartupKind.ReloadedWindow;
E
Erich Gamma 已提交
823 824
	}

J
Johannes Rieken 已提交
825
	private resolveEditorsToOpen(): Promise<IResourceEditor[]> | IResourceEditor[] {
826
		const config = this.workbenchParams.configuration;
I
isidor 已提交
827

B
Benjamin Pasero 已提交
828
		// Files to open, diff or create
829
		if (this.hasInitialFilesToOpen) {
I
isidor 已提交
830

B
Benjamin Pasero 已提交
831
			// Files to diff is exclusive
832
			const filesToDiff = this.toInputs(config.filesToDiff, false);
833
			if (filesToDiff && filesToDiff.length === 2) {
B
Benjamin Pasero 已提交
834
				return [<IResourceDiffInput>{
835 836
					leftResource: filesToDiff[0].resource,
					rightResource: filesToDiff[1].resource,
B
Benjamin Pasero 已提交
837
					options: { pinned: true },
B
Benjamin Pasero 已提交
838
					forceFile: true
B
Benjamin Pasero 已提交
839
				}];
B
Benjamin Pasero 已提交
840
			}
I
isidor 已提交
841

842 843
			const filesToCreate = this.toInputs(config.filesToCreate, true);
			const filesToOpen = this.toInputs(config.filesToOpen, false);
I
isidor 已提交
844

845
			// Otherwise: Open/Create files
B
Benjamin Pasero 已提交
846
			return [...filesToOpen, ...filesToCreate];
B
Benjamin Pasero 已提交
847
		}
I
isidor 已提交
848

849
		// Empty workbench
850
		else if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY && this.openUntitledFile()) {
B
Benjamin Pasero 已提交
851
			const isEmpty = this.editorGroupService.count === 1 && this.editorGroupService.activeGroup.count === 0;
852
			if (!isEmpty) {
B
Benjamin Pasero 已提交
853
				return []; // do not open any empty untitled file if we restored editors from previous session
854
			}
B
Benjamin Pasero 已提交
855

856 857
			return this.backupFileService.hasBackups().then(hasBackups => {
				if (hasBackups) {
B
Benjamin Pasero 已提交
858
					return []; // do not open any empty untitled file if we have backups to restore
859
				}
B
Benjamin Pasero 已提交
860

B
Benjamin Pasero 已提交
861
				return [<IUntitledResourceInput>{}];
862
			});
863
		}
864

B
Benjamin Pasero 已提交
865
		return [];
B
Benjamin Pasero 已提交
866
	}
867

868
	private toInputs(paths: IPath[], isNew: boolean): Array<IResourceInput | IUntitledResourceInput> {
B
Benjamin Pasero 已提交
869 870
		if (!paths || !paths.length) {
			return [];
871
		}
I
isidor 已提交
872

B
Benjamin Pasero 已提交
873
		return paths.map(p => {
874
			const resource = p.fileUri;
875 876 877 878
			let input: IResourceInput | IUntitledResourceInput;
			if (isNew) {
				input = { filePath: resource.fsPath, options: { pinned: true } } as IUntitledResourceInput;
			} else {
B
Benjamin Pasero 已提交
879
				input = { resource, options: { pinned: true }, forceFile: true } as IResourceInput;
880
			}
E
Erich Gamma 已提交
881

882
			if (!isNew && p.lineNumber) {
B
Benjamin Pasero 已提交
883 884 885 886 887
				input.options.selection = {
					startLineNumber: p.lineNumber,
					startColumn: p.columnNumber
				};
			}
888

B
Benjamin Pasero 已提交
889 890
			return input;
		});
891 892
	}

893
	private openUntitledFile() {
894
		const startupEditor = this.configurationService.inspect('workbench.startupEditor');
B
Benjamin Pasero 已提交
895 896

		// Fallback to previous workbench.welcome.enabled setting in case startupEditor is not defined
897
		if (!startupEditor.user && !startupEditor.workspace) {
898 899 900
			const welcomeEnabledValue = this.configurationService.getValue('workbench.welcome.enabled');
			if (typeof welcomeEnabledValue === 'boolean') {
				return !welcomeEnabledValue;
901
			}
902
		}
E
Erich Gamma 已提交
903

904
		return startupEditor.value === 'newUntitledFile';
905
	}
E
Erich Gamma 已提交
906 907

	private initSettings(): void {
908

E
Erich Gamma 已提交
909
		// Sidebar visibility
910
		this.sideBarHidden = this.storageService.getBoolean(Workbench.sidebarHiddenStorageKey, StorageScope.WORKSPACE, this.contextService.getWorkbenchState() === WorkbenchState.EMPTY);
911

I
isidor 已提交
912
		// Panel part visibility
913
		const panelRegistry = Registry.as<PanelRegistry>(PanelExtensions.Panels);
914
		this.panelHidden = this.storageService.getBoolean(Workbench.panelHiddenStorageKey, StorageScope.WORKSPACE, true);
915 916
		if (!panelRegistry.getDefaultPanelId()) {
			this.panelHidden = true; // we hide panel part if there is no default panel
917 918
		}

E
Erich Gamma 已提交
919
		// Sidebar position
920
		const sideBarPosition = this.configurationService.getValue<string>(Workbench.sidebarPositionConfigurationKey);
921
		this.sideBarPosition = (sideBarPosition === 'right') ? Position.RIGHT : Position.LEFT;
922

I
isidor 已提交
923
		// Panel position
924
		this.setPanelPositionFromStorageOrConfig();
925

926
		// Menubar visibility
927
		const menuBarVisibility = this.configurationService.getValue<MenuBarVisibility>(Workbench.menubarVisibilityConfigurationKey);
S
SteVen Batten 已提交
928
		this.setMenubarVisibility(menuBarVisibility, true);
929

B
Benjamin Pasero 已提交
930
		// Statusbar visibility
931
		const statusBarVisible = this.configurationService.getValue<string>(Workbench.statusbarVisibleConfigurationKey);
932
		this.statusBarHidden = !statusBarVisible;
933

S
Sanders Lauture 已提交
934
		// Activity bar visibility
935
		const activityBarVisible = this.configurationService.getValue<string>(Workbench.activityBarVisibleConfigurationKey);
S
Sanders Lauture 已提交
936
		this.activityBarHidden = !activityBarVisible;
937

938
		// Font aliasing
939
		this.fontAliasing = this.configurationService.getValue<FontAliasingOption>(Workbench.fontAliasingConfigurationKey);
940

I
isidor 已提交
941 942
		// Zen mode
		this.zenMode = {
I
isidor 已提交
943
			active: false,
944
			transitionedToFullScreen: false,
945
			transitionedToCenteredEditorLayout: false,
946
			wasSideBarVisible: false,
947 948
			wasPanelVisible: false,
			transitionDisposeables: []
I
isidor 已提交
949
		};
E
Erich Gamma 已提交
950 951
	}

952 953
	private setPanelPositionFromStorageOrConfig() {
		const defaultPanelPosition = this.configurationService.getValue<string>(Workbench.defaultPanelPositionStorageKey);
954
		const panelPosition = this.storageService.get(Workbench.panelPositionStorageKey, StorageScope.WORKSPACE, defaultPanelPosition);
955

956 957
		this.panelPosition = (panelPosition === 'right') ? Position.RIGHT : Position.BOTTOM;
	}
958

B
Benjamin Pasero 已提交
959 960
	private useCustomTitleBarStyle(): boolean {
		return getTitleBarStyle(this.configurationService, this.environmentService) === 'custom';
B
Benjamin Pasero 已提交
961 962
	}

963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978
	private saveLastPanelDimension(): void {
		if (!(this.workbenchGrid instanceof SerializableGrid)) {
			return;
		}

		if (this.panelPosition === Position.BOTTOM) {
			this.uiState.lastPanelHeight = this.workbenchGrid.getViewSize(this.panelPart);
		} else {
			this.uiState.lastPanelWidth = this.workbenchGrid.getViewSize(this.panelPart);
		}
	}

	private getLastPanelDimension(position: Position): number | undefined {
		return position === Position.BOTTOM ? this.uiState.lastPanelHeight : this.uiState.lastPanelWidth;
	}

979 980
	private setStatusBarHidden(hidden: boolean, skipLayout?: boolean): void {
		this.statusBarHidden = hidden;
B
Benjamin Pasero 已提交
981

982 983
		// Adjust CSS
		if (hidden) {
B
Benjamin Pasero 已提交
984
			DOM.addClass(this.workbench, 'nostatusbar');
E
Erich Gamma 已提交
985
		} else {
B
Benjamin Pasero 已提交
986
			DOM.removeClass(this.workbench, 'nostatusbar');
E
Erich Gamma 已提交
987 988
		}

989 990
		// Layout
		if (!skipLayout) {
991
			if (this.workbenchGrid instanceof SerializableGrid) {
S
SteVen Batten 已提交
992
				this.layout();
993 994 995
			} else {
				this.workbenchGrid.layout();
			}
996 997 998
		}
	}

999
	private setFontAliasing(aliasing: FontAliasingOption) {
1000
		this.fontAliasing = aliasing;
S
Sanders Lauture 已提交
1001

B
Benjamin Pasero 已提交
1002 1003 1004 1005 1006
		// Remove all
		document.body.classList.remove(...fontAliasingValues.map(value => `monaco-font-aliasing-${value}`));

		// Add specific
		if (fontAliasingValues.some(option => option === aliasing)) {
1007
			document.body.classList.add(`monaco-font-aliasing-${aliasing}`);
S
Sanders Lauture 已提交
1008
		}
1009 1010
	}

E
Erich Gamma 已提交
1011
	private createWorkbenchLayout(): void {
1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034
		if (this.configurationService.getValue('workbench.useExperimentalGridLayout')) {
			const serializedWorkbenchGridString = this.storageService.get(Workbench.workbenchGridUIStateStorageKey, StorageScope.GLOBAL, undefined);

			if (serializedWorkbenchGridString) {
				const serializedWorkbenchGrid = JSON.parse(serializedWorkbenchGridString) as ISerializedGrid;
				this.workbenchGrid = SerializableGrid.deserialize(serializedWorkbenchGrid, {
					fromJSON: (serializedView: { type: Parts }): WorkbenchView => {
						switch (serializedView.type) {
							case Parts.ACTIVITYBAR_PART: return this.activitybarPart;
							case Parts.EDITOR_PART: return this.editorPart;
							case Parts.PANEL_PART: return this.panelPart;
							case Parts.SIDEBAR_PART: return this.sidebarPart;
							case Parts.STATUSBAR_PART: return this.statusbarPart;
							case Parts.TITLEBAR_PART: return this.titlebarPart;
						}

						return null;
					}
				});
			} else {
				this.workbenchGrid = new SerializableGrid(this.editorPart, { proportionalLayout: false });
			}

1035
			this.workbench.prepend(this.workbenchGrid.element);
1036
			this.layout();
1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055
		} else {
			this.workbenchGrid = this.instantiationService.createInstance(
				WorkbenchLayout,
				this.container,
				this.workbench,
				{
					titlebar: this.titlebarPart,
					activitybar: this.activitybarPart,
					editor: this.editorPart,
					sidebar: this.sidebarPart,
					panel: this.panelPart,
					statusbar: this.statusbarPart,
				},
				this.quickOpen,
				this.quickInput,
				this.notificationsCenter,
				this.notificationsToasts
			);
		}
E
Erich Gamma 已提交
1056 1057 1058 1059 1060 1061
	}

	private renderWorkbench(): void {

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

1065
		if (this.panelHidden) {
B
Benjamin Pasero 已提交
1066
			DOM.addClass(this.workbench, 'nopanel');
1067
		}
B
Benjamin Pasero 已提交
1068

1069
		if (this.statusBarHidden) {
B
Benjamin Pasero 已提交
1070
			DOM.addClass(this.workbench, 'nostatusbar');
1071
		}
E
Erich Gamma 已提交
1072

B
Benjamin Pasero 已提交
1073
		// Apply font aliasing
1074 1075
		this.setFontAliasing(this.fontAliasing);

1076 1077
		// Apply fullscreen state
		if (browser.isFullscreen()) {
B
Benjamin Pasero 已提交
1078
			DOM.addClass(this.workbench, 'fullscreen');
B
Benjamin Pasero 已提交
1079 1080
		}

E
Erich Gamma 已提交
1081
		// Create Parts
B
Benjamin Pasero 已提交
1082
		this.createTitlebarPart();
E
Erich Gamma 已提交
1083 1084 1085
		this.createActivityBarPart();
		this.createSidebarPart();
		this.createEditorPart();
1086
		this.createPanelPart();
E
Erich Gamma 已提交
1087 1088
		this.createStatusbarPart();

1089 1090
		// Notification Handlers
		this.createNotificationsHandlers();
1091

1092 1093

		// Menubar visibility changes
B
Benjamin Pasero 已提交
1094
		if ((isWindows || isLinux) && this.useCustomTitleBarStyle()) {
1095 1096 1097
			this.titlebarPart.onMenubarVisibilityChange()(e => this.onMenubarToggled(e));
		}

E
Erich Gamma 已提交
1098
		// Add Workbench to DOM
B
Benjamin Pasero 已提交
1099
		this.container.appendChild(this.workbench);
E
Erich Gamma 已提交
1100 1101
	}

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

B
Benjamin Pasero 已提交
1105
		this.titlebarPart.create(titlebarContainer);
B
Benjamin Pasero 已提交
1106 1107
	}

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

B
Benjamin Pasero 已提交
1111
		this.activitybarPart.create(activitybarPartContainer);
E
Erich Gamma 已提交
1112 1113 1114
	}

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

B
Benjamin Pasero 已提交
1117
		this.sidebarPart.create(sidebarPartContainer);
E
Erich Gamma 已提交
1118 1119
	}

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

B
Benjamin Pasero 已提交
1123
		this.panelPart.create(panelPartContainer);
I
isidor 已提交
1124 1125
	}

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

B
Benjamin Pasero 已提交
1129
		this.editorPart.create(editorContainer);
E
Erich Gamma 已提交
1130 1131 1132
	}

	private createStatusbarPart(): void {
B
Benjamin Pasero 已提交
1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143
		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);

1144 1145 1146 1147 1148
		if (!this.configurationService.getValue('workbench.useExperimentalGridLayout')) {
			// Insert all workbench parts at the beginning. Issue #52531
			// This is primarily for the title bar to allow overriding -webkit-app-region
			this.workbench.insertBefore(part, this.workbench.lastChild);
		}
E
Erich Gamma 已提交
1149

B
Benjamin Pasero 已提交
1150
		return part;
E
Erich Gamma 已提交
1151 1152
	}

1153 1154
	private createNotificationsHandlers(): void {

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

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

1161
		// Notifications Alerts
1162
		this._register(this.instantiationService.createInstance(NotificationsAlerts, this.notificationService.model));
1163 1164 1165 1166

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

1167
		// Eventing
1168
		this._register(this.notificationsCenter.onDidChangeVisibility(() => {
1169 1170 1171 1172 1173 1174 1175 1176

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

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

1177
		// Register Commands
1178
		registerNotificationCommands(this.notificationsCenter, this.notificationsToasts);
1179 1180
	}

1181
	getInstantiationService(): IInstantiationService {
E
Erich Gamma 已提交
1182 1183 1184
		return this.instantiationService;
	}

1185
	private saveState(e: IWillSaveStateEvent): void {
1186
		if (this.zenMode.active) {
B
Benjamin Pasero 已提交
1187
			this.storageService.store(Workbench.zenModeActiveStorageKey, true, StorageScope.WORKSPACE);
1188
		} else {
B
Benjamin Pasero 已提交
1189
			this.storageService.remove(Workbench.zenModeActiveStorageKey, StorageScope.WORKSPACE);
1190
		}
1191 1192 1193 1194 1195 1196 1197 1198

		if (e.reason === WillSaveStateReason.SHUTDOWN && this.zenMode.active) {
			const zenConfig = this.configurationService.getValue<IZenModeSettings>('zenMode');
			if (!zenConfig.restore) {
				// We will not restore zen mode, need to clear all zen mode state changes
				this.toggleZenMode(true);
			}
		}
1199 1200 1201 1202

		if (this.workbenchGrid instanceof SerializableGrid) {
			this.storageService.store(Workbench.workbenchGridUIStateStorageKey, JSON.stringify(this.workbenchGrid.serialize()), StorageScope.GLOBAL);
		}
1203 1204
	}

1205
	dispose(): void {
1206
		super.dispose();
1207 1208 1209 1210 1211 1212

		this.workbenchShutdown = true;
	}

	//#region IPartService

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

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

B
Benjamin Pasero 已提交
1218 1219
	isRestored(): boolean {
		return !!(this.workbenchRestored && this.workbenchStarted);
1220
	}
1221

1222 1223 1224 1225 1226
	hasFocus(part: Parts): boolean {
		const activeElement = document.activeElement;
		if (!activeElement) {
			return false;
		}
1227

1228 1229 1230
		const container = this.getContainer(part);
		return DOM.isAncestor(activeElement, container);
	}
1231

1232
	getContainer(part: Parts): HTMLElement {
1233
		let container: HTMLElement | null = null;
1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253
		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;
		}
1254

1255 1256
		return container;
	}
1257

1258 1259 1260
	isVisible(part: Parts): boolean {
		switch (part) {
			case Parts.TITLEBAR_PART:
B
Benjamin Pasero 已提交
1261
				if (!this.useCustomTitleBarStyle()) {
1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273
					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;
1274 1275 1276 1277 1278 1279 1280 1281
			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 已提交
1282
		}
1283

1284
		return true; // any other part cannot be hidden
E
Erich Gamma 已提交
1285 1286
	}

1287 1288 1289
	getTitleBarOffset(): number {
		let offset = 0;
		if (this.isVisible(Parts.TITLEBAR_PART)) {
S
SteVen Batten 已提交
1290 1291 1292 1293 1294 1295
			if (this.workbenchGrid instanceof SerializableGrid) {
				offset = this.gridHasView(this.titlebarPart) ? this.workbenchGrid.getViewSize2(this.titlebarPart).height : 0;
			} else {
				offset = this.workbenchGrid.partLayoutInfo.titlebar.height;
			}

1296 1297 1298
			if (isMacintosh || this.menubarVisibility === 'hidden') {
				offset /= browser.getZoomFactor();
			}
E
Erich Gamma 已提交
1299
		}
1300 1301

		return offset;
E
Erich Gamma 已提交
1302
	}
1303

1304 1305
	getWorkbenchElement(): HTMLElement {
		return this.workbench;
1306
	}
1307

I
isidor 已提交
1308
	toggleZenMode(skipLayout?: boolean, restoring = false): void {
I
isidor 已提交
1309
		this.zenMode.active = !this.zenMode.active;
1310
		this.zenMode.transitionDisposeables = dispose(this.zenMode.transitionDisposeables);
1311

1312 1313
		// 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)
1314
		let toggleFullScreen = false;
I
isidor 已提交
1315 1316 1317 1318 1319 1320 1321 1322
		const setLineNumbers = (lineNumbers: any) => {
			this.editorService.visibleControls.forEach(editor => {
				const control = <IEditor>editor.getControl();
				if (control) {
					control.updateOptions({ lineNumbers });
				}
			});
		};
1323 1324

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

I
isidor 已提交
1328
			toggleFullScreen = !browser.isFullscreen() && config.fullScreen;
I
isidor 已提交
1329
			this.zenMode.transitionedToFullScreen = restoring ? config.fullScreen : toggleFullScreen;
1330
			this.zenMode.transitionedToCenteredEditorLayout = !this.isEditorLayoutCentered() && config.centerLayout;
1331 1332
			this.zenMode.wasSideBarVisible = this.isVisible(Parts.SIDEBAR_PART);
			this.zenMode.wasPanelVisible = this.isVisible(Parts.PANEL_PART);
1333

1334 1335
			this.setPanelHidden(true, true);
			this.setSideBarHidden(true, true);
I
isidor 已提交
1336

1337 1338 1339
			if (config.hideActivityBar) {
				this.setActivityBarHidden(true, true);
			}
1340

I
isidor 已提交
1341
			if (config.hideStatusBar) {
I
isidor 已提交
1342 1343
				this.setStatusBarHidden(true, true);
			}
1344

I
isidor 已提交
1345 1346 1347 1348 1349
			if (config.hideLineNumbers) {
				setLineNumbers('off');
				this.zenMode.transitionDisposeables.push(this.editorService.onDidVisibleEditorsChange(() => setLineNumbers('off')));
			}

1350 1351
			if (config.hideTabs && this.editorPart.partOptions.showTabs) {
				this.zenMode.transitionDisposeables.push(this.editorPart.enforcePartOptions({ showTabs: false }));
I
isidor 已提交
1352
			}
1353 1354 1355 1356

			if (config.centerLayout) {
				this.centerEditorLayout(true, true);
			}
1357 1358 1359 1360
		}

		// Zen Mode Inactive
		else {
1361
			if (this.zenMode.wasPanelVisible) {
1362
				this.setPanelHidden(false, true);
1363
			}
1364

1365
			if (this.zenMode.wasSideBarVisible) {
1366
				this.setSideBarHidden(false, true);
1367
			}
1368

1369 1370 1371
			if (this.zenMode.transitionedToCenteredEditorLayout) {
				this.centerEditorLayout(false, true);
			}
I
isidor 已提交
1372
			setLineNumbers(this.configurationService.getValue('editor.lineNumbers'));
1373

1374 1375
			// Status bar and activity bar visibility come from settings -> update their visibility.
			this.onDidUpdateConfiguration(true);
1376

B
Benjamin Pasero 已提交
1377
			this.editorGroupService.activeGroup.focus();
1378

1379
			toggleFullScreen = this.zenMode.transitionedToFullScreen && browser.isFullscreen();
I
isidor 已提交
1380
		}
1381

1382
		this.inZenMode.set(this.zenMode.active);
I
isidor 已提交
1383

I
isidor 已提交
1384
		if (!skipLayout) {
1385
			this.layout();
I
isidor 已提交
1386
		}
1387

1388
		if (toggleFullScreen) {
1389
			this.windowService.toggleFullScreen();
1390
		}
I
isidor 已提交
1391 1392
	}

S
SteVen Batten 已提交
1393 1394 1395 1396
	private gridHasView(view: WorkbenchView): boolean {
		if (!(this.workbenchGrid instanceof SerializableGrid)) {
			return false;
		}
1397

S
SteVen Batten 已提交
1398 1399 1400 1401 1402
		try {
			this.workbenchGrid.getViewSize(view);
			return true;
		} catch {
			return false;
1403 1404 1405
		}
	}

S
SteVen Batten 已提交
1406
	private updateGrid(): void {
1407 1408 1409 1410
		if (!(this.workbenchGrid instanceof SerializableGrid)) {
			return;
		}

S
SteVen Batten 已提交
1411 1412 1413 1414 1415
		let panelInGrid = this.gridHasView(this.panelPart);
		let sidebarInGrid = this.gridHasView(this.sidebarPart);
		let activityBarInGrid = this.gridHasView(this.activitybarPart);
		let statusBarInGrid = this.gridHasView(this.statusbarPart);
		let titlebarInGrid = this.gridHasView(this.titlebarPart);
1416

S
SteVen Batten 已提交
1417 1418 1419 1420 1421 1422
		// Remove hidden parts
		if (this.panelHidden && panelInGrid) {
			this.saveLastPanelDimension();
			this.workbenchGrid.removeView(this.panelPart);
			panelInGrid = false;
		}
1423

S
SteVen Batten 已提交
1424 1425 1426 1427
		if (this.statusBarHidden && statusBarInGrid) {
			this.workbenchGrid.removeView(this.statusbarPart);
			statusBarInGrid = false;
		}
1428

1429
		if (!this.isVisible(Parts.TITLEBAR_PART) && titlebarInGrid) {
S
SteVen Batten 已提交
1430 1431 1432
			this.workbenchGrid.removeView(this.titlebarPart);
			titlebarInGrid = false;
		}
1433

S
SteVen Batten 已提交
1434 1435 1436 1437
		if (this.activityBarHidden && activityBarInGrid) {
			this.workbenchGrid.removeView(this.activitybarPart);
			activityBarInGrid = false;
		}
1438

S
SteVen Batten 已提交
1439 1440 1441 1442 1443
		if (this.sideBarHidden && sidebarInGrid) {
			this.uiState.lastSidebarDimension = this.workbenchGrid.getViewSize(this.sidebarPart);
			this.workbenchGrid.removeView(this.sidebarPart);
			sidebarInGrid = false;
		}
1444 1445


S
SteVen Batten 已提交
1446 1447 1448 1449 1450 1451 1452
		// Add visible parts
		if (!this.statusBarHidden && !statusBarInGrid) {
			if (sidebarInGrid) {
				this.uiState.lastSidebarDimension = this.workbenchGrid.getViewSize(this.sidebarPart);
				this.workbenchGrid.removeView(this.sidebarPart);
				sidebarInGrid = false;
			}
1453

S
SteVen Batten 已提交
1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468
			if (activityBarInGrid) {
				this.workbenchGrid.removeView(this.activitybarPart);
				activityBarInGrid = false;
			}

			if (panelInGrid) {
				this.saveLastPanelDimension();
				this.workbenchGrid.removeView(this.panelPart);
				panelInGrid = false;
			}

			this.workbenchGrid.addView(this.statusbarPart, Sizing.Split, this.editorPart, Direction.Down);
			statusBarInGrid = true;
		}

1469
		if (this.isVisible(Parts.TITLEBAR_PART) && !titlebarInGrid) {
S
SteVen Batten 已提交
1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528
			if (sidebarInGrid) {
				this.uiState.lastSidebarDimension = this.workbenchGrid.getViewSize(this.sidebarPart);
				this.workbenchGrid.removeView(this.sidebarPart);
				sidebarInGrid = false;
			}

			if (activityBarInGrid) {
				this.workbenchGrid.removeView(this.activitybarPart);
				activityBarInGrid = false;
			}

			if (panelInGrid && this.panelPosition !== Position.BOTTOM) {
				this.saveLastPanelDimension();
				this.workbenchGrid.removeView(this.panelPart);
				panelInGrid = false;
			}

			this.workbenchGrid.addView(this.titlebarPart, Sizing.Split, this.editorPart, Direction.Up);
			titlebarInGrid = true;
		}

		if (!this.activityBarHidden && !activityBarInGrid) {
			if (sidebarInGrid) {
				this.uiState.lastSidebarDimension = this.workbenchGrid.getViewSize(this.sidebarPart);
				this.workbenchGrid.removeView(this.sidebarPart);
				sidebarInGrid = false;
			}

			this.workbenchGrid.addView(this.activitybarPart, Sizing.Split, this.editorPart, this.sideBarPosition === Position.RIGHT ? Direction.Right : Direction.Left);
			activityBarInGrid = true;
		}

		if (!this.sideBarHidden && !sidebarInGrid) {
			if (panelInGrid && this.panelPosition === Position.BOTTOM) {
				this.saveLastPanelDimension();
				this.workbenchGrid.removeView(this.panelPart);
				panelInGrid = false;
			}

			this.workbenchGrid.addView(this.sidebarPart, this.uiState.lastSidebarDimension !== undefined ? this.uiState.lastSidebarDimension : Sizing.Split, this.editorPart, this.sideBarPosition === Position.RIGHT ? Direction.Right : Direction.Left);
			sidebarInGrid = true;
		}

		if (!this.panelHidden && !panelInGrid) {
			this.workbenchGrid.addView(this.panelPart, this.getLastPanelDimension(this.panelPosition) !== undefined ? this.getLastPanelDimension(this.panelPosition) : Sizing.Split, this.editorPart, this.panelPosition === Position.BOTTOM ? Direction.Down : Direction.Right);
			panelInGrid = true;
		}
	}

	layout(options?: ILayoutOptions): void {
		this.contextViewService.layout();

		if (this.workbenchStarted && !this.workbenchShutdown) {
			if (this.workbenchGrid instanceof SerializableGrid) {
				const dimensions = DOM.getClientArea(this.container);
				DOM.position(this.workbench, 0, 0, 0, 0, 'relative');
				DOM.size(this.workbench, dimensions.width, dimensions.height);

				this.workbenchGrid.layout(dimensions.width, dimensions.height);
1529
				this.updateGrid();
S
SteVen Batten 已提交
1530 1531
			} else {
				this.workbenchGrid.layout(options);
1532
			}
1533 1534 1535
		}
	}

1536
	isEditorLayoutCentered(): boolean {
1537
		return this.shouldCenterLayout;
S
SrTobi 已提交
1538 1539
	}

1540
	centerEditorLayout(active: boolean, skipLayout?: boolean): void {
B
Benjamin Pasero 已提交
1541
		this.storageService.store(Workbench.centeredEditorLayoutActiveStorageKey, active, StorageScope.WORKSPACE);
1542 1543
		this.shouldCenterLayout = active;
		let smartActive = active;
1544
		if (this.editorPart.groups.length > 1 && this.configurationService.getValue('workbench.editor.centeredLayoutAutoResize')) {
B
Benjamin Pasero 已提交
1545
			smartActive = false; // Respect the auto resize setting - do not go into centered layout if there is more than 1 group.
1546
		}
B
Benjamin Pasero 已提交
1547

1548
		// Enter Centered Editor Layout
1549 1550
		if (this.editorPart.isLayoutCentered() !== smartActive) {
			this.editorPart.centerLayout(smartActive);
1551

1552 1553 1554
			if (!skipLayout) {
				this.layout();
			}
1555
		}
S
SrTobi 已提交
1556 1557
	}

1558
	resizePart(part: Parts, sizeChange: number): void {
1559
		let view: WorkbenchView;
1560 1561
		switch (part) {
			case Parts.SIDEBAR_PART:
1562
				view = this.sidebarPart;
1563
			case Parts.PANEL_PART:
1564
				view = this.panelPart;
1565
			case Parts.EDITOR_PART:
1566 1567 1568 1569 1570 1571
				view = this.editorPart;
				if (this.workbenchGrid instanceof SerializableGrid) {
					this.workbenchGrid.resizeView(view, this.workbenchGrid.getViewSize(view) + sizeChange);
				} else {
					this.workbenchGrid.resizePart(part, sizeChange);
				}
1572 1573
				break;
			default:
B
Benjamin Pasero 已提交
1574
				return; // Cannot resize other parts
1575 1576 1577
		}
	}

1578 1579
	setActivityBarHidden(hidden: boolean, skipLayout?: boolean): void {
		this.activityBarHidden = hidden;
1580

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

1591
	setSideBarHidden(hidden: boolean, skipLayout?: boolean): void {
1592 1593 1594 1595 1596
		this.sideBarHidden = hidden;
		this.sideBarVisibleContext.set(!hidden);

		// Adjust CSS
		if (hidden) {
B
Benjamin Pasero 已提交
1597
			DOM.addClass(this.workbench, 'nosidebar');
1598
		} else {
B
Benjamin Pasero 已提交
1599
			DOM.removeClass(this.workbench, 'nosidebar');
1600 1601
		}

1602 1603
		// If sidebar becomes hidden, also hide the current active Viewlet if any
		if (hidden && this.sidebarPart.getActiveViewlet()) {
1604 1605 1606 1607 1608 1609 1610 1611 1612
			this.sidebarPart.hideActiveViewlet();
			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();
			} else {
				this.editorGroupService.activeGroup.focus();
			}
1613 1614 1615 1616 1617 1618
		}

		// If sidebar becomes visible, show last active Viewlet or default viewlet
		else if (!hidden && !this.sidebarPart.getActiveViewlet()) {
			const viewletToOpen = this.sidebarPart.getLastActiveViewletId();
			if (viewletToOpen) {
I
isidor 已提交
1619
				const viewlet = this.sidebarPart.openViewlet(viewletToOpen, true);
1620
				if (!viewlet) {
I
isidor 已提交
1621
					this.sidebarPart.openViewlet(this.sidebarPart.getDefaultViewletId(), true);
1622
				}
1623
			}
1624 1625
		}

1626

1627 1628 1629 1630 1631 1632 1633
		// 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);
		}
1634

1635 1636
		// Layout
		if (!skipLayout) {
1637
			if (this.workbenchGrid instanceof SerializableGrid) {
S
SteVen Batten 已提交
1638
				this.layout();
1639 1640 1641
			} else {
				this.workbenchGrid.layout();
			}
1642
		}
1643
	}
1644

1645
	setPanelHidden(hidden: boolean, skipLayout?: boolean): void {
1646 1647 1648 1649
		this.panelHidden = hidden;

		// Adjust CSS
		if (hidden) {
B
Benjamin Pasero 已提交
1650
			DOM.addClass(this.workbench, 'nopanel');
1651
		} else {
B
Benjamin Pasero 已提交
1652
			DOM.removeClass(this.workbench, 'nopanel');
1653 1654 1655 1656
		}

		// If panel part becomes hidden, also hide the current active panel if any
		if (hidden && this.panelPart.getActivePanel()) {
1657 1658
			this.panelPart.hideActivePanel();
			this.editorGroupService.activeGroup.focus(); // Pass focus to editor group if panel part is now hidden
1659 1660 1661 1662 1663 1664
		}

		// 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) {
1665
				this.panelPart.openPanel(panelToOpen, true);
1666 1667 1668 1669
			}
		}


1670 1671 1672 1673 1674 1675
		// Remember in settings
		if (!hidden) {
			this.storageService.store(Workbench.panelHiddenStorageKey, 'false', StorageScope.WORKSPACE);
		} else {
			this.storageService.remove(Workbench.panelHiddenStorageKey, StorageScope.WORKSPACE);
		}
1676

1677 1678
		// Layout
		if (!skipLayout) {
1679
			if (this.workbenchGrid instanceof SerializableGrid) {
S
SteVen Batten 已提交
1680
				this.layout();
1681 1682 1683
			} else {
				this.workbenchGrid.layout();
			}
1684
		}
1685 1686 1687
	}

	toggleMaximizedPanel(): void {
1688 1689 1690 1691 1692
		if (this.workbenchGrid instanceof SerializableGrid) {
			this.workbenchGrid.maximizeViewSize(this.panelPart);
		} else {
			this.workbenchGrid.layout({ toggleMaximizedPanel: true, source: Parts.PANEL_PART });
		}
1693 1694 1695
	}

	isPanelMaximized(): boolean {
1696 1697 1698 1699 1700 1701 1702 1703 1704
		if (this.workbenchGrid instanceof SerializableGrid) {
			try {
				return this.workbenchGrid.getViewSize2(this.panelPart).height === this.panelPart.maximumHeight;
			} catch (e) {
				return false;
			}
		} else {
			return this.workbenchGrid.isPanelMaximized();
		}
1705 1706 1707 1708 1709 1710 1711
	}

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

	setSideBarPosition(position: Position): void {
1712 1713
		const wasHidden = this.sideBarHidden;

1714
		if (this.sideBarHidden) {
1715
			this.setSideBarHidden(false, true /* Skip Layout */);
1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732
		}

		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
1733 1734
		if (this.workbenchGrid instanceof SerializableGrid) {

S
SteVen Batten 已提交
1735
			if (!wasHidden) {
1736
				this.uiState.lastSidebarDimension = this.workbenchGrid.getViewSize(this.sidebarPart);
S
SteVen Batten 已提交
1737
				this.workbenchGrid.removeView(this.sidebarPart);
1738 1739
			}

S
SteVen Batten 已提交
1740 1741
			if (!this.activityBarHidden) {
				this.workbenchGrid.removeView(this.activitybarPart);
1742 1743
			}

S
SteVen Batten 已提交
1744
			this.layout();
1745 1746 1747
		} else {
			this.workbenchGrid.layout();
		}
1748 1749
	}

S
SteVen Batten 已提交
1750
	setMenubarVisibility(visibility: MenuBarVisibility, skipLayout: boolean): void {
S
SteVen Batten 已提交
1751 1752
		if (this.menubarVisibility !== visibility) {
			this.menubarVisibility = visibility;
1753

1754
			// Layout
S
SteVen Batten 已提交
1755
			if (!skipLayout) {
1756 1757 1758 1759 1760 1761
				if (this.workbenchGrid instanceof SerializableGrid) {
					const dimensions = DOM.getClientArea(this.container);
					this.workbenchGrid.layout(dimensions.width, dimensions.height);
				} else {
					this.workbenchGrid.layout();
				}
S
SteVen Batten 已提交
1762
			}
1763 1764 1765
		}
	}

S
SteVen Batten 已提交
1766 1767 1768 1769
	getMenubarVisibility(): MenuBarVisibility {
		return this.menubarVisibility;
	}

1770 1771 1772 1773
	getPanelPosition(): Position {
		return this.panelPosition;
	}

1774
	setPanelPosition(position: Position): void {
1775 1776
		const wasHidden = this.panelHidden;

1777 1778
		if (this.panelHidden) {
			this.setPanelHidden(false, true /* Skip Layout */);
1779 1780
		} else {
			this.saveLastPanelDimension();
1781
		}
1782

1783 1784 1785 1786
		const newPositionValue = (position === Position.BOTTOM) ? 'bottom' : 'right';
		const oldPositionValue = (this.panelPosition === Position.BOTTOM) ? 'bottom' : 'right';
		this.panelPosition = position;
		this.storageService.store(Workbench.panelPositionStorageKey, PositionToString(this.panelPosition).toLowerCase(), StorageScope.WORKSPACE);
1787

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

1792 1793 1794 1795
		// Update Styles
		this.panelPart.updateStyles();

		// Layout
1796 1797 1798 1799 1800 1801
		if (this.workbenchGrid instanceof SerializableGrid) {
			if (wasHidden) {
				this.workbenchGrid.addView(this.panelPart, this.getLastPanelDimension(position) !== undefined ? this.getLastPanelDimension(position) : Sizing.Split, this.editorPart, position === Position.BOTTOM ? Direction.Down : Direction.Right);
			} else {
				this.workbenchGrid.moveView(this.panelPart, this.getLastPanelDimension(position) !== undefined ? this.getLastPanelDimension(position) : Sizing.Split, this.editorPart, position === Position.BOTTOM ? Direction.Down : Direction.Right);
			}
1802

1803 1804 1805 1806 1807 1808 1809
			const dimensions = DOM.getClientArea(this.container);
			this.workbenchGrid.layout(dimensions.width, dimensions.height);
		} else {
			this.workbenchGrid.layout();
		}
	}
}