windowsService.ts 10.5 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 13
import { IWindowsService, OpenContext } from 'vs/platform/windows/common/windows';
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 { ITelemetryData } from 'vs/platform/telemetry/common/telemetry';
19
import { ILifecycleService } from "vs/platform/lifecycle/electron-main/lifecycleMain";
B
Benjamin Pasero 已提交
20
import { IWindowsMainService, ISharedProcess } from "vs/platform/windows/electron-main/windows";
21
import { IHistoryMainService } from "vs/platform/history/electron-main/historyMainService";
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
renames  
Benjamin Pasero 已提交
53 54
	pickFileFolderAndOpen(windowId: number, forceNewWindow?: boolean, data?: ITelemetryData): TPromise<void> {
		this.windowsMainService.pickFileFolderAndOpen(forceNewWindow, data);
J
Joao Moreno 已提交
55 56 57
		return TPromise.as(null);
	}

B
renames  
Benjamin Pasero 已提交
58 59
	pickFileAndOpen(windowId: number, forceNewWindow?: boolean, path?: string, data?: ITelemetryData): TPromise<void> {
		this.windowsMainService.pickFileAndOpen(forceNewWindow, path, undefined, data);
J
Joao Moreno 已提交
60 61 62
		return TPromise.as(null);
	}

B
renames  
Benjamin Pasero 已提交
63
	pickFolderAndOpen(windowId: number, forceNewWindow?: boolean, data?: ITelemetryData): TPromise<void> {
B
Benjamin Pasero 已提交
64
		const codeWindow = this.windowsMainService.getWindowById(windowId);
B
renames  
Benjamin Pasero 已提交
65
		this.windowsMainService.pickFolderAndOpen(forceNewWindow, codeWindow, data);
66

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

70 71
	pickFolder(options?: { buttonLabel: string }): TPromise<string[]> {
		return this.windowsMainService.pickFolder(options);
72 73
	}

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

B
Benjamin Pasero 已提交
77 78
		if (codeWindow) {
			this.windowsMainService.reload(codeWindow);
79 80 81 82
		}

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

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

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

		return TPromise.as(null);
	}

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

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

		return TPromise.as(null);
	}
108

J
Joao Moreno 已提交
109
	closeFolder(windowId: number): TPromise<void> {
B
Benjamin Pasero 已提交
110
		const codeWindow = this.windowsMainService.getWindowById(windowId);
J
Joao Moreno 已提交
111

B
Benjamin Pasero 已提交
112 113
		if (codeWindow) {
			this.windowsMainService.open({ context: OpenContext.API, cli: this.environmentService.args, forceEmpty: true, windowToUse: codeWindow, forceReuseWindow: true });
114 115 116 117
		}

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

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

B
Benjamin Pasero 已提交
122 123
		if (codeWindow) {
			codeWindow.toggleFullScreen();
J
Joao Moreno 已提交
124 125 126 127 128
		}

		return TPromise.as(null);
	}

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

B
Benjamin Pasero 已提交
132 133
		if (codeWindow) {
			codeWindow.setRepresentedFilename(fileName);
134 135 136 137 138
		}

		return TPromise.as(null);
	}

139
	addToRecentlyOpen(paths: { path: string, isFile?: boolean }[]): TPromise<void> {
140
		this.historyService.addToRecentPathsList(paths);
141 142 143 144

		return TPromise.as(null);
	}

B
Benjamin Pasero 已提交
145
	removeFromRecentlyOpen(paths: string[]): TPromise<void> {
146
		this.historyService.removeFromRecentPathsList(paths);
B
Benjamin Pasero 已提交
147 148 149 150

		return TPromise.as(null);
	}

C
22768  
Cristian 已提交
151
	clearRecentPathsList(): TPromise<void> {
152
		this.historyService.clearRecentPathsList();
C
22768  
Cristian 已提交
153 154 155
		return TPromise.as(null);
	}

J
Joao Moreno 已提交
156
	getRecentlyOpen(windowId: number): TPromise<{ files: string[]; folders: string[]; }> {
B
Benjamin Pasero 已提交
157
		const codeWindow = this.windowsMainService.getWindowById(windowId);
J
Joao Moreno 已提交
158

B
Benjamin Pasero 已提交
159
		if (codeWindow) {
160
			const { files, folders } = this.historyService.getRecentPathsList(codeWindow.config.workspacePath, codeWindow.config.filesToOpen);
J
Joao Moreno 已提交
161 162 163 164 165 166
			return TPromise.as({ files, folders });
		}

		return TPromise.as({ files: [], folders: [] });
	}

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

B
Benjamin Pasero 已提交
170 171
		if (codeWindow) {
			codeWindow.win.focus();
J
Joao Moreno 已提交
172 173 174 175 176
		}

		return TPromise.as(null);
	}

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

