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

'use strict';

import 'vs/css!./media/shell';

10
import * as nls from 'vs/nls';
J
Johannes Rieken 已提交
11
import { TPromise } from 'vs/base/common/winjs.base';
J
Joao Moreno 已提交
12
import * as platform from 'vs/base/common/platform';
J
Johannes Rieken 已提交
13
import { Dimension, Builder, $ } from 'vs/base/browser/builder';
E
Erich Gamma 已提交
14
import dom = require('vs/base/browser/dom');
15
import aria = require('vs/base/browser/ui/aria/aria');
J
Johannes Rieken 已提交
16
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
E
Erich Gamma 已提交
17
import errors = require('vs/base/common/errors');
J
Johannes Rieken 已提交
18
import { toErrorMessage } from 'vs/base/common/errorMessage';
19
import product from 'vs/platform/node/product';
20
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
21
import pkg from 'vs/platform/node/package';
J
Johannes Rieken 已提交
22
import { ContextViewService } from 'vs/platform/contextview/browser/contextViewService';
23
import { Workbench, IWorkbenchStartedInfo } from 'vs/workbench/electron-browser/workbench';
24
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
25
import { NullTelemetryService, configurationTelemetry, lifecycleTelemetry } from 'vs/platform/telemetry/common/telemetryUtils';
26
import { IExperimentService, ExperimentService } from 'vs/platform/telemetry/common/experiments';
J
Johannes Rieken 已提交
27 28 29
import { ITelemetryAppenderChannel, TelemetryAppenderClient } from 'vs/platform/telemetry/common/telemetryIpc';
import { TelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService';
import { IdleMonitor, UserStatus } from 'vs/platform/telemetry/browser/idleMonitor';
J
Joao Moreno 已提交
30
import ErrorTelemetry from 'vs/platform/telemetry/browser/errorTelemetry';
31
import { ElectronWindow } from 'vs/workbench/electron-browser/window';
C
Christof Marti 已提交
32 33
import { resolveWorkbenchCommonProperties, getOrCreateMachineId } from 'vs/platform/telemetry/node/workbenchCommonProperties';
import { machineIdIpcChannel } from 'vs/platform/telemetry/node/commonProperties';
J
Johannes Rieken 已提交
34
import { WorkspaceStats } from 'vs/workbench/services/telemetry/common/workspaceStats';
35
import { IWindowsService, IWindowService, IWindowConfiguration } from 'vs/platform/windows/common/windows';
J
Joao Moreno 已提交
36
import { WindowService } from 'vs/platform/windows/electron-browser/windowService';
J
Johannes Rieken 已提交
37
import { MessageService } from 'vs/workbench/services/message/electron-browser/messageService';
J
Joao Moreno 已提交
38
import { IRequestService } from 'vs/platform/request/node/request';
39
import { RequestService } from 'vs/platform/request/electron-browser/requestService';
J
Johannes Rieken 已提交
40 41 42 43 44 45 46 47 48 49 50 51
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { SearchService } from 'vs/workbench/services/search/node/searchService';
import { LifecycleService } from 'vs/workbench/services/lifecycle/electron-browser/lifecycleService';
import { MarkerService } from 'vs/platform/markers/common/markerService';
import { IModelService } from 'vs/editor/common/services/modelService';
import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl';
import { CodeEditorServiceImpl } from 'vs/editor/browser/services/codeEditorServiceImpl';
import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService';
import { IntegrityServiceImpl } from 'vs/platform/integrity/node/integrityServiceImpl';
import { IIntegrityService } from 'vs/platform/integrity/common/integrity';
import { EditorWorkerServiceImpl } from 'vs/editor/common/services/editorWorkerServiceImpl';
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';
52
import { ExtensionService } from "vs/workbench/services/extensions/electron-browser/extensionService";
J
Johannes Rieken 已提交
53
import { IStorageService } from 'vs/platform/storage/common/storage';
J
Joao Moreno 已提交
54
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
J
Johannes Rieken 已提交
55 56 57
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
58
import { ILifecycleService, LifecyclePhase, ShutdownEvent, ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle';
J
Johannes Rieken 已提交
59 60
import { IMarkerService } from 'vs/platform/markers/common/markers';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
B
Benjamin Pasero 已提交
61
import { IMessageService, IChoiceService, Severity } from 'vs/platform/message/common/message';
J
Johannes Rieken 已提交
62 63 64 65
import { ChoiceChannel } from 'vs/platform/message/common/messageIpc';
import { ISearchService } from 'vs/platform/search/common/search';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { CommandService } from 'vs/platform/commands/common/commandService';
66
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
67
import { IExtensionService } from 'vs/platform/extensions/common/extensions';
68
import { WorkbenchModeServiceImpl } from 'vs/workbench/services/mode/common/workbenchModeService';
J
Johannes Rieken 已提交
69 70
import { IModeService } from 'vs/editor/common/services/modeService';
import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
71 72
import { ICrashReporterService, NullCrashReporterService } from 'vs/workbench/services/crashReporter/common/crashReporterService';
import { CrashReporterService } from 'vs/workbench/services/crashReporter/electron-browser/crashReporterService';
73
import { NodeCachedDataManager } from 'vs/workbench/electron-browser/nodeCachedDataManager';
J
Johannes Rieken 已提交
74 75 76
import { getDelayedChannel } from 'vs/base/parts/ipc/common/ipc';
import { connect as connectNet } from 'vs/base/parts/ipc/node/ipc.net';
import { IExtensionManagementChannel, ExtensionManagementChannelClient } from 'vs/platform/extensionManagement/common/extensionManagementIpc';
77 78
import { IExtensionManagementService, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionEnablementService';
B
Benjamin Pasero 已提交
79
import { ITimerService } from 'vs/workbench/services/timer/common/timerService';
C
Christof Marti 已提交
80
import { remote, ipcRenderer as ipc } from 'electron';
81
import { BareFontInfo } from 'vs/editor/common/config/fontInfo';
82 83
import { restoreFontInfo, readFontInfo, saveFontInfo } from 'vs/editor/browser/config/configuration';
import * as browser from 'vs/base/browser/browser';
84
import 'vs/platform/opener/browser/opener.contribution';
85 86
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { WorkbenchThemeService } from 'vs/workbench/services/themes/electron-browser/workbenchThemeService';
87 88
import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration';
import { TextResourceConfigurationService } from 'vs/editor/common/services/resourceConfigurationImpl';
89
import { registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
90
import { foreground, selectionBackground, focusBorder, scrollbarShadow, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground, listHighlightForeground, inputPlaceholderForeground } from 'vs/platform/theme/common/colorRegistry';
91 92
import { TextMateService } from 'vs/workbench/services/textMate/electron-browser/TMSyntax';
import { ITextMateService } from 'vs/workbench/services/textMate/electron-browser/textMateService';
93
import { IBroadcastService, BroadcastService } from "vs/platform/broadcast/electron-browser/broadcastService";
B
Benjamin Pasero 已提交
94 95 96 97
import { isWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { StorageService } from 'vs/platform/storage/common/storageService';
import { migrateStorageToMultiRootWorkspace } from 'vs/platform/storage/common/migration';
import { once } from 'vs/base/common/event';
98

99 100 101 102 103 104
/**
 * Services that we require for the Shell
 */
export interface ICoreServices {
	contextService: IWorkspaceContextService;
	configurationService: IConfigurationService;
105
	environmentService: IEnvironmentService;
B
Benjamin Pasero 已提交
106
	timerService: ITimerService;
107
	storageService: IStorageService;
108 109
}

110 111
const currentWindow = remote.getCurrentWindow();

E
Erich Gamma 已提交
112
/**
B
Benjamin Pasero 已提交
113
 * The workbench shell contains the workbench with a rich header containing navigation and the activity bar.
E
Erich Gamma 已提交
114 115 116
 * With the Shell being the top level element in the page, it is also responsible for driving the layouting.
 */
export class WorkbenchShell {
B
Benjamin Pasero 已提交
117
	private storageService: IStorageService;
118
	private messageService: MessageService;
J
Johannes Rieken 已提交
119
	private environmentService: IEnvironmentService;
B
Benjamin Pasero 已提交
120
	private contextViewService: ContextViewService;
121 122
	private configurationService: IConfigurationService;
	private contextService: IWorkspaceContextService;
123
	private telemetryService: ITelemetryService;
124
	private experimentService: IExperimentService;
125
	private extensionService: ExtensionService;
126
	private broadcastService: IBroadcastService;
B
Benjamin Pasero 已提交
127
	private timerService: ITimerService;
B
Benjamin Pasero 已提交
128
	private themeService: WorkbenchThemeService;
129
	private lifecycleService: LifecycleService;
130 131
	private mainProcessServices: ServiceCollection;

E
Erich Gamma 已提交
132
	private container: HTMLElement;
133
	private toUnbind: IDisposable[];
E
Erich Gamma 已提交
134 135 136 137
	private previousErrorValue: string;
	private previousErrorTime: number;
	private content: HTMLElement;
	private contentsContainer: Builder;
138
	private shutdownListener: IDisposable;
E
Erich Gamma 已提交
139

140
	private configuration: IWindowConfiguration;
E
Erich Gamma 已提交
141 142
	private workbench: Workbench;

B
Benjamin Pasero 已提交
143
	constructor(container: HTMLElement, coreServices: ICoreServices, mainProcessServices: ServiceCollection, configuration: IWindowConfiguration) {
E
Erich Gamma 已提交
144 145
		this.container = container;

146
		this.configuration = configuration;
147

B
Benjamin Pasero 已提交
148 149 150 151 152
		this.contextService = coreServices.contextService;
		this.configurationService = coreServices.configurationService;
		this.environmentService = coreServices.environmentService;
		this.timerService = coreServices.timerService;
		this.storageService = coreServices.storageService;
E
Erich Gamma 已提交
153

154 155
		this.mainProcessServices = mainProcessServices;

E
Erich Gamma 已提交
156 157 158 159 160 161
		this.toUnbind = [];
		this.previousErrorTime = 0;
	}

	private createContents(parent: Builder): Builder {

162
		// ARIA
B
Benjamin Pasero 已提交
163
		aria.setARIAContainer(document.body);
164

E
Erich Gamma 已提交
165
		// Workbench Container
166
		const workbenchContainer = $(parent).div();
E
Erich Gamma 已提交
167 168

		// Instantiation service with services
169
		const [instantiationService, serviceCollection] = this.initServiceCollection(parent.getHTMLElement());
E
Erich Gamma 已提交
170 171

		// Workbench
B
Benjamin Pasero 已提交
172
		this.workbench = instantiationService.createInstance(Workbench, parent.getHTMLElement(), workbenchContainer.getHTMLElement(), this.configuration, serviceCollection);
E
Erich Gamma 已提交
173
		this.workbench.startup({
174
			onWorkbenchStarted: (info: IWorkbenchStartedInfo) => {
175 176

				// run workbench started logic
B
Benjamin Pasero 已提交
177
				this.onWorkbenchStarted(info);
178 179 180

				// start cached data manager
				instantiationService.createInstance(NodeCachedDataManager);
181 182 183 184

				// Set lifecycle phase to `Runnning` so that other contributions
				// can now do something
				this.lifecycleService.phase = LifecyclePhase.Running;
E
Erich Gamma 已提交
185 186 187
			}
		});

188
		// Window
189
		this.workbench.getInstantiationService().createInstance(ElectronWindow, this.container);
E
Erich Gamma 已提交
190 191

		// Handle case where workbench is not starting up properly
192
		const timeoutHandle = setTimeout(() => {
E
Erich Gamma 已提交
193 194 195 196 197 198 199 200 201 202
			console.warn('Workbench did not finish loading in 10 seconds, that might be a problem that should be reported.');
		}, 10000);

		this.workbench.joinCreation().then(() => {
			clearTimeout(timeoutHandle);
		});

		return workbenchContainer;
	}

B
Benjamin Pasero 已提交
203
	private onWorkbenchStarted(info: IWorkbenchStartedInfo): void {
204 205

		// Telemetry: workspace info
B
Benjamin Pasero 已提交
206
		const { filesToOpen, filesToCreate, filesToDiff } = this.configuration;
207 208 209
		this.telemetryService.publicLog('workspaceLoad', {
			userAgent: navigator.userAgent,
			windowSize: { innerHeight: window.innerHeight, innerWidth: window.innerWidth, outerHeight: window.outerHeight, outerWidth: window.outerWidth },
B
Benjamin Pasero 已提交
210
			emptyWorkbench: !this.contextService.hasWorkspace(),
B
Benjamin Pasero 已提交
211 212 213
			'workbench.filesToOpen': filesToOpen && filesToOpen.length || void 0,
			'workbench.filesToCreate': filesToCreate && filesToCreate.length || void 0,
			'workbench.filesToDiff': filesToDiff && filesToDiff.length || void 0,
214
			customKeybindingsCount: info.customKeybindingsCount,
B
Benjamin Pasero 已提交
215
			theme: this.themeService.getColorTheme().id,
216
			language: platform.language,
217
			experiments: this.experimentService.getExperiments(),
218 219
			pinnedViewlets: info.pinnedViewlets,
			restoredViewlet: info.restoredViewlet,
220 221
			restoredEditors: info.restoredEditors.length,
			startupKind: this.lifecycleService.startupKind
222 223
		});

B
Benjamin Pasero 已提交
224
		// Telemetry: startup metrics
225
		this.timerService.workbenchStarted = Date.now();
B
Benjamin Pasero 已提交
226 227
		this.timerService.restoreEditorsDuration = info.restoreEditorsDuration;
		this.timerService.restoreViewletDuration = info.restoreViewletDuration;
228
		this.extensionService.onReady().done(() => {
B
Benjamin Pasero 已提交
229
			this.telemetryService.publicLog('startupTime', this.timerService.startupMetrics);
230
		});
B
Benjamin Pasero 已提交
231

232
		// Telemetry: workspace tags
233
		const workspaceStats: WorkspaceStats = <WorkspaceStats>this.workbench.getInstantiationService().createInstance(WorkspaceStats);
B
Benjamin Pasero 已提交
234
		workspaceStats.reportWorkspaceTags(this.configuration);
K
kieferrm 已提交
235
		workspaceStats.reportCloudStats();
J
Joao Moreno 已提交
236 237 238 239

		if ((platform.isLinux || platform.isMacintosh) && process.getuid() === 0) {
			this.messageService.show(Severity.Warning, nls.localize('runningAsRoot', "It is recommended not to run Code as 'root'."));
		}
B
Benjamin Pasero 已提交
240 241
	}

242
	private initServiceCollection(container: HTMLElement): [IInstantiationService, ServiceCollection] {
J
Johannes Rieken 已提交
243
		const disposables: IDisposable[] = [];
J
Joao Moreno 已提交
244

245 246 247
		const serviceCollection = new ServiceCollection();
		serviceCollection.set(IWorkspaceContextService, this.contextService);
		serviceCollection.set(IConfigurationService, this.configurationService);
248
		serviceCollection.set(IEnvironmentService, this.environmentService);
B
Benjamin Pasero 已提交
249
		serviceCollection.set(ITimerService, this.timerService);
250
		serviceCollection.set(IStorageService, this.storageService);
251 252 253
		this.mainProcessServices.forEach((serviceIdentifier, serviceInstance) => {
			serviceCollection.set(serviceIdentifier, serviceInstance);
		});
254

255
		const instantiationService: IInstantiationService = new InstantiationService(serviceCollection, true);
256

257 258
		this.broadcastService = new BroadcastService(currentWindow.id);
		serviceCollection.set(IBroadcastService, this.broadcastService);
259

260
		serviceCollection.set(IWindowService, new SyncDescriptor(WindowService, currentWindow.id));
J
Joao Moreno 已提交
261

262
		const sharedProcess = (<IWindowsService>serviceCollection.get(IWindowsService)).whenSharedProcessReady()
263
			.then(() => connectNet(this.environmentService.sharedIPCHandle, `window:${currentWindow.id}`));
264 265 266

		sharedProcess
			.done(client => client.registerChannel('choice', instantiationService.createInstance(ChoiceChannel)));
267

268 269 270 271
		// Warm up font cache information before building up too many dom elements
		restoreFontInfo(this.storageService);
		readFontInfo(BareFontInfo.createFromRawSettings(this.configurationService.getConfiguration('editor'), browser.getZoomLevel()));

272 273 274 275
		// Experiments
		this.experimentService = instantiationService.createInstance(ExperimentService);
		serviceCollection.set(IExperimentService, this.experimentService);

276
		// Telemetry
C
Christof Marti 已提交
277
		this.sendMachineIdToMain(this.storageService);
278
		if (this.environmentService.isBuilt && !this.environmentService.isExtensionDevelopment && !!product.enableTelemetry) {
279
			const channel = getDelayedChannel<ITelemetryAppenderChannel>(sharedProcess.then(c => c.getChannel('telemetryAppender')));
280 281
			const commit = product.commit;
			const version = pkg.version;
282

283
			const config: ITelemetryServiceConfig = {
284
				appender: new TelemetryAppenderClient(channel),
285
				commonProperties: resolveWorkbenchCommonProperties(this.storageService, commit, version),
286
				piiPaths: [this.environmentService.appRoot, this.environmentService.extensionsPath]
287
			};
288

J
Joao Moreno 已提交
289
			const telemetryService = instantiationService.createInstance(TelemetryService, config);
290 291
			this.telemetryService = telemetryService;

J
Joao Moreno 已提交
292
			const errorTelemetry = new ErrorTelemetry(telemetryService);
293
			const idleMonitor = new IdleMonitor(2 * 60 * 1000); // 2 minutes
294

295 296 297 298
			const listener = idleMonitor.onStatusChange(status =>
				this.telemetryService.publicLog(status === UserStatus.Active
					? TelemetryService.IDLE_STOP_EVENT_NAME
					: TelemetryService.IDLE_START_EVENT_NAME
299
				));
300

J
Johannes Rieken 已提交
301
			disposables.push(telemetryService, errorTelemetry, listener, idleMonitor);
302
		} else {
303
			this.telemetryService = NullTelemetryService;
304
		}
E
Erich Gamma 已提交
305

306
		serviceCollection.set(ITelemetryService, this.telemetryService);
J
Johannes Rieken 已提交
307
		disposables.push(configurationTelemetry(this.telemetryService, this.configurationService));
E
Erich Gamma 已提交
308

309 310 311 312 313 314
		let crashReporterService = NullCrashReporterService;
		if (product.crashReporter && product.hockeyApp) {
			crashReporterService = instantiationService.createInstance(CrashReporterService);
		}
		serviceCollection.set(ICrashReporterService, crashReporterService);

315
		this.messageService = instantiationService.createInstance(MessageService, container);
316
		serviceCollection.set(IMessageService, this.messageService);
J
Joao Moreno 已提交
317
		serviceCollection.set(IChoiceService, this.messageService);
E
Erich Gamma 已提交
318

319
		const lifecycleService = instantiationService.createInstance(LifecycleService);
J
Johannes Rieken 已提交
320
		this.toUnbind.push(lifecycleService.onShutdown(reason => dispose(disposables)));
321
		this.toUnbind.push(lifecycleService.onShutdown(reason => saveFontInfo(this.storageService)));
322
		this.toUnbind.push(lifecycleService.onWillShutdown(event => this.onWillShutdown(event)));
323
		serviceCollection.set(ILifecycleService, lifecycleService);
J
Johannes Rieken 已提交
324
		disposables.push(lifecycleTelemetry(this.telemetryService, lifecycleService));
325
		this.lifecycleService = lifecycleService;
326

S
Sandeep Somavarapu 已提交
327
		const extensionManagementChannel = getDelayedChannel<IExtensionManagementChannel>(sharedProcess.then(c => c.getChannel('extensions')));
328
		serviceCollection.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementChannelClient, extensionManagementChannel));
S
Sandeep Somavarapu 已提交
329

330 331
		const extensionEnablementService = instantiationService.createInstance(ExtensionEnablementService);
		serviceCollection.set(IExtensionEnablementService, extensionEnablementService);
J
Johannes Rieken 已提交
332
		disposables.push(extensionEnablementService);
333

334
		this.extensionService = instantiationService.createInstance(ExtensionService);
335
		serviceCollection.set(IExtensionService, this.extensionService);
336 337

		this.timerService.beforeExtensionLoad = Date.now();
338
		this.extensionService.onReady().done(() => {
339
			this.timerService.afterExtensionLoad = Date.now();
340
		});
E
Erich Gamma 已提交
341

B
Benjamin Pasero 已提交
342 343 344
		this.themeService = instantiationService.createInstance(WorkbenchThemeService, document.body);
		serviceCollection.set(IWorkbenchThemeService, this.themeService);

345
		serviceCollection.set(ICommandService, new SyncDescriptor(CommandService));
346

347 348
		this.contextViewService = instantiationService.createInstance(ContextViewService, this.container);
		serviceCollection.set(IContextViewService, this.contextViewService);
E
Erich Gamma 已提交
349

350
		serviceCollection.set(IRequestService, new SyncDescriptor(RequestService));
E
Erich Gamma 已提交
351

352
		serviceCollection.set(IMarkerService, new SyncDescriptor(MarkerService));
E
Erich Gamma 已提交
353

354
		serviceCollection.set(IModeService, new SyncDescriptor(WorkbenchModeServiceImpl));
355

356
		serviceCollection.set(IModelService, new SyncDescriptor(ModelServiceImpl));
357

358 359
		serviceCollection.set(ITextResourceConfigurationService, new SyncDescriptor(TextResourceConfigurationService));

360
		serviceCollection.set(IEditorWorkerService, new SyncDescriptor(EditorWorkerServiceImpl));
361

362
		serviceCollection.set(IUntitledEditorService, new SyncDescriptor(UntitledEditorService));
363

364
		serviceCollection.set(ITextMateService, new SyncDescriptor(TextMateService));
A
Alex Dima 已提交
365

366
		serviceCollection.set(ISearchService, new SyncDescriptor(SearchService));
367

368
		serviceCollection.set(ICodeEditorService, new SyncDescriptor(CodeEditorServiceImpl));
369

370
		serviceCollection.set(IIntegrityService, new SyncDescriptor(IntegrityServiceImpl));
A
Alex Dima 已提交
371

372
		return [instantiationService, serviceCollection];
E
Erich Gamma 已提交
373 374
	}

C
Christof Marti 已提交
375 376 377 378 379 380
	private sendMachineIdToMain(storageService: IStorageService) {
		getOrCreateMachineId(storageService).then(machineId => {
			ipc.send(machineIdIpcChannel, machineId);
		}).then(null, errors.onUnexpectedError);
	}

E
Erich Gamma 已提交
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410
	public open(): void {

		// Listen on unexpected errors
		errors.setUnexpectedErrorHandler((error: any) => {
			this.onUnexpectedError(error);
		});

		// Shell Class for CSS Scoping
		$(this.container).addClass('monaco-shell');

		// Controls
		this.content = $('.monaco-shell-content').appendTo(this.container).getHTMLElement();

		// Create Contents
		this.contentsContainer = this.createContents($(this.content));

		// Layout
		this.layout();

		// Listeners
		this.registerListeners();
	}

	private registerListeners(): void {

		// Resize
		$(window).on(dom.EventType.RESIZE, () => this.layout(), this.toUnbind);
	}

	public onUnexpectedError(error: any): void {
411
		const errorMsg = toErrorMessage(error, true);
E
Erich Gamma 已提交
412 413 414 415
		if (!errorMsg) {
			return;
		}

416
		const now = Date.now();
E
Erich Gamma 已提交
417 418 419 420 421 422 423 424 425 426 427
		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 to console
		console.error(errorMsg);

		// Show to user if friendly message provided
428
		if (error && error.friendlyMessage && this.messageService) {
B
Benjamin Pasero 已提交
429
			this.messageService.show(Severity.Error, error.friendlyMessage);
E
Erich Gamma 已提交
430 431 432
		}
	}

B
Benjamin Pasero 已提交
433
	private layout(): void {
434
		const clArea = $(this.container).getClientArea();
E
Erich Gamma 已提交
435

436
		const contentsSize = new Dimension(clArea.width, clArea.height);
E
Erich Gamma 已提交
437 438
		this.contentsContainer.size(contentsSize.width, contentsSize.height);

B
Benjamin Pasero 已提交
439
		this.contextViewService.layout();
E
Erich Gamma 已提交
440 441 442 443 444 445 446
		this.workbench.layout();
	}

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

447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473
	private onWillShutdown(event: ShutdownEvent): void {

		// The shutdown sequence could have been stopped due to a veto. Make sure to
		// always dispose the shutdown listener if we are called again in the same session.
		if (this.shutdownListener) {
			this.shutdownListener.dispose();
			this.shutdownListener = void 0;
		}

		if (event.reason === ShutdownReason.RELOAD) {
			const workspace = event.payload;

			// We are transitioning into a workspace from an empty workspace or folder workspace
			// As such we want to migrate UI state from the current workspace to the new one. Since
			// many components write to storage only on shutdown, we register a shutdown listener
			// very late to be called as the last one.
			if (isWorkspaceIdentifier(workspace) && !this.contextService.hasMultiFolderWorkspace()) {
				this.shutdownListener = once(this.lifecycleService.onShutdown)(() => {

					// TODO@Ben revisit this when we move away from local storage to a file based approach
					const storageImpl = this.storageService as StorageService;
					migrateStorageToMultiRootWorkspace(storageImpl.storageId, workspace, storageImpl.workspaceStorage);
				});
			}
		}
	}

B
Benjamin Pasero 已提交
474
	public dispose(): void {
E
Erich Gamma 已提交
475 476 477

		// Workbench
		if (this.workbench) {
B
Benjamin Pasero 已提交
478
			this.workbench.dispose();
E
Erich Gamma 已提交
479 480
		}

B
Benjamin Pasero 已提交
481
		this.contextViewService.dispose();
E
Erich Gamma 已提交
482 483

		// Listeners
J
Joao Moreno 已提交
484
		this.toUnbind = dispose(this.toUnbind);
E
Erich Gamma 已提交
485

486 487 488 489 490
		if (this.shutdownListener) {
			this.shutdownListener.dispose();
			this.shutdownListener = void 0;
		}

E
Erich Gamma 已提交
491 492 493
		// Container
		$(this.container).empty();
	}
494
}
495 496

registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
B
Benjamin Pasero 已提交
497 498

	// Foreground
B
Benjamin Pasero 已提交
499
	const windowForeground = theme.getColor(foreground);
500 501 502
	if (windowForeground) {
		collector.addRule(`.monaco-shell { color: ${windowForeground}; }`);
	}
B
Benjamin Pasero 已提交
503

504 505 506 507 508 509
	// Selection
	const windowSelectionBackground = theme.getColor(selectionBackground);
	if (windowSelectionBackground) {
		collector.addRule(`.monaco-shell ::selection { background-color: ${windowSelectionBackground}; }`);
	}

510 511 512 513 514 515 516
	// Input placeholder
	const placeholderForeground = theme.getColor(inputPlaceholderForeground);
	if (placeholderForeground) {
		collector.addRule(`.monaco-shell input::-webkit-input-placeholder { color: ${placeholderForeground}; }`);
		collector.addRule(`.monaco-shell textarea::-webkit-input-placeholder { color: ${placeholderForeground}; }`);
	}

517 518 519 520 521 522 523 524 525 526 527
	// List highlight
	const listHighlightForegroundColor = theme.getColor(listHighlightForeground);
	if (listHighlightForegroundColor) {
		collector.addRule(`
			.monaco-shell .monaco-tree .monaco-tree-row .monaco-highlighted-label .highlight,
			.monaco-shell .monaco-list .monaco-list-row .monaco-highlighted-label .highlight {
				color: ${listHighlightForegroundColor};
			}
		`);
	}

B
Benjamin Pasero 已提交
528
	// We need to set the workbench background color so that on Windows we get subpixel-antialiasing.
529 530 531 532 533 534 535 536 537 538 539 540 541
	let workbenchBackground: string;
	switch (theme.type) {
		case 'dark':
			workbenchBackground = '#252526';
			break;
		case 'light':
			workbenchBackground = '#F3F3F3';
			break;
		default:
			workbenchBackground = '#000000';
	}
	collector.addRule(`.monaco-workbench { background-color: ${workbenchBackground}; }`);

B
Benjamin Pasero 已提交
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
	// Scrollbars
	const scrollbarShadowColor = theme.getColor(scrollbarShadow);
	if (scrollbarShadowColor) {
		collector.addRule(`
			.monaco-shell .monaco-scrollable-element > .shadow.top {
				box-shadow: ${scrollbarShadowColor} 0 6px 6px -6px inset;
			}

			.monaco-shell .monaco-scrollable-element > .shadow.left {
				box-shadow: ${scrollbarShadowColor} 6px 0 6px -6px inset;
			}

			.monaco-shell .monaco-scrollable-element > .shadow.top.left {
				box-shadow: ${scrollbarShadowColor} 6px 6px 6px -6px inset;
			}
		`);
	}

	const scrollbarSliderBackgroundColor = theme.getColor(scrollbarSliderBackground);
	if (scrollbarSliderBackgroundColor) {
		collector.addRule(`
			.monaco-shell .monaco-scrollable-element > .scrollbar > .slider {
				background: ${scrollbarSliderBackgroundColor};
			}
		`);
	}

	const scrollbarSliderHoverBackgroundColor = theme.getColor(scrollbarSliderHoverBackground);
	if (scrollbarSliderHoverBackgroundColor) {
		collector.addRule(`
			.monaco-shell .monaco-scrollable-element > .scrollbar > .slider:hover {
				background: ${scrollbarSliderHoverBackgroundColor};
			}
		`);
	}

	const scrollbarSliderActiveBackgroundColor = theme.getColor(scrollbarSliderActiveBackground);
	if (scrollbarSliderActiveBackgroundColor) {
		collector.addRule(`
			.monaco-shell .monaco-scrollable-element > .scrollbar > .slider.active {
				background: ${scrollbarSliderActiveBackgroundColor};
			}
		`);
	}

	// Focus outline
588
	const focusOutline = theme.getColor(focusBorder);
B
Benjamin Pasero 已提交
589 590 591 592 593 594 595 596
	if (focusOutline) {
		collector.addRule(`
			.monaco-shell [tabindex="0"]:focus,
			.monaco-shell .synthetic-focus,
			.monaco-shell select:focus,
			.monaco-shell .monaco-tree.focused.no-focused-item:focus:before,
			.monaco-shell input[type="button"]:focus,
			.monaco-shell input[type="text"]:focus,
B
Benjamin Pasero 已提交
597
			.monaco-shell button:focus,
B
Benjamin Pasero 已提交
598 599 600 601 602 603 604
			.monaco-shell textarea:focus,
			.monaco-shell input[type="search"]:focus,
			.monaco-shell input[type="checkbox"]:focus {
				outline-color: ${focusOutline};
			}
		`);
	}
605
});