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

6
import 'vs/workbench/browser/style';
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 { EventType, addDisposableListener, addClasses, scheduleAtNextAnimationFrame, addClass, removeClass, trackFocus, isAncestor, getClientArea, position, size } from 'vs/base/browser/dom';
B
Benjamin Pasero 已提交
12
import { RunOnceScheduler, runWhenIdle } from 'vs/base/common/async';
13 14 15
import { getZoomLevel, onDidChangeFullscreen, isFullscreen, getZoomFactor } from 'vs/base/browser/browser';
import { mark } from 'vs/base/common/performance';
import { onUnexpectedError, setUnexpectedErrorHandler } 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';
19
import { isWindows, isLinux, isMacintosh, language } 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
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';
64
import { TextFileService } from 'vs/workbench/services/textfile/common/textFileService';
J
Johannes Rieken 已提交
65
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
66
import { IProgressService2 } from 'vs/platform/progress/common/progress';
67
import { ProgressService2 } from 'vs/workbench/services/progress/browser/progressService2';
68
import { TextModelResolverService } from 'vs/workbench/services/textmodelResolver/common/textModelResolverService';
69
import { ITextModelService } from 'vs/editor/common/services/resolverService';
J
Johannes Rieken 已提交
70
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
71
import { LifecyclePhase, StartupKind } from 'vs/platform/lifecycle/common/lifecycle';
72
import { LifecycleService } from 'vs/platform/lifecycle/electron-browser/lifecycleService';
B
Benjamin Pasero 已提交
73
import { IWindowService, IWindowConfiguration, IPath, MenuBarVisibility, getTitleBarStyle } from 'vs/platform/windows/common/windows';
J
Johannes Rieken 已提交
74
import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar';
75
import { IMenuService, SyncActionDescriptor } from 'vs/platform/actions/common/actions';
76
import { MenuService } from 'vs/platform/actions/common/menuService';
S
SteVen Batten 已提交
77
import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';
J
Johannes Rieken 已提交
78
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
B
Benjamin Pasero 已提交
79
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
80
import { ShowPreviousWindowTab, MoveWindowTabToNewWindow, MergeAllWindowTabs, ShowNextWindowTab, ToggleWindowTabsBar, NewWindowTab, OpenRecentAction, ReloadWindowAction, ReloadWindowWithExtensionsDisabledAction } from 'vs/workbench/electron-browser/actions/windowActions';
81
import { ToggleDevToolsAction } from 'vs/workbench/electron-browser/actions/developerActions';
82
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
83
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
B
Benjamin Pasero 已提交
84
import { WorkspaceEditingService } from 'vs/workbench/services/workspace/node/workspaceEditingService';
85
import { FileDecorationsService } from 'vs/workbench/services/decorations/browser/decorationsService';
J
Johannes Rieken 已提交
86
import { IDecorationsService } from 'vs/workbench/services/decorations/browser/decorations';
I
isidor 已提交
87
import { ActivityService } from 'vs/workbench/services/activity/browser/activityService';
88
import { URI } from 'vs/base/common/uri';
J
Joao Moreno 已提交
89
import { IListService, ListService } from 'vs/platform/list/browser/listService';
A
Alex Ross 已提交
90
import { InputFocusedContext, IsMacContext, IsLinuxContext, IsWindowsContext, SupportsOpenFileFolderContext, SupportsWorkspacesContext } from 'vs/platform/contextkey/common/contextkeys';
91
import { IViewsService } from 'vs/workbench/common/views';
S
Sandeep Somavarapu 已提交
92
import { ViewsService } from 'vs/workbench/browser/parts/views/views';
93 94
import { INotificationService } from 'vs/platform/notification/common/notification';
import { NotificationService } from 'vs/workbench/services/notification/common/notificationService';
95 96
import { NotificationsCenter } from 'vs/workbench/browser/parts/notifications/notificationsCenter';
import { NotificationsAlerts } from 'vs/workbench/browser/parts/notifications/notificationsAlerts';
97
import { NotificationsStatus } from 'vs/workbench/browser/parts/notifications/notificationsStatus';
98
import { registerNotificationCommands } from 'vs/workbench/browser/parts/notifications/notificationsCommands';
99
import { NotificationsToasts } from 'vs/workbench/browser/parts/notifications/notificationsToasts';
J
Joao Moreno 已提交
100
import { IPCClient } from 'vs/base/parts/ipc/node/ipc';
J
Joao Moreno 已提交
101
import { registerWindowDriver } from 'vs/platform/driver/electron-browser/driver';
S
Sandeep Somavarapu 已提交
102 103
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
import { PreferencesService } from 'vs/workbench/services/preferences/browser/preferencesService';
104
import { IEditorService, IResourceEditor } from 'vs/workbench/services/editor/common/editorService';
105
import { IEditorGroupsService, GroupDirection, preferredSideBySideGroupDirection } from 'vs/workbench/services/editor/common/editorGroupsService';
106
import { EditorService } from 'vs/workbench/services/editor/browser/editorService';
J
Joao Moreno 已提交
107
import { IExtensionUrlHandler, ExtensionUrlHandler } from 'vs/workbench/services/extensions/electron-browser/inactiveExtensionUrlHandler';
S
SteVen Batten 已提交
108
import { ContextViewService } from 'vs/platform/contextview/browser/contextViewService';
A
Alex Dima 已提交
109 110
import { WorkbenchThemeService } from 'vs/workbench/services/themes/electron-browser/workbenchThemeService';
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
M
Martin Aeschlimann 已提交
111
import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
112
import { FileDialogService } from 'vs/workbench/services/dialogs/electron-browser/dialogService';
113
import { LogStorageAction } from 'vs/platform/storage/node/storageService';
S
SteVen Batten 已提交
114
import { Sizing, Direction, Grid, View } from 'vs/base/browser/ui/grid/grid';
I
isidor 已提交
115
import { IEditor } from 'vs/editor/common/editorCommon';
116
import { WorkbenchLayout } from 'vs/workbench/browser/layout';
117 118 119 120 121 122
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { setARIAContainer } from 'vs/base/browser/ui/aria/aria';
import { restoreFontInfo, readFontInfo, saveFontInfo } from 'vs/editor/browser/config/configuration';
import { BareFontInfo } from 'vs/editor/common/config/fontInfo';
import { ILogService } from 'vs/platform/log/common/log';
import { toErrorMessage } from 'vs/base/common/errorMessage';
123

E
Erich Gamma 已提交
124
interface WorkbenchParams {
125
	configuration: IWindowConfiguration;
126
	serviceCollection: ServiceCollection;
E
Erich Gamma 已提交
127 128
}

I
isidor 已提交
129 130
interface IZenModeSettings {
	fullScreen: boolean;
131
	centerLayout: boolean;
I
isidor 已提交
132
	hideTabs: boolean;
133
	hideActivityBar: boolean;
I
isidor 已提交
134
	hideStatusBar: boolean;
I
isidor 已提交
135
	hideLineNumbers: boolean;
I
isidor 已提交
136
	restore: boolean;
I
isidor 已提交
137 138
}

139
interface IWorkbenchStartedInfo {
140 141
	customKeybindingsCount: number;
	pinnedViewlets: string[];
142
	restoredViewlet: string;
143
	restoredEditorsCount: number;
144
}
145 146
type FontAliasingOption = 'default' | 'antialiased' | 'none' | 'auto';

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

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

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

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

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

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

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

199 200 201
	private previousErrorValue: string;
	private previousErrorTime: number = 0;

E
Erich Gamma 已提交
202
	private workbenchParams: WorkbenchParams;
B
Benjamin Pasero 已提交
203
	private workbench: HTMLElement;
E
Erich Gamma 已提交
204
	private workbenchStarted: boolean;
B
Benjamin Pasero 已提交
205
	private workbenchRestored: boolean;
E
Erich Gamma 已提交
206
	private workbenchShutdown: boolean;
207

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

S
SteVen Batten 已提交
217
	private workbenchGrid: Grid<View> | WorkbenchLayout;
218

B
Benjamin Pasero 已提交
219
	private titlebarPart: TitlebarPart;
E
Erich Gamma 已提交
220 221
	private activitybarPart: ActivitybarPart;
	private sidebarPart: SidebarPart;
I
isidor 已提交
222
	private panelPart: PanelPart;
E
Erich Gamma 已提交
223 224
	private editorPart: EditorPart;
	private statusbarPart: StatusbarPart;
S
SteVen Batten 已提交
225 226 227 228 229 230 231 232

	private titlebarPartView: View;
	private activitybarPartView: View;
	private sidebarPartView: View;
	private panelPartView: View;
	private editorPartView: View;
	private statusbarPartView: View;

E
Erich Gamma 已提交
233
	private quickOpen: QuickOpenController;
234
	private notificationsCenter: NotificationsCenter;
235
	private notificationsToasts: NotificationsToasts;
236

S
SteVen Batten 已提交
237
	private editorHidden: boolean;
E
Erich Gamma 已提交
238
	private sideBarHidden: boolean;
239
	private statusBarHidden: boolean;
S
Sanders Lauture 已提交
240
	private activityBarHidden: boolean;
241
	private menubarToggled: boolean;
E
Erich Gamma 已提交
242
	private sideBarPosition: Position;
I
isidor 已提交
243
	private panelPosition: Position;
I
isidor 已提交
244
	private panelHidden: boolean;
S
SteVen Batten 已提交
245
	private menubarVisibility: MenuBarVisibility;
246 247
	private zenMode: IZenMode;
	private fontAliasing: FontAliasingOption;
248
	private hasInitialFilesToOpen: boolean;
249
	private shouldCenterLayout = false;
250 251 252 253 254
	private uiState: IWorkbenchUIState = {
		lastPanelHeight: 350,
		lastPanelWidth: 350,
		lastSidebarDimension: 300,
	};