B
Benjamin Pasero 已提交
180 181
		if (codeWindow) {
			return TPromise.as(codeWindow.win.isFocused());
182 183 184 185 186
		}

		return TPromise.as(null);
	}

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

B
Benjamin Pasero 已提交
190 191
		if (codeWindow) {
			return TPromise.as(codeWindow.win.isMaximized());
192 193 194 195 196 197
		}

		return TPromise.as(null);
	}

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

B
Benjamin Pasero 已提交
200 201
		if (codeWindow) {
			codeWindow.win.maximize();
202 203 204 205 206 207
		}

		return TPromise.as(null);
	}

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

B
Benjamin Pasero 已提交
210 211
		if (codeWindow) {
			codeWindow.win.unmaximize();
212 213 214 215 216 217
		}

		return TPromise.as(null);
	}

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

B
Benjamin Pasero 已提交
220 221
		if (codeWindow) {
			codeWindow.onWindowTitleDoubleClick();
222 223 224 225 226
		}

		return TPromise.as(null);
	}

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

B
Benjamin Pasero 已提交
230 231
		if (codeWindow && codeWindow.win.isDocumentEdited() !== flag) {
			codeWindow.win.setDocumentEdited(flag);
J
Joao Moreno 已提交
232 233 234 235 236
		}

		return TPromise.as(null);
	}

237
	openWindow(paths: string[], options?: { forceNewWindow?: boolean, forceReuseWindow?: boolean }): TPromise<void> {
J
Joao Moreno 已提交
238 239
		if (!paths || !paths.length) {
			return TPromise.as(null);
J
Joao Moreno 已提交
240 241
		}

C
chrmarti 已提交
242
		this.windowsMainService.open({ context: OpenContext.API, cli: this.environmentService.args, pathsToOpen: paths, forceNewWindow: options && options.forceNewWindow, forceReuseWindow: options && options.forceReuseWindow });
J
Joao Moreno 已提交
243 244
		return TPromise.as(null);
	}
J
Joao Moreno 已提交
245 246

	openNewWindow(): TPromise<void> {
C
chrmarti 已提交
247
		this.windowsMainService.openNewWindow(OpenContext.API);
J
Joao Moreno 已提交
248 249
		return TPromise.as(null);
	}
J
Joao Moreno 已提交
250 251

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

B
Benjamin Pasero 已提交
254 255
		if (codeWindow) {
			codeWindow.win.show();
J
Joao Moreno 已提交
256 257 258 259
		}

		return TPromise.as(null);
	}
J
Joao Moreno 已提交
260 261 262

	getWindows(): TPromise<{ id: number; path: string; title: string; }[]> {
		const windows = this.windowsMainService.getWindows();
263
		const result = windows.map(w => ({ path: w.openedWorkspacePath, title: w.win.getTitle(), id: w.id, filename: w.getRepresentedFilename() }));
264

J
Joao Moreno 已提交
265 266
		return TPromise.as(result);
	}
J
Joao Moreno 已提交
267

268 269 270 271
	getWindowCount(): TPromise<number> {
		return TPromise.as(this.windowsMainService.getWindows().length);
	}

J
Joao Moreno 已提交
272 273 274 275
	log(severity: string, ...messages: string[]): TPromise<void> {
		console[severity].apply(console, ...messages);
		return TPromise.as(null);
	}
276

B
Benjamin Pasero 已提交
277 278 279 280 281 282
	closeExtensionHostWindow(extensionDevelopmentPaths: string[]): TPromise<void> {
		extensionDevelopmentPaths.map(p => this.windowsMainService.findWindow(null, null, p)).forEach(windowOnExtension => {
			if (windowOnExtension) {
				windowOnExtension.win.close();
			}
		});
283 284 285

		return TPromise.as(null);
	}
J
Joao Moreno 已提交
286 287 288 289 290

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

292 293
	openExternal(url: string): TPromise<boolean> {
		return TPromise.as(shell.openExternal(url));
J
Joao Moreno 已提交
294
	}
295 296 297 298 299

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

301 302 303 304 305
	quit(): TPromise<void> {
		this.windowsMainService.quit();
		return TPromise.as(null);
	}

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

J
Johannes Rieken 已提交
309 310 311
		return TPromise.as(null);
	}

312 313 314 315
	whenSharedProcessReady(): TPromise<void> {
		return this.sharedProcess.whenReady();
	}

316 317 318 319 320
	toggleSharedProcess(): TPromise<void> {
		this.sharedProcess.toggle();
		return TPromise.as(null);
	}

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

C
chrmarti 已提交
325
		this.windowsMainService.open({ context: OpenContext.API, cli, pathsToOpen });
326 327 328
		return TPromise.as(null);
	}

329 330 331 332 333 334 335 336 337 338
	/**
	 * 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);
	}

339 340 341
	dispose(): void {
		this.disposables = dispose(this.disposables);
	}
342
}