windowsService.ts 10.6 KB
Newer Older
J
Joao Moreno 已提交
1 2 3 4 5 6 7 8
/*---------------------------------------------------------------------------------------------
 *  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 { TPromise } from 'vs/base/common/winjs.base';
9 10
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { assign } from 'vs/base/common/objects';
J
jordanmkasla2009 已提交
11
import URI from 'vs/base/common/uri';
B
Benjamin Pasero 已提交
12
import { IWindowsService, OpenContext, INativeOpenDialogOptions } from 'vs/platform/windows/common/windows';
B
Benjamin Pasero 已提交
13
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
J
Joao Moreno 已提交
14
import { shell, crashReporter, app } from 'electron';
15
import Event, { chain } from 'vs/base/common/event';
J
Joao Moreno 已提交
16
import { fromEventEmitter } from 'vs/base/node/event';
17
import { IURLService } from 'vs/platform/url/common/url';
18
import { ILifecycleService } from "vs/platform/lifecycle/electron-main/lifecycleMain";
B
Benjamin Pasero 已提交
19
import { IWindowsMainService, ISharedProcess } from "vs/platform/windows/electron-main/windows";
20
import { IHistoryMainService, IRecentlyOpened } from "vs/platform/history/common/history";
21
import { IWorkspaceIdentifier } from "vs/platform/workspaces/common/workspaces";
22

23
export class WindowsService implements IWindowsService, IDisposable {
J
Joao Moreno 已提交
24 25 26

	_serviceBrand: any;

27 28
	private disposables: IDisposable[] = [];

J
Joao Moreno 已提交
29
	onWindowOpen: Event<number> = fromEventEmitter(app, 'browser-window-created', (_, w: Electron.BrowserWindow) => w.id);
J
Joao Moreno 已提交
30 31
	onWindowFocus: Event<number> = fromEventEmitter(app, 'browser-window-focus', (_, w: Electron.BrowserWindow) => w.id);

J
Joao Moreno 已提交
32
	constructor(
33
		private sharedProcess: ISharedProcess,
34
		@IWindowsMainService private windowsMainService: IWindowsMainService,
35
		@IEnvironmentService private environmentService: IEnvironmentService,
36
		@IURLService urlService: IURLService,
37 38
		@ILifecycleService private lifecycleService: ILifecycleService,
		@IHistoryMainService private historyService: IHistoryMainService
39
	) {
40
		// Catch file URLs
41
		chain(urlService.onOpenURL)
42
			.filter(uri => uri.authority === 'file' && !!uri.path)
43
			.map(uri => URI.file(uri.fsPath))
44
			.on(this.openFileForURI, this, this.disposables);
45 46 47 48 49 50

		// Catch extension URLs when there are no windows open
		chain(urlService.onOpenURL)
			.filter(uri => /^extension/.test(uri.path))
			.filter(() => this.windowsMainService.getWindowCount() === 0)
			.on(this.openExtensionForURI, this, this.disposables);
51
	}
J
Joao Moreno 已提交
52

B
Benjamin Pasero 已提交
53 54 55
	pickFileFolderAndOpen(options: INativeOpenDialogOptions): TPromise<void> {
		this.windowsMainService.pickFileFolderAndOpen(options);

J
Joao Moreno 已提交
56 57 58
		return TPromise.as(null);
	}

B
Benjamin Pasero 已提交
59 60 61
	pickFileAndOpen(options: INativeOpenDialogOptions): TPromise<void> {
		this.windowsMainService.pickFileAndOpen(options);

J
Joao Moreno 已提交
62 63 64
		return TPromise.as(null);
	}

B
Benjamin Pasero 已提交
65 66
	pickFolderAndOpen(options: INativeOpenDialogOptions): TPromise<void> {
		this.windowsMainService.pickFolderAndOpen(options);
67

J
Joao Moreno 已提交
68 69
		return TPromise.as(null);
	}
70 71

	reloadWindow(windowId: number): TPromise<void> {
B
Benjamin Pasero 已提交
72
		const codeWindow = this.windowsMainService.getWindowById(windowId);
73

B
Benjamin Pasero 已提交
74 75
		if (codeWindow) {
			this.windowsMainService.reload(codeWindow);
76 77 78 79
		}

		return TPromise.as(null);
	}
J
Joao Moreno 已提交
80

J
Joao Moreno 已提交
81
	openDevTools(windowId: number): TPromise<void> {
B
Benjamin Pasero 已提交
82
		const codeWindow = this.windowsMainService.getWindowById(windowId);
J
Joao Moreno 已提交
83

B
Benjamin Pasero 已提交
84 85
		if (codeWindow) {
			codeWindow.win.webContents.openDevTools();
J
Joao Moreno 已提交
86 87 88 89 90
		}

		return TPromise.as(null);
	}

J
Joao Moreno 已提交
91
	toggleDevTools(windowId: number): TPromise<void> {
B
Benjamin Pasero 已提交
92
		const codeWindow = this.windowsMainService.getWindowById(windowId);
J
Joao Moreno 已提交
93

B
Benjamin Pasero 已提交
94 95 96
		if (codeWindow) {
			const contents = codeWindow.win.webContents;
			if (codeWindow.hasHiddenTitleBarStyle() && !codeWindow.win.isFullScreen() && !contents.isDevToolsOpened()) {
97 98 99 100
				contents.openDevTools({ mode: 'undocked' }); // due to https://github.com/electron/electron/issues/3647
			} else {
				contents.toggleDevTools();
			}
J
Joao Moreno 已提交
101 102 103 104
		}

		return TPromise.as(null);
	}
105

106
	closeWorkspace(windowId: number): TPromise<void> {
B
Benjamin Pasero 已提交
107
		const codeWindow = this.windowsMainService.getWindowById(windowId);
J
Joao Moreno 已提交
108

B
Benjamin Pasero 已提交
109
		if (codeWindow) {
110
			this.windowsMainService.closeWorkspace(codeWindow);
111 112 113 114
		}

		return TPromise.as(null);
	}
J
Joao Moreno 已提交
115

116 117 118 119 120 121 122 123 124 125
	openWorkspace(windowId: number): TPromise<void> {
		const codeWindow = this.windowsMainService.getWindowById(windowId);

		if (codeWindow) {
			this.windowsMainService.openWorkspace(codeWindow);
		}

		return TPromise.as(null);
	}

126 127 128 129 130 131 132 133 134 135
	newWorkspace(windowId: number): TPromise<void> {
		const codeWindow = this.windowsMainService.getWindowById(windowId);

		if (codeWindow) {
			this.windowsMainService.newWorkspace(codeWindow);
		}

		return TPromise.as(null);
	}

J
Joao Moreno 已提交
136
	toggleFullScreen(windowId: number): TPromise<void> {
B
Benjamin Pasero 已提交
137
		const codeWindow = this.windowsMainService.getWindowById(windowId);
J
Joao Moreno 已提交
138

B
Benjamin Pasero 已提交
139 140
		if (codeWindow) {
			codeWindow.toggleFullScreen();
J
Joao Moreno 已提交
141 142 143 144 145
		}

		return TPromise.as(null);
	}

146
	setRepresentedFilename(windowId: number, fileName: string): TPromise<void> {
B
Benjamin Pasero 已提交
147
		const codeWindow = this.windowsMainService.getWindowById(windowId);
148

B
Benjamin Pasero 已提交
149 150
		if (codeWindow) {
			codeWindow.setRepresentedFilename(fileName);
151 152 153 154 155
		}

		return TPromise.as(null);
	}

156 157
	addRecentlyOpened(files: string[]): TPromise<void> {
		this.historyService.addRecentlyOpened(void 0, files);
158 159 160 161

		return TPromise.as(null);
	}

162 163
	removeFromRecentlyOpened(paths: string[]): TPromise<void> {
		this.historyService.removeFromRecentlyOpened(paths);
B
Benjamin Pasero 已提交
164 165 166 167

		return TPromise.as(null);
	}

B
Benjamin Pasero 已提交
168 169
	clearRecentlyOpened(): TPromise<void> {
		this.historyService.clearRecentlyOpened();
170

C
22768  
Cristian 已提交
171 172 173
		return TPromise.as(null);
	}

174
	getRecentlyOpened(windowId: number): TPromise<IRecentlyOpened> {
B
Benjamin Pasero 已提交
175
		const codeWindow = this.windowsMainService.getWindowById(windowId);
J
Joao Moreno 已提交
176

B
Benjamin Pasero 已提交
177
		if (codeWindow) {
B
Benjamin Pasero 已提交
178
			return TPromise.as(this.historyService.getRecentlyOpened(codeWindow.config.workspace || codeWindow.config.folderPath, codeWindow.config.filesToOpen));
J
Joao Moreno 已提交
179 180
		}

B
Benjamin Pasero 已提交
181
		return TPromise.as(this.historyService.getRecentlyOpened());
J
Joao Moreno 已提交
182 183
	}

J
Joao Moreno 已提交
184
	focusWindow(windowId: number): TPromise<void> {
B
Benjamin Pasero 已提交
185
		const codeWindow = this.windowsMainService.getWindowById(windowId);
J
Joao Moreno 已提交
186

B
Benjamin Pasero 已提交
187 188
		if (codeWindow) {
			codeWindow.win.focus();
J
Joao Moreno 已提交
189 190 191 192 193
		}

		return TPromise.as(null);
	}

194 195 196 197 198 199 200 201 202 203
	closeWindow(windowId: number): TPromise<void> {
		const codeWindow = this.windowsMainService.getWindowById(windowId);

		if (codeWindow) {
			codeWindow.win.close();
		}

		return TPromise.as(null);
	}

204
	isFocused(windowId: number): TPromise<boolean> {
B
Benjamin Pasero 已提交
205
		const codeWindow = this.windowsMainService.getWindowById(windowId);
206

B
Benjamin Pasero 已提交
207 208
		if (codeWindow) {
			return TPromise.as(codeWindow.win.isFocused());
209 210 211 212 213
		}

		return TPromise.as(null);
	}

214
	isMaximized(windowId: number): TPromise<boolean> {
B
Benjamin Pasero 已提交
215
		const codeWindow = this.windowsMainService.getWindowById(windowId);
216

B
Benjamin Pasero 已提交
217 218
		if (codeWindow) {
			return TPromise.as(codeWindow.win.isMaximized());
219 220 221 222 223 224
		}

		return TPromise.as(null);
	}

	maximizeWindow(windowId: number): TPromise<void> {
B
Benjamin Pasero 已提交
225
		const codeWindow = this.windowsMainService.getWindowById(windowId);
226

B
Benjamin Pasero 已提交
227 228
		if (codeWindow) {
			codeWindow.win.maximize();
229 230 231 232 233 234
		}

		return TPromise.as(null);
	}

	unmaximizeWindow(windowId: number): TPromise<void> {
B
Benjamin Pasero 已提交
235
		const codeWindow = this.windowsMainService.getWindowById(windowId);
236

B
Benjamin Pasero 已提交
237 238
		if (codeWindow) {
			codeWindow.win.unmaximize();
239 240 241 242 243 244
		}

		return TPromise.as(null);
	}

	onWindowTitleDoubleClick(windowId: number): TPromise<void> {
B
Benjamin Pasero 已提交
245
		const codeWindow = this.windowsMainService.getWindowById(windowId);
246

B
Benjamin Pasero 已提交
247 248
		if (codeWindow) {
			codeWindow.onWindowTitleDoubleClick();
249 250 251 252 253
		}

		return TPromise.as(null);
	}

J
Joao Moreno 已提交
254
	setDocumentEdited(windowId: number, flag: boolean): TPromise<void> {
B
Benjamin Pasero 已提交
255
		const codeWindow = this.windowsMainService.getWindowById(windowId);
J
Joao Moreno 已提交
256

B
Benjamin Pasero 已提交
257 258
		if (codeWindow && codeWindow.win.isDocumentEdited() !== flag) {
			codeWindow.win.setDocumentEdited(flag);
J
Joao Moreno 已提交
259 260 261 262 263
		}

		return TPromise.as(null);
	}

264
	openWindow(paths: string[], options?: { forceNewWindow?: boolean, forceReuseWindow?: boolean, forceOpenWorkspaceAsFile?: boolean }): TPromise<void> {
J
Joao Moreno 已提交
265 266
		if (!paths || !paths.length) {
			return TPromise.as(null);
J
Joao Moreno 已提交
267 268
		}

269 270 271 272 273 274 275 276 277
		this.windowsMainService.open({
			context: OpenContext.API,
			cli: this.environmentService.args,
			pathsToOpen: paths,
			forceNewWindow: options && options.forceNewWindow,
			forceReuseWindow: options && options.forceReuseWindow,
			forceOpenWorkspaceAsFile: options && options.forceOpenWorkspaceAsFile
		});

J
Joao Moreno 已提交
278 279
		return TPromise.as(null);
	}
J
Joao Moreno 已提交
280 281

	openNewWindow(): TPromise<void> {
C
chrmarti 已提交
282
		this.windowsMainService.openNewWindow(OpenContext.API);
J
Joao Moreno 已提交
283 284
		return TPromise.as(null);
	}
J
Joao Moreno 已提交
285 286

	showWindow(windowId: number): TPromise<void> {
B
Benjamin Pasero 已提交
287
		const codeWindow = this.windowsMainService.getWindowById(windowId);
J
Joao Moreno 已提交
288

B
Benjamin Pasero 已提交
289 290
		if (codeWindow) {
			codeWindow.win.show();
J
Joao Moreno 已提交
291 292 293 294
		}

		return TPromise.as(null);
	}
J
Joao Moreno 已提交
295

296
	getWindows(): TPromise<{ id: number; workspace?: IWorkspaceIdentifier; folderPath?: string; title: string; filename?: string; }[]> {
J
Joao Moreno 已提交
297
		const windows = this.windowsMainService.getWindows();
298
		const result = windows.map(w => ({ id: w.id, workspace: w.openedWorkspace, openedFolderPath: w.openedFolderPath, title: w.win.getTitle(), filename: w.getRepresentedFilename() }));
299

J
Joao Moreno 已提交
300 301
		return TPromise.as(result);
	}
J
Joao Moreno 已提交
302

303 304 305 306
	getWindowCount(): TPromise<number> {
		return TPromise.as(this.windowsMainService.getWindows().length);
	}

J
Joao Moreno 已提交
307 308 309 310
	log(severity: string, ...messages: string[]): TPromise<void> {
		console[severity].apply(console, ...messages);
		return TPromise.as(null);
	}
311

J
Joao Moreno 已提交
312 313 314 315
	showItemInFolder(path: string): TPromise<void> {
		shell.showItemInFolder(path);
		return TPromise.as(null);
	}
J
Joao Moreno 已提交
316

317 318
	openExternal(url: string): TPromise<boolean> {
		return TPromise.as(shell.openExternal(url));
J
Joao Moreno 已提交
319
	}
320 321 322 323 324

	startCrashReporter(config: Electron.CrashReporterStartOptions): TPromise<void> {
		crashReporter.start(config);
		return TPromise.as(null);
	}
325

326 327 328 329 330
	quit(): TPromise<void> {
		this.windowsMainService.quit();
		return TPromise.as(null);
	}

J
Johannes Rieken 已提交
331
	relaunch(options: { addArgs?: string[], removeArgs?: string[] }): TPromise<void> {
332 333
		this.lifecycleService.relaunch(options);

J
Johannes Rieken 已提交
334 335 336
		return TPromise.as(null);
	}

337 338 339 340
	whenSharedProcessReady(): TPromise<void> {
		return this.sharedProcess.whenReady();
	}

341 342 343 344 345
	toggleSharedProcess(): TPromise<void> {
		this.sharedProcess.toggle();
		return TPromise.as(null);
	}

346
	private openFileForURI(uri: URI): TPromise<void> {
347
		const cli = assign(Object.create(null), this.environmentService.args, { goto: true });
348
		const pathsToOpen = [uri.fsPath];
349

C
chrmarti 已提交
350
		this.windowsMainService.open({ context: OpenContext.API, cli, pathsToOpen });
351 352 353
		return TPromise.as(null);
	}

354 355 356 357 358 359 360 361 362 363
	/**
	 * This should only fire whenever an extension URL is open
	 * and there are no windows to handle it.
	 */
	private openExtensionForURI(uri: URI): TPromise<void> {
		const cli = assign(Object.create(null), this.environmentService.args);
		this.windowsMainService.open({ context: OpenContext.API, cli });
		return TPromise.as(null);
	}

364 365 366
	dispose(): void {
		this.disposables = dispose(this.disposables);
	}
367
}