255

I
isidor 已提交
256
	private inZenMode: IContextKey<boolean>;
257
	private sideBarVisibleContext: IContextKey<boolean>;
258

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

261
	constructor(
262
		private container: HTMLElement,
J
Joao Moreno 已提交
263
		private configuration: IWindowConfiguration,
264
		serviceCollection: ServiceCollection,
265
		private lifecycleService: LifecycleService,
J
Joao Moreno 已提交
266
		private mainProcessClient: IPCClient,
267 268 269 270 271 272 273
		@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,
274 275 276
		@INotificationService private readonly notificationService: NotificationService,
		@ITelemetryService private readonly telemetryService: ITelemetryService,
		@ILogService private readonly logService: ILogService
277
	) {
278
		super();
E
Erich Gamma 已提交
279

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

282
		this.hasInitialFilesToOpen =
B
Benjamin Pasero 已提交
283 284 285
			(configuration.filesToCreate && configuration.filesToCreate.length > 0) ||
			(configuration.filesToOpen && configuration.filesToOpen.length > 0) ||
			(configuration.filesToDiff && configuration.filesToDiff.length > 0);
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303

		this.registerErrorHandler();
	}

	private registerErrorHandler(): void {

		// Listen on unhandled rejection events
		window.addEventListener('unhandledrejection', (event: PromiseRejectionEvent) => {

			// See https://developer.mozilla.org/en-US/docs/Web/API/PromiseRejectionEvent
			onUnexpectedError(event.reason);

			// Prevent the printing of this event to the console
			event.preventDefault();
		});

		// Install handler for unexpected errors
		setUnexpectedErrorHandler(error => this.handleUnexpectedError(error));
304 305
	}

306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
	private handleUnexpectedError(error: any): void {
		const errorMsg = toErrorMessage(error, true);
		if (!errorMsg) {
			return;
		}

		const now = Date.now();
		if (errorMsg === this.previousErrorValue && now - this.previousErrorTime <= 1000) {
			return; // Return if error message identical to previous and shorter than 1 second
		}

		this.previousErrorTime = now;
		this.previousErrorValue = errorMsg;

		// Log it
		this.logService.error(errorMsg);

		// Show to user if friendly message provided
		if (error && error.friendlyMessage && this.notificationService) {
			this.notificationService.error(error.friendlyMessage);
		}
	}

	startup(): Promise<void> {
		try {
			return this.doStartup().then(undefined, error => this.logService.error(toErrorMessage(error, true)));
		} catch (error) {
			this.logService.error(toErrorMessage(error, true));

			throw error; // rethrow because this is a critical issue we cannot handle properly here
		}
337 338
	}

339
	private doStartup(): Promise<void> {
340
		this.workbenchStarted = true;
E
Erich Gamma 已提交
341

342 343 344 345 346 347 348 349 350 351 352 353 354
		// Set lifecycle phase to `Ready`
		this.lifecycleService.phase = LifecyclePhase.Ready;

		// ARIA
		setARIAContainer(document.body);

		// Warm up font cache information before building up too many dom elements
		restoreFontInfo(this.storageService);
		readFontInfo(BareFontInfo.createFromRawSettings(this.configurationService.getValue('editor'), getZoomLevel()));
		this._register(this.storageService.onWillSaveState(() => {
			saveFontInfo(this.storageService); // Keep font info for next startup around
		}));

B
Benjamin Pasero 已提交
355
		// Create Workbench Container
356
		this.createWorkbench();
E
Erich Gamma 已提交
357

358 359
		// Install some global actions
		this.createGlobalActions();
360

361 362
		// Services
		this.initServices();
E
Erich Gamma 已提交
363

364 365
		// Context Keys
		this.handleContextKeys();
J
Joao Moreno 已提交
366

367 368
		// Register Listeners
		this.registerListeners();
E
Erich Gamma 已提交
369

370 371
		// Settings
		this.initSettings();
E
Erich Gamma 已提交
372

373 374
		// Create Workbench and Parts
		this.renderWorkbench();
375

376 377
		// Workbench Layout
		this.createWorkbenchLayout();
B
polish  
Benjamin Pasero 已提交
378

379 380 381
		// Layout
		this.layout();

J
Joao Moreno 已提交
382 383
		// Driver
		if (this.environmentService.driverHandle) {
384
			registerWindowDriver(this.mainProcessClient, this.configuration.windowId, this.instantiationService).then(disposable => this._register(disposable));
J
Joao Moreno 已提交
385 386
		}

387 388 389 390 391 392 393 394 395
		// Handle case where workbench is not starting up properly
		const timeoutHandle = setTimeout(() => {
			this.logService.warn('Workbench did not finish loading in 10 seconds, that might be a problem that should be reported.');
		}, 10000);

		this.lifecycleService.when(LifecyclePhase.Restored).then(() => {
			clearTimeout(timeoutHandle);
		});

396
		// Restore Parts
B
Benjamin Pasero 已提交
397 398
		return this.restoreParts();
	}
399

B
Benjamin Pasero 已提交
400
	private createWorkbench(): void {
B
Benjamin Pasero 已提交
401 402
		this.workbench = document.createElement('div');
		this.workbench.id = Identifiers.WORKBENCH_CONTAINER;
S
SteVen Batten 已提交
403

404
		addClasses(this.workbench, 'monaco-workbench', isWindows ? 'windows' : isLinux ? 'linux' : 'mac');
405
	}
E
Erich Gamma 已提交
406

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

B
Benjamin Pasero 已提交
410
		// Actions registered here to adjust for developing vs built workbench
411
		const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
R
Rob Lourens 已提交
412 413
		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"));
414 415
		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');
416
		registry.registerWorkbenchAction(new SyncActionDescriptor(LogStorageAction, LogStorageAction.ID, LogStorageAction.LABEL), 'Developer: Log Storage', localize('developer', "Developer"));
417

418
		// Actions for macOS native tabs management (only when enabled)
419
		const windowConfig = this.configurationService.getValue<IWindowConfiguration>();
420
		if (windowConfig && windowConfig.window && windowConfig.window.nativeTabs) {
421
			registry.registerWorkbenchAction(new SyncActionDescriptor(NewWindowTab, NewWindowTab.ID, NewWindowTab.LABEL), 'New Window Tab');
422 423 424 425 426
			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');
427
		}
428 429
	}

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

E
Erich Gamma 已提交
433
		// Services we contribute
434
		serviceCollection.set(IPartService, this);
E
Erich Gamma 已提交
435

436
		// Clipboard
J
Johannes Rieken 已提交
437
		serviceCollection.set(IClipboardService, new SyncDescriptor(ClipboardService));
438

439 440 441 442
		// Status bar
		this.statusbarPart = this.instantiationService.createInstance(StatusbarPart, Identifiers.STATUSBAR_PART);
		serviceCollection.set(IStatusbarService, this.statusbarPart);

443 444 445
		// Progress 2
		serviceCollection.set(IProgressService2, new SyncDescriptor(ProgressService2));

446
		// Keybindings
A
Alex Dima 已提交
447
		this.contextKeyService = this.instantiationService.createInstance(ContextKeyService);
448
		serviceCollection.set(IContextKeyService, this.contextKeyService);
449

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

453 454 455
		// List
		serviceCollection.set(IListService, this.instantiationService.createInstance(ListService));

J
Joao Moreno 已提交
456
		// Context view service
B
Benjamin Pasero 已提交
457
		this.contextViewService = this.instantiationService.createInstance(ContextViewService, this.workbench);
J
Joao Moreno 已提交
458 459
		serviceCollection.set(IContextViewService, this.contextViewService);

S
SteVen Batten 已提交
460
		// Use themable context menus when custom titlebar is enabled to match custom menubar
B
Benjamin Pasero 已提交
461
		if (!isMacintosh && this.useCustomTitleBarStyle()) {
J
fix npe  
Johannes Rieken 已提交
462
			serviceCollection.set(IContextMenuService, new SyncDescriptor(HTMLContextMenuService, [null]));
S
SteVen Batten 已提交
463 464 465
		} else {
			serviceCollection.set(IContextMenuService, new SyncDescriptor(NativeContextMenuService));
		}
466

467 468
		// Menus/Actions
		serviceCollection.set(IMenuService, new SyncDescriptor(MenuService));
469

P
Pine Wu 已提交
470
		// Sidebar part
471
		this.sidebarPart = this.instantiationService.createInstance(SidebarPart, Identifiers.SIDEBAR_PART);
P
Pine Wu 已提交
472 473

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

I
isidor 已提交
476
		// Panel service (panel part)
477 478
		this.panelPart = this.instantiationService.createInstance(PanelPart, Identifiers.PANEL_PART);
		serviceCollection.set(IPanelService, this.panelPart);
I
isidor 已提交
479

480 481 482
		// views service
		const viewsService = this.instantiationService.createInstance(ViewsService);
		serviceCollection.set(IViewsService, viewsService);
S
Sandeep Somavarapu 已提交
483

E
Erich Gamma 已提交
484
		// Activity service (activitybar part)
485
		this.activitybarPart = this.instantiationService.createInstance(ActivitybarPart, Identifiers.ACTIVITYBAR_PART);
I
isidor 已提交
486 487
		const activityService = this.instantiationService.createInstance(ActivityService, this.activitybarPart, this.panelPart);
		serviceCollection.set(IActivityService, activityService);
E
Erich Gamma 已提交
488

489 490 491
		// File Service
		this.fileService = this.instantiationService.createInstance(RemoteFileService);
		serviceCollection.set(IFileService, this.fileService);
S
#47154  
Sandeep Somavarapu 已提交
492
		this.configurationService.acquireFileService(this.fileService);
A
Alex Dima 已提交
493
		this.themeService.acquireFileService(this.fileService);
494

