shell.ts 21.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, Disposables } 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 20
import product from 'vs/platform/product';
import pkg from 'vs/platform/package';
21
import * as browser from 'vs/base/browser/browser';
J
Johannes Rieken 已提交
22
import { ContextViewService } from 'vs/platform/contextview/browser/contextViewService';
E
Erich Gamma 已提交
23
import timer = require('vs/base/common/timer');
J
Johannes Rieken 已提交
24
import { Workbench } from 'vs/workbench/electron-browser/workbench';
B
Benjamin Pasero 已提交
25
import { StorageService, inMemoryLocalStorageInstance } from 'vs/workbench/services/storage/common/storageService';
J
Johannes Rieken 已提交
26 27 28 29
import { ITelemetryService, NullTelemetryService, loadExperiments } from 'vs/platform/telemetry/common/telemetry';
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';
J
Johannes Rieken 已提交
31 32 33
import { resolveWorkbenchCommonProperties } from 'vs/platform/telemetry/node/workbenchCommonProperties';
import { ElectronIntegration } from 'vs/workbench/electron-browser/integration';
import { WorkspaceStats } from 'vs/workbench/services/telemetry/common/workspaceStats';
J
Joao Moreno 已提交
34 35 36 37
import { IWindowIPCService, WindowIPCService } from 'vs/workbench/services/window/electron-browser/windowService';
import { IWindowsService, IWindowService } from 'vs/platform/windows/common/windows';
import { WindowsChannelClient } from 'vs/platform/windows/common/windowsIpc';
import { WindowService } from 'vs/platform/windows/electron-browser/windowService';
J
Johannes Rieken 已提交
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
import { MessageService } from 'vs/workbench/services/message/electron-browser/messageService';
import { IRequestService } from 'vs/platform/request/common/request';
import { RequestService } from 'vs/platform/request/node/requestService';
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 { MainThreadService } from 'vs/workbench/services/thread/electron-browser/threadService';
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';
import { MainProcessExtensionService } from 'vs/workbench/api/node/mainThreadExtensionService';
import { IOptions } from 'vs/workbench/common/options';
import { IStorageService } from 'vs/platform/storage/common/storage';
J
Joao Moreno 已提交
57
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
J
Johannes Rieken 已提交
58 59 60 61 62 63 64 65 66 67 68 69 70 71
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
import { IEventService } from 'vs/platform/event/common/event';
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { IMarkerService } from 'vs/platform/markers/common/markers';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IMessageService, IChoiceService, Severity } from 'vs/platform/message/common/message';
import { ChoiceChannel } from 'vs/platform/message/common/messageIpc';
import { ISearchService } from 'vs/platform/search/common/search';
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { CommandService } from 'vs/platform/commands/common/commandService';
import { IWorkspaceContextService, IWorkspace } from 'vs/platform/workspace/common/workspace';
72
import { IExtensionService } from 'vs/platform/extensions/common/extensions';
J
Johannes Rieken 已提交
73 74 75 76 77 78 79 80
import { MainThreadModeServiceImpl } from 'vs/editor/common/services/modeServiceImpl';
import { IModeService } from 'vs/editor/common/services/modeService';
import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
import { CrashReporter } from 'vs/workbench/electron-browser/crashReporter';
import { IThemeService } from 'vs/workbench/services/themes/common/themeService';
import { ThemeService } from 'vs/workbench/services/themes/electron-browser/themeService';
import { getDelayedChannel } from 'vs/base/parts/ipc/common/ipc';
import { connect as connectNet } from 'vs/base/parts/ipc/node/ipc.net';
81
import { Client as ElectronIPCClient } from 'vs/base/parts/ipc/electron-browser/ipc.electron-browser';
J
Johannes Rieken 已提交
82
import { IExtensionManagementChannel, ExtensionManagementChannelClient } from 'vs/platform/extensionManagement/common/extensionManagementIpc';
83 84
import { IExtensionManagementService, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionEnablementService';
J
Johannes Rieken 已提交
85 86 87 88
import { URLChannelClient } from 'vs/platform/url/common/urlIpc';
import { IURLService } from 'vs/platform/url/common/url';
import { ReloadWindowAction } from 'vs/workbench/electron-browser/actions';
import { WorkspaceConfigurationService } from 'vs/workbench/services/configuration/node/configurationService';
S
Sandeep Somavarapu 已提交
89
import { ExtensionHostProcessWorker } from 'vs/workbench/electron-browser/extensionHost';
90
import { remote, webFrame } from 'electron';
91 92

// self registering services
93
import 'vs/platform/opener/browser/opener.contribution';
94

95 96 97 98 99 100 101
/**
 * Services that we require for the Shell
 */
export interface ICoreServices {
	contextService: IWorkspaceContextService;
	eventService: IEventService;
	configurationService: IConfigurationService;
102
	environmentService: IEnvironmentService;
103 104
}

E
Erich Gamma 已提交
105
/**
B
Benjamin Pasero 已提交
106
 * The workbench shell contains the workbench with a rich header containing navigation and the activity bar.
E
Erich Gamma 已提交
107 108 109
 * 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 已提交
110
	private storageService: IStorageService;
111
	private messageService: MessageService;
112
	private eventService: IEventService;
J
Johannes Rieken 已提交
113
	private environmentService: IEnvironmentService;
B
Benjamin Pasero 已提交
114 115
	private contextViewService: ContextViewService;
	private threadService: MainThreadService;
116
	private configurationService: IConfigurationService;
M
Martin Aeschlimann 已提交
117
	private themeService: ThemeService;
118
	private contextService: IWorkspaceContextService;
119
	private telemetryService: ITelemetryService;
E
Erich Gamma 已提交
120 121

	private container: HTMLElement;
122
	private toUnbind: IDisposable[];
E
Erich Gamma 已提交
123 124 125 126 127 128 129 130 131
	private previousErrorValue: string;
	private previousErrorTime: number;
	private content: HTMLElement;
	private contentsContainer: Builder;

	private workspace: IWorkspace;
	private options: IOptions;
	private workbench: Workbench;

132
	constructor(container: HTMLElement, workspace: IWorkspace, services: ICoreServices, options: IOptions) {
E
Erich Gamma 已提交
133 134 135
		this.container = container;

		this.workspace = workspace;
136 137 138 139 140
		this.options = options;

		this.contextService = services.contextService;
		this.eventService = services.eventService;
		this.configurationService = services.configurationService;
141
		this.environmentService = services.environmentService;
E
Erich Gamma 已提交
142 143 144 145 146 147 148

		this.toUnbind = [];
		this.previousErrorTime = 0;
	}

	private createContents(parent: Builder): Builder {

149
		// ARIA
B
Benjamin Pasero 已提交
150
		aria.setARIAContainer(document.body);
151

E
Erich Gamma 已提交
152
		// Workbench Container
153
		const workbenchContainer = $(parent).div();
E
Erich Gamma 已提交
154 155

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

		//crash reporting
159
		if (!!product.crashReporter) {
160
			instantiationService.createInstance(CrashReporter, product.crashReporter);
E
Erich Gamma 已提交
161 162 163
		}

		// Workbench
B
Benjamin Pasero 已提交
164
		this.workbench = instantiationService.createInstance(Workbench, parent.getHTMLElement(), workbenchContainer.getHTMLElement(), this.workspace, this.options, serviceCollection);
E
Erich Gamma 已提交
165
		this.workbench.startup({
166 167
			onWorkbenchStarted: (customKeybindingsCount) => {
				this.onWorkbenchStarted(customKeybindingsCount);
E
Erich Gamma 已提交
168 169 170 171 172 173 174
			}
		});

		// Electron integration
		this.workbench.getInstantiationService().createInstance(ElectronIntegration).integrate(this.container);

		// Handle case where workbench is not starting up properly
175
		const timeoutHandle = setTimeout(() => {
E
Erich Gamma 已提交
176 177 178 179 180 181 182 183 184 185
			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;
	}

186
	private onWorkbenchStarted(customKeybindingsCount: number): void {
B
Benjamin Pasero 已提交
187 188

		// Log to telemetry service
189
		const windowSize = {
B
Benjamin Pasero 已提交
190 191 192 193 194 195 196 197 198 199 200
			innerHeight: window.innerHeight,
			innerWidth: window.innerWidth,
			outerHeight: window.outerHeight,
			outerWidth: window.outerWidth
		};

		this.telemetryService.publicLog('workspaceLoad',
			{
				userAgent: navigator.userAgent,
				windowSize: windowSize,
				emptyWorkbench: !this.contextService.getWorkspace(),
201
				customKeybindingsCount,
M
Martin Aeschlimann 已提交
202
				theme: this.themeService.getColorTheme(),
203 204
				language: platform.language,
				experiments: this.telemetryService.getExperiments()
B
Benjamin Pasero 已提交
205 206
			});

207
		const workspaceStats: WorkspaceStats = <WorkspaceStats>this.workbench.getInstantiationService().createInstance(WorkspaceStats);
B
Benjamin Pasero 已提交
208
		workspaceStats.reportWorkspaceTags();
J
Joao Moreno 已提交
209 210 211 212

		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 已提交
213 214
	}

215
	private initServiceCollection(container: HTMLElement): [IInstantiationService, ServiceCollection] {
J
Joao Moreno 已提交
216 217
		const disposables = new Disposables();

218
		const mainProcessClient = new ElectronIPCClient(String(`window${remote.getCurrentWindow().id}`));
J
Joao Moreno 已提交
219
		disposables.add(mainProcessClient);
J
Joao Moreno 已提交
220

221 222 223 224
		const serviceCollection = new ServiceCollection();
		serviceCollection.set(IEventService, this.eventService);
		serviceCollection.set(IWorkspaceContextService, this.contextService);
		serviceCollection.set(IConfigurationService, this.configurationService);
225
		serviceCollection.set(IEnvironmentService, this.environmentService);
226

J
Joao Moreno 已提交
227 228
		const instantiationServiceImpl = new InstantiationService(serviceCollection, true);
		const instantiationService = instantiationServiceImpl as IInstantiationService;
229

J
Joao Moreno 已提交
230 231 232
		// TODO@joao remove this
		const windowIPCService = instantiationService.createInstance<IWindowIPCService>(WindowIPCService);
		serviceCollection.set(IWindowIPCService, windowIPCService);
233

J
Joao Moreno 已提交
234 235 236 237 238 239 240 241
		const windowsChannel = mainProcessClient.getChannel('windows');
		const windowsChannelClient = new WindowsChannelClient(windowsChannel);
		serviceCollection.set(IWindowsService, windowsChannelClient);

		const windowService = new WindowService(windowIPCService.getWindowId(), windowsChannelClient);
		serviceCollection.set(IWindowService, windowService);

		const sharedProcess = connectNet(this.environmentService.sharedIPCHandle, `window:${windowIPCService.getWindowId()}`);
242
		sharedProcess.done(client => {
S
Sandeep Somavarapu 已提交
243 244 245

			client.registerChannel('choice', new ChoiceChannel(this.messageService));

246 247 248 249 250 251 252 253
			client.onClose(() => {
				this.messageService.show(Severity.Error, {
					message: nls.localize('sharedProcessCrashed', "The shared process terminated unexpectedly. Please reload the window to recover."),
					actions: [instantiationService.createInstance(ReloadWindowAction, ReloadWindowAction.ID, ReloadWindowAction.LABEL)]
				});
			});
		}, errors.onUnexpectedError);

B
Benjamin Pasero 已提交
254
		// Storage Sevice
255
		const disableWorkspaceStorage = this.environmentService.extensionTestsPath || (!this.workspace && !this.environmentService.extensionDevelopmentPath); // without workspace or in any extension test, we use inMemory storage unless we develop an extension where we want to preserve state
B
Benjamin Pasero 已提交
256
		this.storageService = instantiationService.createInstance(StorageService, window.localStorage, disableWorkspaceStorage ? inMemoryLocalStorageInstance : window.localStorage);
257
		serviceCollection.set(IStorageService, this.storageService);
E
Erich Gamma 已提交
258

259
		// Telemetry
260
		if (this.environmentService.isBuilt && !this.environmentService.extensionDevelopmentPath && !!product.enableTelemetry) {
261
			const channel = getDelayedChannel<ITelemetryAppenderChannel>(sharedProcess.then(c => c.getChannel('telemetryAppender')));
262 263
			const commit = product.commit;
			const version = pkg.version;
264

265
			const config: ITelemetryServiceConfig = {
266
				appender: new TelemetryAppenderClient(channel),
267
				commonProperties: resolveWorkbenchCommonProperties(this.storageService, commit, version),
268
				piiPaths: [this.environmentService.appRoot, this.environmentService.extensionsPath],
269
				experiments: loadExperiments(this.storageService, this.configurationService)
270
			};
271

J
Joao Moreno 已提交
272
			const telemetryService = instantiationService.createInstance(TelemetryService, config);
273 274
			this.telemetryService = telemetryService;

J
Joao Moreno 已提交
275
			const errorTelemetry = new ErrorTelemetry(telemetryService);
276
			const idleMonitor = new IdleMonitor(2 * 60 * 1000); // 2 minutes
277

278 279 280 281
			const listener = idleMonitor.onStatusChange(status =>
				this.telemetryService.publicLog(status === UserStatus.Active
					? TelemetryService.IDLE_STOP_EVENT_NAME
					: TelemetryService.IDLE_START_EVENT_NAME
282
				));
283

284
			disposables.add(telemetryService, errorTelemetry, listener, idleMonitor);
285
		} else {
286
			NullTelemetryService._experiments = loadExperiments(this.storageService, this.configurationService);
287
			this.telemetryService = NullTelemetryService;
288
		}
E
Erich Gamma 已提交
289

290
		serviceCollection.set(ITelemetryService, this.telemetryService);
291 292 293
		if (this.configurationService instanceof WorkspaceConfigurationService) {
			this.configurationService.telemetryService = this.telemetryService;
		}
E
Erich Gamma 已提交
294

295
		this.messageService = instantiationService.createInstance(MessageService, container);
296
		serviceCollection.set(IMessageService, this.messageService);
J
Joao Moreno 已提交
297
		serviceCollection.set(IChoiceService, this.messageService);
E
Erich Gamma 已提交
298

299
		const lifecycleService = instantiationService.createInstance(LifecycleService);
300 301
		this.toUnbind.push(lifecycleService.onShutdown(() => disposables.dispose()));
		serviceCollection.set(ILifecycleService, lifecycleService);
302

S
Sandeep Somavarapu 已提交
303 304 305 306
		const extensionManagementChannel = getDelayedChannel<IExtensionManagementChannel>(sharedProcess.then(c => c.getChannel('extensions')));
		const extensionManagementChannelClient = new ExtensionManagementChannelClient(extensionManagementChannel);
		serviceCollection.set(IExtensionManagementService, extensionManagementChannelClient);

307 308 309
		const extensionEnablementService = instantiationService.createInstance(ExtensionEnablementService);
		serviceCollection.set(IExtensionEnablementService, extensionEnablementService);
		disposables.add(extensionEnablementService);
310

311
		const extensionHostProcessWorker = instantiationService.createInstance(ExtensionHostProcessWorker);
312
		this.threadService = instantiationService.createInstance(MainThreadService, extensionHostProcessWorker.messagingProtocol);
313
		serviceCollection.set(IThreadService, this.threadService);
314

315
		const extensionService = instantiationService.createInstance(MainProcessExtensionService);
316
		serviceCollection.set(IExtensionService, extensionService);
317
		extensionHostProcessWorker.start(extensionService);
E
Erich Gamma 已提交
318

319 320
		serviceCollection.set(ICommandService, new CommandService(instantiationService, extensionService));

321 322
		this.contextViewService = instantiationService.createInstance(ContextViewService, this.container);
		serviceCollection.set(IContextViewService, this.contextViewService);
E
Erich Gamma 已提交
323

J
Joao Moreno 已提交
324
		const requestService = instantiationService.createInstance(RequestService);
325
		serviceCollection.set(IRequestService, requestService);
E
Erich Gamma 已提交
326

327
		const markerService = instantiationService.createInstance(MarkerService);
328
		serviceCollection.set(IMarkerService, markerService);
E
Erich Gamma 已提交
329

330
		const modeService = instantiationService.createInstance(MainThreadModeServiceImpl);
331
		serviceCollection.set(IModeService, modeService);
332

333
		const modelService = instantiationService.createInstance(ModelServiceImpl);
334
		serviceCollection.set(IModelService, modelService);
335

336
		const editorWorkerService = instantiationService.createInstance(EditorWorkerServiceImpl);
337
		serviceCollection.set(IEditorWorkerService, editorWorkerService);
338

339
		const untitledEditorService = instantiationService.createInstance(UntitledEditorService);
340 341 342
		serviceCollection.set(IUntitledEditorService, untitledEditorService);

		this.themeService = instantiationService.createInstance(ThemeService);
343
		serviceCollection.set(IThemeService, this.themeService);
344

345
		const searchService = instantiationService.createInstance(SearchService);
346 347
		serviceCollection.set(ISearchService, searchService);

J
Joao Moreno 已提交
348
		const codeEditorService = instantiationServiceImpl.createInstance(CodeEditorServiceImpl);
349 350
		serviceCollection.set(ICodeEditorService, codeEditorService);

A
Alex Dima 已提交
351 352 353
		const integrityService = instantiationService.createInstance(IntegrityServiceImpl);
		serviceCollection.set(IIntegrityService, integrityService);

J
Joao Moreno 已提交
354
		const urlChannel = mainProcessClient.getChannel('url');
J
Joao Moreno 已提交
355
		const urlChannelClient = new URLChannelClient(urlChannel, windowIPCService.getWindowId());
J
Joao Moreno 已提交
356 357
		serviceCollection.set(IURLService, urlChannelClient);

J
Joao Moreno 已提交
358
		return [instantiationServiceImpl, serviceCollection];
E
Erich Gamma 已提交
359 360 361 362 363 364 365 366 367
	}

	public open(): void {

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

368 369
		// Ensure others can listen to zoom level changes
		browser.setZoomLevel(webFrame.getZoomLevel());
B
Benjamin Pasero 已提交
370
		browser.setZoomFactor(webFrame.getZoomFactor());
371

E
Erich Gamma 已提交
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
		// Shell Class for CSS Scoping
		$(this.container).addClass('monaco-shell');

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

		// Handle Load Performance Timers
		this.writeTimers();

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

		// Layout
		this.layout();

		// Listeners
		this.registerListeners();

		// Enable theme support
M
Martin Aeschlimann 已提交
391
		this.themeService.initialize(this.container).then(null, error => {
392 393
			errors.onUnexpectedError(error);
		});
E
Erich Gamma 已提交
394 395 396 397 398 399 400 401 402
	}

	private registerListeners(): void {

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

	private writeTimers(): void {
403
		const timers = (<any>window).MonacoEnvironment.timers;
E
Erich Gamma 已提交
404
		if (timers) {
405
			const events: timer.IExistingTimerEvent[] = [];
E
Erich Gamma 已提交
406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441

			// Window
			if (timers.vscodeStart) {
				events.push({
					startTime: timers.vscodeStart,
					stopTime: timers.beforeLoad,
					topic: 'Startup',
					name: 'VSCode Startup',
					description: 'Time it takes to create a window and startup VSCode'
				});
			}

			// Load
			events.push({
				startTime: timers.beforeLoad,
				stopTime: timers.afterLoad,
				topic: 'Startup',
				name: 'Load Modules',
				description: 'Time it takes to load VSCodes main modules'
			});

			// Ready
			events.push({
				startTime: timers.beforeReady,
				stopTime: timers.afterReady,
				topic: 'Startup',
				name: 'Event DOMContentLoaded',
				description: 'Time it takes for the DOM to emit DOMContentLoaded event'
			});

			// Write to Timer
			timer.getTimeKeeper().setInitialCollectedEvents(events, timers.start);
		}
	}

	public onUnexpectedError(error: any): void {
442
		const errorMsg = toErrorMessage(error, true);
E
Erich Gamma 已提交
443 444 445 446
		if (!errorMsg) {
			return;
		}

447
		const now = Date.now();
E
Erich Gamma 已提交
448 449 450 451 452 453 454 455 456 457 458
		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
459
		if (error && error.friendlyMessage && this.messageService) {
B
Benjamin Pasero 已提交
460
			this.messageService.show(Severity.Error, error.friendlyMessage);
E
Erich Gamma 已提交
461 462 463
		}
	}

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

467
		const contentsSize = new Dimension(clArea.width, clArea.height);
E
Erich Gamma 已提交
468 469
		this.contentsContainer.size(contentsSize.width, contentsSize.height);

B
Benjamin Pasero 已提交
470
		this.contextViewService.layout();
E
Erich Gamma 已提交
471 472 473 474 475 476 477
		this.workbench.layout();
	}

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

B
Benjamin Pasero 已提交
478
	public dispose(): void {
E
Erich Gamma 已提交
479 480 481

		// Workbench
		if (this.workbench) {
B
Benjamin Pasero 已提交
482
			this.workbench.dispose();
E
Erich Gamma 已提交
483 484
		}

B
Benjamin Pasero 已提交
485
		this.contextViewService.dispose();
E
Erich Gamma 已提交
486 487

		// Listeners
J
Joao Moreno 已提交
488
		this.toUnbind = dispose(this.toUnbind);
E
Erich Gamma 已提交
489 490 491 492 493

		// Container
		$(this.container).empty();
	}
}