495 496
		// Editor and Group services
		const restorePreviousEditorState = !this.hasInitialFilesToOpen;
497
		this.editorPart = this.instantiationService.createInstance(EditorPart, Identifiers.EDITOR_PART, restorePreviousEditorState);
B
Benjamin Pasero 已提交
498
		this.editorGroupService = this.editorPart;
499 500 501
		serviceCollection.set(IEditorGroupsService, this.editorPart);
		this.editorService = this.instantiationService.createInstance(EditorService);
		serviceCollection.set(IEditorService, this.editorService);
E
Erich Gamma 已提交
502

503 504 505
		// Title bar
		this.titlebarPart = this.instantiationService.createInstance(TitlebarPart, Identifiers.TITLEBAR_PART);
		serviceCollection.set(ITitleService, this.titlebarPart);
B
Benjamin Pasero 已提交
506

507
		// History
508
		serviceCollection.set(IHistoryService, new SyncDescriptor(HistoryService));
509

M
Martin Aeschlimann 已提交
510
		// File Dialogs
511
		serviceCollection.set(IFileDialogService, new SyncDescriptor(FileDialogService));
M
Martin Aeschlimann 已提交
512

513
		// Backup File Service
B
Benjamin Pasero 已提交
514 515 516 517 518
		if (this.workbenchParams.configuration.backupPath) {
			this.backupFileService = this.instantiationService.createInstance(BackupFileService, this.workbenchParams.configuration.backupPath);
		} else {
			this.backupFileService = new InMemoryBackupFileService();
		}
519
		serviceCollection.set(IBackupFileService, this.backupFileService);
520

521
		// Text File Service
522
		serviceCollection.set(ITextFileService, new SyncDescriptor(TextFileService));
523

524
		// File Decorations
J
Johannes Rieken 已提交
525
		serviceCollection.set(IDecorationsService, new SyncDescriptor(FileDecorationsService));
526

J
Joao Moreno 已提交
527
		// Inactive extension URL handler
J
Joao Moreno 已提交
528
		serviceCollection.set(IExtensionUrlHandler, new SyncDescriptor(ExtensionUrlHandler));
J
Joao Moreno 已提交
529

B
Benjamin Pasero 已提交
530
		// Text Model Resolver Service
531
		serviceCollection.set(ITextModelService, new SyncDescriptor(TextModelResolverService));
B
Benjamin Pasero 已提交
532

533 534 535 536
		// JSON Editing
		const jsonEditingService = this.instantiationService.createInstance(JSONEditingService);
		serviceCollection.set(IJSONEditingService, jsonEditingService);

537 538 539
		// Workspace Editing
		serviceCollection.set(IWorkspaceEditingService, new SyncDescriptor(WorkspaceEditingService));

540 541 542
		// Keybinding Editing
		serviceCollection.set(IKeybindingEditingService, this.instantiationService.createInstance(KeybindingsEditingService));

543
		// Configuration Resolver
544
		serviceCollection.set(IConfigurationResolverService, new SyncDescriptor(ConfigurationResolverService, [process.env]));
545

E
Erich Gamma 已提交
546
		// Quick open service (quick open controller)
547 548
		this.quickOpen = this.instantiationService.createInstance(QuickOpenController);
		serviceCollection.set(IQuickOpenService, this.quickOpen);
549

C
Christof Marti 已提交
550 551 552 553
		// Quick input service
		this.quickInput = this.instantiationService.createInstance(QuickInputService);
		serviceCollection.set(IQuickInputService, this.quickInput);

S
Sandeep Somavarapu 已提交
554 555 556
		// PreferencesService
		serviceCollection.set(IPreferencesService, this.instantiationService.createInstance(PreferencesService));

B
polish  
Benjamin Pasero 已提交
557
		// Contributed services
B
Benjamin Pasero 已提交
558
		const contributedServices = getServices();
E
Erich Gamma 已提交
559
		for (let contributedService of contributedServices) {
560
			serviceCollection.set(contributedService.id, contributedService.descriptor);
E
Erich Gamma 已提交
561 562 563
		}

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

568
		this.instantiationService.createInstance(DefaultConfigurationExportHelper);
569

S
#47154  
Sandeep Somavarapu 已提交
570
		this.configurationService.acquireInstantiationService(this.getInstantiationService());
E
Erich Gamma 已提交
571 572
	}

573
	//#region event handling
E
Erich Gamma 已提交
574

575
	private registerListeners(): void {
I
isidor 已提交
576

577
		// Storage
578
		this._register(this.storageService.onWillSaveState(e => this.saveState(e)));
579

580
		// Listen to visible editor changes
581
		this._register(this.editorService.onDidVisibleEditorsChange(() => this.onDidVisibleEditorsChange()));
B
Benjamin Pasero 已提交
582

583 584 585
		// Listen to editor group activations when editor is hidden
		this._register(this.editorPart.onDidActivateGroup(() => { if (this.editorHidden) { this.setEditorHidden(false); } }));

586 587 588
		// Listen to editor closing (if we run with --wait)
		const filesToWait = this.workbenchParams.configuration.filesToWait;
		if (filesToWait) {
589
			const resourcesToWaitFor = filesToWait.paths.map(p => p.fileUri);
590
			const waitMarkerFile = URI.file(filesToWait.waitMarkerFilePath);
591
			const listenerDispose = this.editorService.onDidCloseEditor(() => this.onEditorClosed(listenerDispose, resourcesToWaitFor, waitMarkerFile));
I
isidor 已提交
592

593
			this._register(listenerDispose);
594
		}
S
Sanders Lauture 已提交
595

596
		// Configuration changes
597
		this._register(this.configurationService.onDidChangeConfiguration(() => this.onDidUpdateConfiguration()));
I
isidor 已提交
598

599
		// Fullscreen changes
600
		this._register(onDidChangeFullscreen(() => this.onFullscreenChanged()));
B
Benjamin Pasero 已提交
601 602 603 604

		// Group changes
		this._register(this.editorGroupService.onDidAddGroup(() => this.centerEditorLayout(this.shouldCenterLayout)));
		this._register(this.editorGroupService.onDidRemoveGroup(() => this.centerEditorLayout(this.shouldCenterLayout)));
605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630

		// Layout
		this._register(addDisposableListener(window, EventType.RESIZE, e => this.onWindowResize(e, true)));

		// Prevent workbench from scrolling #55456
		this._register(addDisposableListener(this.workbench, EventType.SCROLL, () => {
			this.workbench.scrollTop = 0;
		}));
	}

	private onWindowResize(e: any, retry: boolean): void {
		if (e.target === window) {
			if (window.document && window.document.body && window.document.body.clientWidth === 0) {
				// TODO@Ben this is an electron issue on macOS when simple fullscreen is enabled
				// where for some reason the window clientWidth is reported as 0 when switching
				// between simple fullscreen and normal screen. In that case we schedule the layout
				// call at the next animation frame once, in the hope that the dimensions are
				// proper then.
				if (retry) {
					scheduleAtNextAnimationFrame(() => this.onWindowResize(e, false));
				}
				return;
			}

			this.layout();
		}
631
	}
632

633
	private onFullscreenChanged(): void {
S
SrTobi 已提交
634

635
		// Apply as CSS class
636 637
		if (isFullscreen()) {
			addClass(this.workbench, 'fullscreen');
638
		} else {
639
			removeClass(this.workbench, 'fullscreen');
B
Benjamin Pasero 已提交
640

641 642 643 644
			if (this.zenMode.transitionedToFullScreen && this.zenMode.active) {
				this.toggleZenMode();
			}
		}
E
Erich Gamma 已提交
645

646
		// Changing fullscreen state of the window has an impact on custom title bar visibility, so we need to update
B
Benjamin Pasero 已提交
647
		if (this.useCustomTitleBarStyle()) {
648 649 650
			this._onTitleBarVisibilityChange.fire();
			this.layout(); // handle title bar when fullscreen changes
		}
651 652
	}

653 654 655 656
	private onMenubarToggled(visible: boolean) {
		if (visible !== this.menubarToggled) {
			this.menubarToggled = visible;

657
			if (isFullscreen() && (this.menubarVisibility === 'toggle' || this.menubarVisibility === 'default')) {
658
				this._onTitleBarVisibilityChange.fire();
659 660 661 662 663
				this.layout();
			}
		}
	}

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

666 667 668
		// 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.
669
		if (resourcesToWaitFor.every(resource => !this.editorService.isOpen({ resource }))) {
670
			listenerDispose.dispose();
671
			this.fileService.del(waitMarkerFile);
672
		}
E
Erich Gamma 已提交
673 674
	}

675
	private onDidVisibleEditorsChange(): void {
676
		const visibleEditors = this.editorService.visibleControls;
E
Erich Gamma 已提交
677

678 679 680 681 682 683 684 685 686
		// 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();
			}
		}
687 688 689 690

		if (this.editorHidden) {
			this.setEditorHidden(false);
		}
691 692
	}

693
	private onAllEditorsClosed(): void {
694
		const visibleEditors = this.editorService.visibleControls.length;
695 696
		if (visibleEditors === 0) {
			this.windowService.closeWindow();
E
Erich Gamma 已提交
697 698 699
		}
	}

700 701 702 703 704
	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);
705
		}
E
Erich Gamma 已提交
706

707
		this.setPanelPositionFromStorageOrConfig();
E
Erich Gamma 已提交
708

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

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

720 721 722 723
			const newActivityBarHiddenValue = !this.configurationService.getValue<boolean>(Workbench.activityBarVisibleConfigurationKey);
			if (newActivityBarHiddenValue !== this.activityBarHidden) {
				this.setActivityBarHidden(newActivityBarHiddenValue, skipLayout);
			}
B
Benjamin Pasero 已提交
724
		}
S
SteVen Batten 已提交
725

726
		const newMenubarVisibility = this.configurationService.getValue<MenuBarVisibility>(Workbench.menubarVisibilityConfigurationKey);
S
SteVen Batten 已提交
727
		this.setMenubarVisibility(newMenubarVisibility, skipLayout);
728
	}
B
Benjamin Pasero 已提交
729

730
	//#endregion
B
Benjamin Pasero 已提交
731

732 733
	private handleContextKeys(): void {
		this.inZenMode = InEditorZenModeContext.bindTo(this.contextKeyService);
734

I
isidor 已提交
735 736 737
		IsMacContext.bindTo(this.contextKeyService);
		IsLinuxContext.bindTo(this.contextKeyService);
		IsWindowsContext.bindTo(this.contextKeyService);
A
Alex Ross 已提交
738 739 740 741 742 743
		const supportsOpenFileFolderContextKey = SupportsOpenFileFolderContext.bindTo(this.contextKeyService);
		const supportsWorkspacesContextKey = SupportsWorkspacesContext.bindTo(this.contextKeyService);
		if (this.windowService.getConfiguration().remoteAuthority) {
			supportsOpenFileFolderContextKey.set(true);
			supportsWorkspacesContextKey.set(false);
		}
744

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

748
		const activeEditorContext = ActiveEditorContext.bindTo(this.contextKeyService);
749 750
		const editorsVisibleContext = EditorsVisibleContext.bindTo(this.contextKeyService);
		const textCompareEditorVisible = TextCompareEditorVisibleContext.bindTo(this.contextKeyService);
751
		const textCompareEditorActive = TextCompareEditorActiveContext.bindTo(this.contextKeyService);
752 753
		const activeEditorGroupEmpty = ActiveEditorGroupEmptyContext.bindTo(this.contextKeyService);
		const multipleEditorGroups = MultipleEditorGroupsContext.bindTo(this.contextKeyService);
754

755
		const updateEditorContextKeys = () => {
756
			const activeControl = this.editorService.activeControl;
757
			const visibleEditors = this.editorService.visibleControls;
E
Erich Gamma 已提交
758

759
			textCompareEditorActive.set(activeControl && activeControl.getId() === TEXT_DIFF_EDITOR_ID);
760
			textCompareEditorVisible.set(visibleEditors.some(control => control.getId() === TEXT_DIFF_EDITOR_ID));
I
isidor 已提交
761

762 763 764 765
			if (visibleEditors.length > 0) {
				editorsVisibleContext.set(true);
			} else {
				editorsVisibleContext.reset();
766
			}
B
Benjamin Pasero 已提交
767

768
			if (!this.editorService.activeEditor) {
769 770 771
				activeEditorGroupEmpty.set(true);
			} else {
				activeEditorGroupEmpty.reset();
772
			}
773

B
Benjamin Pasero 已提交
774
			if (this.editorGroupService.count > 1) {
775 776 777 778
				multipleEditorGroups.set(true);
			} else {
				multipleEditorGroups.reset();
			}
779 780 781 782 783 784

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

787
		this.editorPart.whenRestored.then(() => updateEditorContextKeys());
788 789
		this._register(this.editorService.onDidActiveEditorChange(() => updateEditorContextKeys()));
		this._register(this.editorService.onDidVisibleEditorsChange(() => updateEditorContextKeys()));
B
Benjamin Pasero 已提交
790 791
		this._register(this.editorGroupService.onDidAddGroup(() => updateEditorContextKeys()));
		this._register(this.editorGroupService.onDidRemoveGroup(() => updateEditorContextKeys()));
792

793
		const inputFocused = InputFocusedContext.bindTo(this.contextKeyService);
B
Benjamin Pasero 已提交
794 795 796 797 798 799 800 801 802 803

		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) {
804
				const tracker = trackFocus(document.activeElement as HTMLElement);
J
Joao Moreno 已提交
805
				Event.once(tracker.onDidBlur)(() => {
B
Benjamin Pasero 已提交
806 807 808 809 810 811 812
					inputFocused.set(activeElementIsInput());

					tracker.dispose();
				});
			}
		}

813
		this._register(addDisposableListener(window, 'focusin', () => trackInputFocus(), true));
814 815 816 817 818 819

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

821 822 823 824 825
		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);
		}));
826

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

829 830 831 832
		const updateSplitEditorsVerticallyContext = () => {
			const direction = preferredSideBySideGroupDirection(this.configurationService);
			splitEditorsVerticallyContext.set(direction === GroupDirection.DOWN);
		};
S
Sanders Lauture 已提交
833

834 835 836 837 838
		this._register(this.configurationService.onDidChangeConfiguration(e => {
			if (e.affectsConfiguration('workbench.editor.openSideBySideDirection')) {
				updateSplitEditorsVerticallyContext();
			}
		}));
E
Erich Gamma 已提交
839

840
		updateSplitEditorsVerticallyContext();
841
	}
E
Erich Gamma 已提交
842

843
	private restoreParts(): Promise<void> {
J
Johannes Rieken 已提交
844
		const restorePromises: Promise<any>[] = [];
B
Benjamin Pasero 已提交
845

846
		// Restore Editorpart
847
		mark('willRestoreEditors');
848
		restorePromises.push(this.editorPart.whenRestored.then(() => {
B
Benjamin Pasero 已提交
849 850 851 852

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

J
Johannes Rieken 已提交
855
				return Promise.resolve(undefined);
B
Benjamin Pasero 已提交
856 857 858 859 860 861 862 863 864
			}

			const editorsToOpen = this.resolveEditorsToOpen();

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

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

867 868 869 870
		// Restore Sidebar
		let viewletIdToRestore: string;
		if (!this.sideBarHidden) {
			this.sideBarVisibleContext.set(true);
871

872
			if (this.shouldRestoreLastOpenedViewlet()) {
873
				viewletIdToRestore = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE);
874
			}
875

876
			if (!viewletIdToRestore) {
I
isidor 已提交
877
				viewletIdToRestore = this.sidebarPart.getDefaultViewletId();
878
			}
E
Erich Gamma 已提交
879

880
			mark('willRestoreViewlet');
I
isidor 已提交
881 882
			restorePromises.push(this.sidebarPart.openViewlet(viewletIdToRestore)
				.then(viewlet => viewlet || this.sidebarPart.openViewlet(this.sidebarPart.getDefaultViewletId()))
883
				.then(() => mark('didRestoreViewlet')));
884 885
		}

886 887
		// Restore Panel
		const panelRegistry = Registry.as<PanelRegistry>(PanelExtensions.Panels);
888
		const panelId = this.storageService.get(PanelPart.activePanelSettingsKey, StorageScope.WORKSPACE, panelRegistry.getDefaultPanelId());
889
		if (!this.panelHidden && !!panelId) {
890
			mark('willRestorePanel');
891
			const isPanelToRestoreEnabled = !!this.panelPart.getPanels().filter(p => p.id === panelId).length;
892
			const panelIdToRestore = isPanelToRestoreEnabled ? panelId : panelRegistry.getDefaultPanelId();
893
			this.panelPart.openPanel(panelIdToRestore, false);
894
			mark('didRestorePanel');
I
isidor 已提交
895 896
		}

897 898 899
		// 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);
900
		if (wasZenActive && zenConfig.restore) {
I
isidor 已提交
901
			this.toggleZenMode(true, true);
I
isidor 已提交
902 903
		}

B
Benjamin Pasero 已提交
904
		// Restore Forced Editor Center Mode
905
		if (this.storageService.getBoolean(Workbench.centeredEditorLayoutActiveStorageKey, StorageScope.WORKSPACE, false)) {
I
isidor 已提交
906
			this.centerEditorLayout(true);
S
SrTobi 已提交
907
		}
908

909
		const onRestored = (error?: Error): void => {
B
Benjamin Pasero 已提交
910 911 912 913 914
			this.workbenchRestored = true;

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

915 916 917 918 919 920 921
			// 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);
922

923
			if (error) {
924
				onUnexpectedError(error);
925
			}
I
isidor 已提交
926

927
			this.logStartupTelemetry({
928
				customKeybindingsCount: this.keybindingService.customKeybindingsCount(),
P
Pine Wu 已提交
929
				pinnedViewlets: this.activitybarPart.getPinnedViewletIds(),
930
				restoredViewlet: viewletIdToRestore,
931
				restoredEditorsCount: this.editorService.visibleEditors.length
932
			});
933
		};
934

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

938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981
	private logStartupTelemetry(info: IWorkbenchStartedInfo): void {
		const { filesToOpen, filesToCreate, filesToDiff } = this.configuration;

		/* __GDPR__
			"workspaceLoad" : {
				"userAgent" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
				"windowSize.innerHeight": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
				"windowSize.innerWidth": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
				"windowSize.outerHeight": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
				"windowSize.outerWidth": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
				"emptyWorkbench": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
				"workbench.filesToOpen": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
				"workbench.filesToCreate": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
				"workbench.filesToDiff": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
				"customKeybindingsCount": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
				"theme": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
				"language": { "classification": "SystemMetaData", "purpose": "BusinessInsight" },
				"pinnedViewlets": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
				"restoredViewlet": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
				"restoredEditors": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
				"pinnedViewlets": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
				"startupKind": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }
			}
		*/
		this.telemetryService.publicLog('workspaceLoad', {
			userAgent: navigator.userAgent,
			windowSize: { innerHeight: window.innerHeight, innerWidth: window.innerWidth, outerHeight: window.outerHeight, outerWidth: window.outerWidth },
			emptyWorkbench: this.contextService.getWorkbenchState() === WorkbenchState.EMPTY,
			'workbench.filesToOpen': filesToOpen && filesToOpen.length || 0,
			'workbench.filesToCreate': filesToCreate && filesToCreate.length || 0,
			'workbench.filesToDiff': filesToDiff && filesToDiff.length || 0,
			customKeybindingsCount: info.customKeybindingsCount,
			theme: this.themeService.getColorTheme().id,
			language,
			pinnedViewlets: info.pinnedViewlets,
			restoredViewlet: info.restoredViewlet,
			restoredEditors: info.restoredEditorsCount,
			startupKind: this.lifecycleService.startupKind
		});

		// Telemetry: startup metrics
		mark('didStartWorkbench');
	}

982 983 984
	private shouldRestoreLastOpenedViewlet(): boolean {
		if (!this.environmentService.isBuilt) {
			return true; // always restore sidebar when we are in development mode
E
Erich Gamma 已提交
985 986
		}

987 988
		// always restore sidebar when the window was reloaded
		return this.lifecycleService.startupKind === StartupKind.ReloadedWindow;
E
Erich Gamma 已提交
989 990
	}

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

B
Benjamin Pasero 已提交
994
		// Files to open, diff or create
995
		if (this.hasInitialFilesToOpen) {
I
isidor 已提交
996

B
Benjamin Pasero 已提交
997
			// Files to diff is exclusive
998
			const filesToDiff = this.toInputs(config.filesToDiff, false);
999
			if (filesToDiff && filesToDiff.length === 2) {
B
Benjamin Pasero 已提交
1000
				return [<IResourceDiffInput>{
1001 1002
					leftResource: filesToDiff[0].resource,
					rightResource: filesToDiff[1].resource,
B
Benjamin Pasero 已提交
1003
					options: { pinned: true },
B
Benjamin Pasero 已提交
1004
					forceFile: true
B
Benjamin Pasero 已提交
1005
				}];
B
Benjamin Pasero 已提交
1006
			}
I
isidor 已提交
1007

1008 1009
			const filesToCreate = this.toInputs(config.filesToCreate, true);
			const filesToOpen = this.toInputs(config.filesToOpen, false);
I
isidor 已提交
1010

1011
			// Otherwise: Open/Create files
B
Benjamin Pasero 已提交
1012
			return [...filesToOpen, ...filesToCreate];
B
Benjamin Pasero 已提交
1013
		}
I
isidor 已提交
1014

1015
		// Empty workbench
1016
		else if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY && this.openUntitledFile()) {
B
Benjamin Pasero 已提交
1017
			const isEmpty = this.editorGroupService.count === 1 && this.editorGroupService.activeGroup.count === 0;
1018
			if (!isEmpty) {
B
Benjamin Pasero 已提交
1019
				return []; // do not open any empty untitled file if we restored editors from previous session
1020
			}
B
Benjamin Pasero 已提交
1021

1022 1023
			return this.backupFileService.hasBackups().then(hasBackups => {
				if (hasBackups) {
B
Benjamin Pasero 已提交
1024
					return []; // do not open any empty untitled file if we have backups to restore
1025
				}
B
Benjamin Pasero 已提交
1026

B
Benjamin Pasero 已提交
1027
				return [<IUntitledResourceInput>{}];
1028
			});
1029
		}
1030

B
Benjamin Pasero 已提交
1031
		return [];
B
Benjamin Pasero 已提交
1032
	}
1033

1034
	private toInputs(paths: IPath[], isNew: boolean): Array<IResourceInput | IUntitledResourceInput> {
B
Benjamin Pasero 已提交
1035 1036
		if (!paths || !paths.length) {
			return [];
1037
		}
I
isidor 已提交
1038

B
Benjamin Pasero 已提交
1039
		return paths.map(p => {
1040
			const resource = p.fileUri;
1041 1042 1043 1044
			let input: IResourceInput | IUntitledResourceInput;
			if (isNew) {
				input = { filePath: resource.fsPath, options: { pinned: true } } as IUntitledResourceInput;
			} else {
B
Benjamin Pasero 已提交
1045
				input = { resource, options: { pinned: true }, forceFile: true } as IResourceInput;
1046
			}
E
Erich Gamma 已提交
1047

1048
			if (!isNew && p.lineNumber) {
B
Benjamin Pasero 已提交
1049 1050 1051 1052 1053
				input.options.selection = {
					startLineNumber: p.lineNumber,
					startColumn: p.columnNumber
				};
			}
1054

B
Benjamin Pasero 已提交
1055 1056
			return input;
		});
1057 1058
	}

1059
	private openUntitledFile() {
1060
		const startupEditor = this.configurationService.inspect('workbench.startupEditor');
B
Benjamin Pasero 已提交
1061 1062

		// Fallback to previous workbench.welcome.enabled setting in case startupEditor is not defined
1063
		if (!startupEditor.user && !startupEditor.workspace) {
1064 1065 1066
			const welcomeEnabledValue = this.configurationService.getValue('workbench.welcome.enabled');
			if (typeof welcomeEnabledValue === 'boolean') {
				return !welcomeEnabledValue;
1067
			}
1068
		}
E
Erich Gamma 已提交
1069

1070
		return startupEditor.value === 'newUntitledFile';
1071
	}
E
Erich Gamma 已提交
1072 1073

	private initSettings(): void {
1074

S
SteVen Batten 已提交
1075 1076 1077
		// Editor visiblity
		this.editorHidden = false;

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

I
isidor 已提交
1081
		// Panel part visibility
1082
		const panelRegistry = Registry.as<PanelRegistry>(PanelExtensions.Panels);
1083
		this.panelHidden = this.storageService.getBoolean(Workbench.panelHiddenStorageKey, StorageScope.WORKSPACE, true);
1084 1085
		if (!panelRegistry.getDefaultPanelId()) {
			this.panelHidden = true; // we hide panel part if there is no default panel
1086 1087
		}

E
Erich Gamma 已提交
1088
		// Sidebar position
1089
		const sideBarPosition = this.configurationService.getValue<string>(Workbench.sidebarPositionConfigurationKey);
1090
		this.sideBarPosition = (sideBarPosition === 'right') ? Position.RIGHT : Position.LEFT;
1091

I
isidor 已提交
1092
		// Panel position
1093
		this.setPanelPositionFromStorageOrConfig();
1094

1095
		// Menubar visibility
1096
		const menuBarVisibility = this.configurationService.getValue<MenuBarVisibility>(Workbench.menubarVisibilityConfigurationKey);
S
SteVen Batten 已提交
1097
		this.setMenubarVisibility(menuBarVisibility, true);
1098

B
Benjamin Pasero 已提交
1099
		// Statusbar visibility
1100
		const statusBarVisible = this.configurationService.getValue<string>(Workbench.statusbarVisibleConfigurationKey);
1101
		this.statusBarHidden = !statusBarVisible;
1102

S
Sanders Lauture 已提交
1103
		// Activity bar visibility
1104
		const activityBarVisible = this.configurationService.getValue<string>(Workbench.activityBarVisibleConfigurationKey);
S
Sanders Lauture 已提交
1105
		this.activityBarHidden = !activityBarVisible;
1106

1107
		// Font aliasing
1108
		this.fontAliasing = this.configurationService.getValue<FontAliasingOption>(Workbench.fontAliasingConfigurationKey);
1109

I
isidor 已提交
1110 1111
		// Zen mode
		this.zenMode = {
I
isidor 已提交
1112
			active: false,
1113
			transitionedToFullScreen: false,
1114
			transitionedToCenteredEditorLayout: false,
1115
			wasSideBarVisible: false,
1116 1117
			wasPanelVisible: false,
			transitionDisposeables: []
I
isidor 已提交
1118
		};
E
Erich Gamma 已提交
1119 1120
	}

1121 1122
	private setPanelPositionFromStorageOrConfig() {
		const defaultPanelPosition = this.configurationService.getValue<string>(Workbench.defaultPanelPositionStorageKey);
1123
		const panelPosition = this.storageService.get(Workbench.panelPositionStorageKey, StorageScope.WORKSPACE, defaultPanelPosition);
1124

1125 1126
		this.panelPosition = (panelPosition === 'right') ? Position.RIGHT : Position.BOTTOM;
	}
1127

B
Benjamin Pasero 已提交
1128 1129
	private useCustomTitleBarStyle(): boolean {
		return getTitleBarStyle(this.configurationService, this.environmentService) === 'custom';
B
Benjamin Pasero 已提交
1130 1131
	}

1132
	private saveLastPanelDimension(): void {
S
SteVen Batten 已提交
1133
		if (!(this.workbenchGrid instanceof Grid)) {
1134 1135 1136 1137
			return;
		}

		if (this.panelPosition === Position.BOTTOM) {
S
SteVen Batten 已提交
1138
			this.uiState.lastPanelHeight = this.workbenchGrid.getViewSize(this.panelPartView);
1139
		} else {
S
SteVen Batten 已提交
1140
			this.uiState.lastPanelWidth = this.workbenchGrid.getViewSize(this.panelPartView);
1141 1142 1143 1144 1145 1146 1147
		}
	}

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

1148 1149
	private setStatusBarHidden(hidden: boolean, skipLayout?: boolean): void {
		this.statusBarHidden = hidden;
B
Benjamin Pasero 已提交
1150

1151 1152
		// Adjust CSS
		if (hidden) {
1153
			addClass(this.workbench, 'nostatusbar');
E
Erich Gamma 已提交
1154
		} else {
1155
			removeClass(this.workbench, 'nostatusbar');
E
Erich Gamma 已提交
1156 1157
		}

1158 1159
		// Layout
		if (!skipLayout) {
S
SteVen Batten 已提交
1160
			if (this.workbenchGrid instanceof Grid) {
S
SteVen Batten 已提交
1161
				this.layout();
1162 1163 1164
			} else {
				this.workbenchGrid.layout();
			}
1165 1166 1167
		}
	}

1168
	private setFontAliasing(aliasing: FontAliasingOption) {
1169
		this.fontAliasing = aliasing;
S
Sanders Lauture 已提交
1170

B
Benjamin Pasero 已提交
1171 1172 1173 1174 1175
		// Remove all
		document.body.classList.remove(...fontAliasingValues.map(value => `monaco-font-aliasing-${value}`));

		// Add specific
		if (fontAliasingValues.some(option => option === aliasing)) {
1176
			document.body.classList.add(`monaco-font-aliasing-${aliasing}`);
S
Sanders Lauture 已提交
1177
		}
1178 1179
	}

E
Erich Gamma 已提交
1180
	private createWorkbenchLayout(): void {
1181
		if (this.configurationService.getValue('workbench.useExperimentalGridLayout')) {
1182

S
SteVen Batten 已提交
1183 1184 1185 1186 1187 1188 1189 1190 1191
			// Create view wrappers for all parts
			this.titlebarPartView = new View(this.titlebarPart);
			this.sidebarPartView = new View(this.sidebarPart);
			this.activitybarPartView = new View(this.activitybarPart);
			this.editorPartView = new View(this.editorPart);
			this.panelPartView = new View(this.panelPart);
			this.statusbarPartView = new View(this.statusbarPart);

			this.workbenchGrid = new Grid(this.editorPartView, { proportionalLayout: false });
1192

1193
			this.workbench.prepend(this.workbenchGrid.element);
1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212
		} 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 已提交
1213 1214 1215 1216 1217 1218
	}

	private renderWorkbench(): void {

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

1222
		if (this.panelHidden) {
1223
			addClass(this.workbench, 'nopanel');
1224
		}
B
Benjamin Pasero 已提交
1225

1226
		if (this.statusBarHidden) {
1227
			addClass(this.workbench, 'nostatusbar');
1228
		}
E
Erich Gamma 已提交
1229

B
Benjamin Pasero 已提交
1230
		// Apply font aliasing
1231 1232
		this.setFontAliasing(this.fontAliasing);

1233
		// Apply fullscreen state
1234 1235
		if (isFullscreen()) {
			addClass(this.workbench, 'fullscreen');
B
Benjamin Pasero 已提交
1236 1237
		}

E
Erich Gamma 已提交
1238
		// Create Parts
B
Benjamin Pasero 已提交
1239
		this.createTitlebarPart();
E
Erich Gamma 已提交
1240 1241 1242
		this.createActivityBarPart();
		this.createSidebarPart();
		this.createEditorPart();
1243
		this.createPanelPart();
E
Erich Gamma 已提交
1244 1245
		this.createStatusbarPart();

1246 1247
		// Notification Handlers
		this.createNotificationsHandlers();
1248

1249 1250

		// Menubar visibility changes
B
Benjamin Pasero 已提交
1251
		if ((isWindows || isLinux) && this.useCustomTitleBarStyle()) {
1252 1253 1254
			this.titlebarPart.onMenubarVisibilityChange()(e => this.onMenubarToggled(e));
		}

E
Erich Gamma 已提交
1255
		// Add Workbench to DOM
B
Benjamin Pasero 已提交
1256
		this.container.appendChild(this.workbench);
E
Erich Gamma 已提交
1257 1258
	}

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

B
Benjamin Pasero 已提交
1262
		this.titlebarPart.create(titlebarContainer);
B
Benjamin Pasero 已提交
1263 1264
	}

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

B
Benjamin Pasero 已提交
1268
		this.activitybarPart.create(activitybarPartContainer);
E
Erich Gamma 已提交
1269 1270 1271
	}

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

B
Benjamin Pasero 已提交
1274
		this.sidebarPart.create(sidebarPartContainer);
E
Erich Gamma 已提交
1275 1276
	}

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

B
Benjamin Pasero 已提交
1280
		this.panelPart.create(panelPartContainer);
I
isidor 已提交
1281 1282
	}

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

B
Benjamin Pasero 已提交
1286
		this.editorPart.create(editorContainer);
E
Erich Gamma 已提交
1287 1288 1289
	}

	private createStatusbarPart(): void {
B
Benjamin Pasero 已提交
1290 1291 1292 1293 1294 1295 1296
		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');
1297
		classes.forEach(clazz => addClass(part, clazz));
B
Benjamin Pasero 已提交
1298 1299 1300
		part.id = id;
		part.setAttribute('role', role);

1301 1302 1303 1304 1305
		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 已提交
1306

B
Benjamin Pasero 已提交
1307
		return part;
E
Erich Gamma 已提交
1308 1309
	}

1310 1311
	private createNotificationsHandlers(): void {

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

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

1318
		// Notifications Alerts
1319
		this._register(this.instantiationService.createInstance(NotificationsAlerts, this.notificationService.model));
1320 1321 1322 1323

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

1324
		// Eventing
1325
		this._register(this.notificationsCenter.onDidChangeVisibility(() => {
1326 1327 1328 1329 1330 1331 1332 1333

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

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

1334
		// Register Commands
1335
		registerNotificationCommands(this.notificationsCenter, this.notificationsToasts);
1336 1337
	}

1338
	getInstantiationService(): IInstantiationService {
E
Erich Gamma 已提交
1339 1340 1341
		return this.instantiationService;
	}

1342
	private saveState(e: IWillSaveStateEvent): void {
1343
		if (this.zenMode.active) {
B
Benjamin Pasero 已提交
1344
			this.storageService.store(Workbench.zenModeActiveStorageKey, true, StorageScope.WORKSPACE);
1345
		} else {
B
Benjamin Pasero 已提交
1346
			this.storageService.remove(Workbench.zenModeActiveStorageKey, StorageScope.WORKSPACE);
1347
		}
1348 1349 1350 1351 1352 1353 1354 1355

		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);
			}
		}
1356 1357
	}

1358
	dispose(): void {
1359
		super.dispose();
1360 1361 1362 1363 1364 1365

		this.workbenchShutdown = true;
	}

	//#region IPartService

M
Matt Bierner 已提交
1366
	private readonly _onTitleBarVisibilityChange: Emitter<void> = this._register(new Emitter<void>());
1367
	get onTitleBarVisibilityChange(): Event<void> { return this._onTitleBarVisibilityChange.event; }
1368

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

B
Benjamin Pasero 已提交
1371 1372
	isRestored(): boolean {
		return !!(this.workbenchRestored && this.workbenchStarted);
1373
	}
1374

1375 1376 1377 1378 1379
	hasFocus(part: Parts): boolean {
		const activeElement = document.activeElement;
		if (!activeElement) {
			return false;
		}
1380

1381
		const container = this.getContainer(part);
1382
		return isAncestor(activeElement, container);
1383
	}
1384

1385
	getContainer(part: Parts): HTMLElement | null {
1386 1387
		switch (part) {
			case Parts.TITLEBAR_PART:
1388
				return this.titlebarPart.getContainer();
1389
			case Parts.ACTIVITYBAR_PART:
1390
				return this.activitybarPart.getContainer();
1391
			case Parts.SIDEBAR_PART:
1392
				return this.sidebarPart.getContainer();
1393
			case Parts.PANEL_PART:
1394
				return this.panelPart.getContainer();
1395
			case Parts.EDITOR_PART:
1396
				return this.editorPart.getContainer();
1397
			case Parts.STATUSBAR_PART:
1398
				return this.statusbarPart.getContainer();
1399
		}
1400

1401
		return null;
1402
	}
1403

1404 1405 1406
	isVisible(part: Parts): boolean {
		switch (part) {
			case Parts.TITLEBAR_PART:
B
Benjamin Pasero 已提交
1407
				if (!this.useCustomTitleBarStyle()) {
1408
					return false;
1409
				} else if (!isFullscreen()) {
1410 1411 1412 1413 1414 1415 1416 1417 1418 1419
					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;
1420 1421 1422 1423 1424 1425 1426 1427
			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;
1428 1429
			case Parts.EDITOR_PART:
				return this.workbenchGrid instanceof Grid ? !this.editorHidden : true;
E
Erich Gamma 已提交
1430
		}
1431

1432
		return true; // any other part cannot be hidden
E
Erich Gamma 已提交
1433 1434
	}

1435 1436 1437
	getTitleBarOffset(): number {
		let offset = 0;
		if (this.isVisible(Parts.TITLEBAR_PART)) {
S
SteVen Batten 已提交
1438 1439
			if (this.workbenchGrid instanceof Grid) {
				offset = this.gridHasView(this.titlebarPartView) ? this.workbenchGrid.getViewSize2(this.titlebarPartView).height : 0;
S
SteVen Batten 已提交
1440 1441 1442 1443
			} else {
				offset = this.workbenchGrid.partLayoutInfo.titlebar.height;
			}

1444
			if (isMacintosh || this.menubarVisibility === 'hidden') {
1445
				offset /= getZoomFactor();
1446
			}
E
Erich Gamma 已提交
1447
		}
1448 1449

		return offset;
E
Erich Gamma 已提交
1450
	}
1451

1452 1453
	getWorkbenchElement(): HTMLElement {
		return this.workbench;
1454
	}
1455

I
isidor 已提交
1456
	toggleZenMode(skipLayout?: boolean, restoring = false): void {
I
isidor 已提交
1457
		this.zenMode.active = !this.zenMode.active;
1458
		this.zenMode.transitionDisposeables = dispose(this.zenMode.transitionDisposeables);
1459

1460 1461
		// 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)
1462
		let toggleFullScreen = false;
I
isidor 已提交
1463 1464 1465 1466 1467 1468 1469 1470
		const setLineNumbers = (lineNumbers: any) => {
			this.editorService.visibleControls.forEach(editor => {
				const control = <IEditor>editor.getControl();
				if (control) {
					control.updateOptions({ lineNumbers });
				}
			});
		};
1471 1472

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

1476
			toggleFullScreen = !isFullscreen() && config.fullScreen;
I
isidor 已提交
1477
			this.zenMode.transitionedToFullScreen = restoring ? config.fullScreen : toggleFullScreen;
1478
			this.zenMode.transitionedToCenteredEditorLayout = !this.isEditorLayoutCentered() && config.centerLayout;
1479 1480
			this.zenMode.wasSideBarVisible = this.isVisible(Parts.SIDEBAR_PART);
			this.zenMode.wasPanelVisible = this.isVisible(Parts.PANEL_PART);
1481

1482 1483
			this.setPanelHidden(true, true);
			this.setSideBarHidden(true, true);
I
isidor 已提交
1484

1485 1486 1487
			if (config.hideActivityBar) {
				this.setActivityBarHidden(true, true);
			}
1488

I
isidor 已提交
1489
			if (config.hideStatusBar) {
I
isidor 已提交
1490 1491
				this.setStatusBarHidden(true, true);
			}
1492

I
isidor 已提交
1493 1494 1495 1496 1497
			if (config.hideLineNumbers) {
				setLineNumbers('off');
				this.zenMode.transitionDisposeables.push(this.editorService.onDidVisibleEditorsChange(() => setLineNumbers('off')));
			}

1498 1499
			if (config.hideTabs && this.editorPart.partOptions.showTabs) {
				this.zenMode.transitionDisposeables.push(this.editorPart.enforcePartOptions({ showTabs: false }));
I
isidor 已提交
1500
			}
1501 1502 1503 1504

			if (config.centerLayout) {
				this.centerEditorLayout(true, true);
			}
1505 1506 1507 1508
		}

		// Zen Mode Inactive
		else {
1509
			if (this.zenMode.wasPanelVisible) {
1510
				this.setPanelHidden(false, true);
1511
			}
1512

1513
			if (this.zenMode.wasSideBarVisible) {
1514
				this.setSideBarHidden(false, true);
1515
			}
1516

1517 1518 1519
			if (this.zenMode.transitionedToCenteredEditorLayout) {
				this.centerEditorLayout(false, true);
			}
I
isidor 已提交
1520
			setLineNumbers(this.configurationService.getValue('editor.lineNumbers'));
1521

1522 1523
			// Status bar and activity bar visibility come from settings -> update their visibility.
			this.onDidUpdateConfiguration(true);
1524

B
Benjamin Pasero 已提交
1525
			this.editorGroupService.activeGroup.focus();
1526

1527
			toggleFullScreen = this.zenMode.transitionedToFullScreen && isFullscreen();
I
isidor 已提交
1528
		}
1529

1530
		this.inZenMode.set(this.zenMode.active);
I
isidor 已提交
1531

I
isidor 已提交
1532
		if (!skipLayout) {
1533
			this.layout();
I
isidor 已提交
1534
		}
1535

1536
		if (toggleFullScreen) {
1537
			this.windowService.toggleFullScreen();
1538
		}
I
isidor 已提交
1539 1540
	}

S
SteVen Batten 已提交
1541 1542
	private gridHasView(view: View): boolean {
		if (!(this.workbenchGrid instanceof Grid)) {
S
SteVen Batten 已提交
1543 1544
			return false;
		}
1545

S
SteVen Batten 已提交
1546 1547 1548 1549 1550
		try {
			this.workbenchGrid.getViewSize(view);
			return true;
		} catch {
			return false;
1551 1552 1553
		}
	}

S
SteVen Batten 已提交
1554
	private updateGrid(): void {
S
SteVen Batten 已提交
1555
		if (!(this.workbenchGrid instanceof Grid)) {
1556 1557 1558
			return;
		}

S
SteVen Batten 已提交
1559 1560 1561 1562 1563
		let panelInGrid = this.gridHasView(this.panelPartView);
		let sidebarInGrid = this.gridHasView(this.sidebarPartView);
		let activityBarInGrid = this.gridHasView(this.activitybarPartView);
		let statusBarInGrid = this.gridHasView(this.statusbarPartView);
		let titlebarInGrid = this.gridHasView(this.titlebarPartView);
1564

S
SteVen Batten 已提交
1565 1566 1567
		// Add parts to grid
		if (!statusBarInGrid) {
			this.workbenchGrid.addView(this.statusbarPartView, Sizing.Split, this.editorPartView, Direction.Down);
S
SteVen Batten 已提交
1568 1569 1570
			statusBarInGrid = true;
		}

1571
		if (!titlebarInGrid && this.useCustomTitleBarStyle()) {
S
SteVen Batten 已提交
1572 1573 1574
			this.workbenchGrid.addView(this.titlebarPartView, Sizing.Split, this.editorPartView, Direction.Up);
			titlebarInGrid = true;
		}
S
SteVen Batten 已提交
1575

S
SteVen Batten 已提交
1576 1577 1578 1579
		if (!activityBarInGrid) {
			this.workbenchGrid.addView(this.activitybarPartView, Sizing.Split, panelInGrid && this.sideBarPosition === this.panelPosition ? this.panelPartView : this.editorPartView, this.sideBarPosition === Position.RIGHT ? Direction.Right : Direction.Left);
			activityBarInGrid = true;
		}
S
SteVen Batten 已提交
1580

S
SteVen Batten 已提交
1581 1582 1583 1584
		if (!sidebarInGrid) {
			this.workbenchGrid.addView(this.sidebarPartView, this.uiState.lastSidebarDimension !== undefined ? this.uiState.lastSidebarDimension : Sizing.Split, this.activitybarPartView, this.sideBarPosition === Position.LEFT ? Direction.Right : Direction.Left);
			sidebarInGrid = true;
		}
S
SteVen Batten 已提交
1585

S
SteVen Batten 已提交
1586 1587 1588
		if (!panelInGrid) {
			this.workbenchGrid.addView(this.panelPartView, this.getLastPanelDimension(this.panelPosition) !== undefined ? this.getLastPanelDimension(this.panelPosition) : Sizing.Split, this.editorPartView, this.panelPosition === Position.BOTTOM ? Direction.Down : Direction.Right);
			panelInGrid = true;
S
SteVen Batten 已提交
1589 1590
		}

S
SteVen Batten 已提交
1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615
		// Hide parts
		if (this.panelHidden) {
			this.panelPartView.hide();
		}

		if (this.statusBarHidden) {
			this.statusbarPartView.hide();
		}

		if (!this.isVisible(Parts.TITLEBAR_PART)) {
			this.titlebarPartView.hide();
		}

		if (this.activityBarHidden) {
			this.activitybarPartView.hide();
		}

		if (this.sideBarHidden) {
			this.sidebarPartView.hide();
		}

		if (this.editorHidden) {
			this.editorPartView.hide();
		}

S
SteVen Batten 已提交
1616
		// Show visible parts
S
SteVen Batten 已提交
1617 1618 1619 1620
		if (!this.editorHidden) {
			this.editorPartView.show();
		}

S
SteVen Batten 已提交
1621 1622 1623
		if (!this.statusBarHidden) {
			this.statusbarPartView.show();
		}
S
SteVen Batten 已提交
1624

S
SteVen Batten 已提交
1625 1626
		if (this.isVisible(Parts.TITLEBAR_PART)) {
			this.titlebarPartView.show();
S
SteVen Batten 已提交
1627 1628
		}

S
SteVen Batten 已提交
1629 1630 1631
		if (!this.activityBarHidden) {
			this.activitybarPartView.show();
		}
S
SteVen Batten 已提交
1632

S
SteVen Batten 已提交
1633 1634
		if (!this.sideBarHidden) {
			this.sidebarPartView.show();
S
SteVen Batten 已提交
1635 1636
		}

S
SteVen Batten 已提交
1637 1638
		if (!this.panelHidden) {
			this.panelPartView.show();
S
SteVen Batten 已提交
1639 1640 1641 1642 1643 1644 1645
		}
	}

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

		if (this.workbenchStarted && !this.workbenchShutdown) {
S
SteVen Batten 已提交
1646
			if (this.workbenchGrid instanceof Grid) {
1647 1648 1649
				const dimensions = getClientArea(this.container);
				position(this.workbench, 0, 0, 0, 0, 'relative');
				size(this.workbench, dimensions.width, dimensions.height);
S
SteVen Batten 已提交
1650

S
SteVen Batten 已提交
1651
				// Layout the grid
S
SteVen Batten 已提交
1652
				this.workbenchGrid.layout(dimensions.width, dimensions.height);
S
SteVen Batten 已提交
1653 1654 1655 1656 1657 1658 1659 1660

				// Layout non-view ui components
				this.quickInput.layout(dimensions);
				this.quickOpen.layout(dimensions);
				this.notificationsCenter.layout(dimensions);
				this.notificationsToasts.layout(dimensions);

				// Update grid view membership
1661
				this.updateGrid();
S
SteVen Batten 已提交
1662 1663
			} else {
				this.workbenchGrid.layout(options);
1664
			}
1665 1666 1667
		}
	}

1668
	isEditorLayoutCentered(): boolean {
1669
		return this.shouldCenterLayout;
S
SrTobi 已提交
1670 1671
	}

1672
	centerEditorLayout(active: boolean, skipLayout?: boolean): void {
B
Benjamin Pasero 已提交
1673
		this.storageService.store(Workbench.centeredEditorLayoutActiveStorageKey, active, StorageScope.WORKSPACE);
1674 1675
		this.shouldCenterLayout = active;
		let smartActive = active;
1676
		if (this.editorPart.groups.length > 1 && this.configurationService.getValue('workbench.editor.centeredLayoutAutoResize')) {
B
Benjamin Pasero 已提交
1677
			smartActive = false; // Respect the auto resize setting - do not go into centered layout if there is more than 1 group.
1678
		}
B
Benjamin Pasero 已提交
1679

1680
		// Enter Centered Editor Layout
1681 1682
		if (this.editorPart.isLayoutCentered() !== smartActive) {
			this.editorPart.centerLayout(smartActive);
1683

1684 1685 1686
			if (!skipLayout) {
				this.layout();
			}
1687
		}
S
SrTobi 已提交
1688 1689
	}

1690
	resizePart(part: Parts, sizeChange: number): void {
S
SteVen Batten 已提交
1691
		let view: View;
1692 1693
		switch (part) {
			case Parts.SIDEBAR_PART:
S
SteVen Batten 已提交
1694
				view = this.sidebarPartView;
1695
			case Parts.PANEL_PART:
S
SteVen Batten 已提交
1696
				view = this.panelPartView;
1697
			case Parts.EDITOR_PART:
S
SteVen Batten 已提交
1698 1699
				view = this.editorPartView;
				if (this.workbenchGrid instanceof Grid) {
1700 1701 1702 1703
					this.workbenchGrid.resizeView(view, this.workbenchGrid.getViewSize(view) + sizeChange);
				} else {
					this.workbenchGrid.resizePart(part, sizeChange);
				}
1704 1705
				break;
			default:
B
Benjamin Pasero 已提交
1706
				return; // Cannot resize other parts
1707 1708 1709
		}
	}

1710 1711
	setActivityBarHidden(hidden: boolean, skipLayout?: boolean): void {
		this.activityBarHidden = hidden;
1712

1713 1714
		// Layout
		if (!skipLayout) {
S
SteVen Batten 已提交
1715
			if (this.workbenchGrid instanceof Grid) {
S
SteVen Batten 已提交
1716
				this.layout();
1717 1718 1719
			} else {
				this.workbenchGrid.layout();
			}
1720
		}
1721
	}
1722

S
SteVen Batten 已提交
1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739
	setEditorHidden(hidden: boolean, skipLayout?: boolean): void {
		if (!(this.workbenchGrid instanceof Grid)) {
			return;
		}

		this.editorHidden = hidden;

		// The editor and the panel cannot be hidden at the same time
		if (this.editorHidden && this.panelHidden) {
			this.setPanelHidden(false, true);
		}

		if (!skipLayout) {
			this.layout();
		}
	}

1740
	setSideBarHidden(hidden: boolean, skipLayout?: boolean): void {
1741 1742 1743 1744 1745
		this.sideBarHidden = hidden;
		this.sideBarVisibleContext.set(!hidden);

		// Adjust CSS
		if (hidden) {
1746
			addClass(this.workbench, 'nosidebar');
1747
		} else {
1748
			removeClass(this.workbench, 'nosidebar');
1749 1750
		}

1751 1752
		// If sidebar becomes hidden, also hide the current active Viewlet if any
		if (hidden && this.sidebarPart.getActiveViewlet()) {
1753 1754 1755 1756 1757 1758 1759 1760 1761
			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();
			}
1762 1763 1764 1765 1766 1767
		}

		// 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 已提交
1768
				const viewlet = this.sidebarPart.openViewlet(viewletToOpen, true);
1769
				if (!viewlet) {
I
isidor 已提交
1770
					this.sidebarPart.openViewlet(this.sidebarPart.getDefaultViewletId(), true);
1771
				}
1772
			}
1773 1774
		}

1775

1776 1777 1778 1779 1780 1781 1782
		// 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);
		}
1783

1784 1785
		// Layout
		if (!skipLayout) {
S
SteVen Batten 已提交
1786
			if (this.workbenchGrid instanceof Grid) {
S
SteVen Batten 已提交
1787
				this.layout();
1788 1789 1790
			} else {
				this.workbenchGrid.layout();
			}
1791
		}
1792
	}
1793

1794
	setPanelHidden(hidden: boolean, skipLayout?: boolean): void {
1795 1796 1797 1798
		this.panelHidden = hidden;

		// Adjust CSS
		if (hidden) {
1799
			addClass(this.workbench, 'nopanel');
1800
		} else {
1801
			removeClass(this.workbench, 'nopanel');
1802 1803 1804 1805
		}

		// If panel part becomes hidden, also hide the current active panel if any
		if (hidden && this.panelPart.getActivePanel()) {
1806 1807
			this.panelPart.hideActivePanel();
			this.editorGroupService.activeGroup.focus(); // Pass focus to editor group if panel part is now hidden
1808 1809 1810 1811 1812 1813
		}

		// 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) {
1814
				this.panelPart.openPanel(panelToOpen, true);
1815 1816 1817 1818
			}
		}


1819 1820 1821 1822 1823 1824
		// Remember in settings
		if (!hidden) {
			this.storageService.store(Workbench.panelHiddenStorageKey, 'false', StorageScope.WORKSPACE);
		} else {
			this.storageService.remove(Workbench.panelHiddenStorageKey, StorageScope.WORKSPACE);
		}
1825

S
SteVen Batten 已提交
1826 1827 1828 1829 1830
		// The editor and panel cannot be hiddne at the same time
		if (hidden && this.editorHidden) {
			this.setEditorHidden(false, true);
		}

1831 1832
		// Layout
		if (!skipLayout) {
S
SteVen Batten 已提交
1833
			if (this.workbenchGrid instanceof Grid) {
S
SteVen Batten 已提交
1834
				this.layout();
1835 1836 1837
			} else {
				this.workbenchGrid.layout();
			}
1838
		}
1839 1840 1841
	}

	toggleMaximizedPanel(): void {
S
SteVen Batten 已提交
1842 1843
		if (this.workbenchGrid instanceof Grid) {
			this.workbenchGrid.maximizeViewSize(this.panelPartView);
1844 1845 1846
		} else {
			this.workbenchGrid.layout({ toggleMaximizedPanel: true, source: Parts.PANEL_PART });
		}
1847 1848 1849
	}

	isPanelMaximized(): boolean {
S
SteVen Batten 已提交
1850
		if (this.workbenchGrid instanceof Grid) {
1851
			try {
S
SteVen Batten 已提交
1852
				return this.workbenchGrid.getViewSize2(this.panelPartView).height === this.panelPart.maximumHeight;
1853 1854 1855 1856 1857 1858
			} catch (e) {
				return false;
			}
		} else {
			return this.workbenchGrid.isPanelMaximized();
		}
1859 1860 1861 1862 1863 1864 1865
	}

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

	setSideBarPosition(position: Position): void {
1866 1867
		const wasHidden = this.sideBarHidden;

1868
		if (this.sideBarHidden) {
1869
			this.setSideBarHidden(false, true /* Skip Layout */);
1870 1871 1872 1873 1874 1875 1876
		}

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

		// Adjust CSS
1877 1878 1879 1880
		removeClass(this.activitybarPart.getContainer(), oldPositionValue);
		removeClass(this.sidebarPart.getContainer(), oldPositionValue);
		addClass(this.activitybarPart.getContainer(), newPositionValue);
		addClass(this.sidebarPart.getContainer(), newPositionValue);
1881 1882 1883 1884 1885 1886

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

		// Layout
S
SteVen Batten 已提交
1887
		if (this.workbenchGrid instanceof Grid) {
1888

S
SteVen Batten 已提交
1889
			if (!wasHidden) {
S
SteVen Batten 已提交
1890
				this.uiState.lastSidebarDimension = this.workbenchGrid.getViewSize(this.sidebarPartView);
1891 1892
			}

S
SteVen Batten 已提交
1893 1894
			this.workbenchGrid.removeView(this.sidebarPartView);
			this.workbenchGrid.removeView(this.activitybarPartView);
S
SteVen Batten 已提交
1895 1896 1897

			if (!this.panelHidden && this.panelPosition === Position.BOTTOM) {
				this.workbenchGrid.removeView(this.panelPartView);
1898 1899
			}

S
SteVen Batten 已提交
1900
			this.layout();
1901 1902 1903
		} else {
			this.workbenchGrid.layout();
		}
1904 1905
	}

S
SteVen Batten 已提交
1906
	setMenubarVisibility(visibility: MenuBarVisibility, skipLayout: boolean): void {
S
SteVen Batten 已提交
1907 1908
		if (this.menubarVisibility !== visibility) {
			this.menubarVisibility = visibility;
1909

1910
			// Layout
S
SteVen Batten 已提交
1911
			if (!skipLayout) {
S
SteVen Batten 已提交
1912
				if (this.workbenchGrid instanceof Grid) {
1913
					const dimensions = getClientArea(this.container);
1914 1915 1916 1917
					this.workbenchGrid.layout(dimensions.width, dimensions.height);
				} else {
					this.workbenchGrid.layout();
				}
S
SteVen Batten 已提交
1918
			}
1919 1920 1921
		}
	}

S
SteVen Batten 已提交
1922 1923 1924 1925
	getMenubarVisibility(): MenuBarVisibility {
		return this.menubarVisibility;
	}

1926 1927 1928 1929
	getPanelPosition(): Position {
		return this.panelPosition;
	}

1930
	setPanelPosition(position: Position): void {
1931 1932
		const wasHidden = this.panelHidden;

1933 1934
		if (this.panelHidden) {
			this.setPanelHidden(false, true /* Skip Layout */);
1935 1936
		} else {
			this.saveLastPanelDimension();
1937
		}
1938

1939 1940 1941 1942
		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);
1943

1944
		// Adjust CSS
1945 1946
		removeClass(this.panelPart.getContainer(), oldPositionValue);
		addClass(this.panelPart.getContainer(), newPositionValue);
1947

1948 1949 1950 1951
		// Update Styles
		this.panelPart.updateStyles();

		// Layout
S
SteVen Batten 已提交
1952 1953 1954
		if (this.workbenchGrid instanceof Grid) {
			if (!wasHidden) {
				this.saveLastPanelDimension();
1955
			}
1956

1957
			this.workbenchGrid.removeView(this.panelPartView);
S
SteVen Batten 已提交
1958
			this.layout();
1959 1960 1961 1962
		} else {
			this.workbenchGrid.layout();
		}
	}
J
Johannes Rieken 已提交
1963
}