Skip to content

Commit d6428a8

Browse files
author
Benjamin Pasero
committed
perf - move more things to after first window opens
1 parent 10c56b5 commit d6428a8

1 file changed

Lines changed: 117 additions & 120 deletions

File tree

  • src/vs/code/electron-main

src/vs/code/electron-main/app.ts

Lines changed: 117 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import { app, ipcMain as ipc, systemPreferences, shell, Event, contentTracing, protocol } from 'electron';
7-
import * as platform from 'vs/base/common/platform';
7+
import { IProcessEnvironment, isWindows, isMacintosh } from 'vs/base/common/platform';
88
import { WindowsManager } from 'vs/code/electron-main/windows';
99
import { IWindowsService, OpenContext, ActiveWindowManager } from 'vs/platform/windows/common/windows';
1010
import { WindowsChannel } from 'vs/platform/windows/node/windowsIpc';
@@ -88,7 +88,7 @@ export class CodeApplication extends Disposable {
8888

8989
constructor(
9090
private mainIpcServer: Server,
91-
private userEnv: platform.IProcessEnvironment,
91+
private userEnv: IProcessEnvironment,
9292
@IInstantiationService private instantiationService: IInstantiationService,
9393
@ILogService private logService: ILogService,
9494
@IEnvironmentService private environmentService: IEnvironmentService,
@@ -138,12 +138,27 @@ export class CodeApplication extends Disposable {
138138
app.on('web-contents-created', (event: any, contents) => {
139139
contents.on('will-attach-webview', (event: Electron.Event, webPreferences, params) => {
140140

141+
const isValidWebviewSource = (source: string): boolean => {
142+
if (!source) {
143+
return false;
144+
}
145+
146+
if (source === 'data:text/html;charset=utf-8,%3C%21DOCTYPE%20html%3E%0D%0A%3Chtml%20lang%3D%22en%22%20style%3D%22width%3A%20100%25%3B%20height%3A%20100%25%22%3E%0D%0A%3Chead%3E%0D%0A%09%3Ctitle%3EVirtual%20Document%3C%2Ftitle%3E%0D%0A%3C%2Fhead%3E%0D%0A%3Cbody%20style%3D%22margin%3A%200%3B%20overflow%3A%20hidden%3B%20width%3A%20100%25%3B%20height%3A%20100%25%22%3E%0D%0A%3C%2Fbody%3E%0D%0A%3C%2Fhtml%3E') {
147+
return true;
148+
}
149+
150+
const srcUri: any = URI.parse(source).fsPath.toLowerCase();
151+
const rootUri = URI.file(this.environmentService.appRoot).fsPath.toLowerCase();
152+
153+
return srcUri.startsWith(rootUri + nativeSep);
154+
};
155+
141156
// Ensure defaults
142157
delete webPreferences.preload;
143158
webPreferences.nodeIntegration = false;
144159

145160
// Verify URLs being loaded
146-
if (this.isValidWebviewSource(params.src) && this.isValidWebviewSource(webPreferences.preloadURL)) {
161+
if (isValidWebviewSource(params.src) && isValidWebviewSource(webPreferences.preloadURL)) {
147162
return;
148163
}
149164

@@ -168,85 +183,6 @@ export class CodeApplication extends Disposable {
168183
});
169184
});
170185

171-
const connectionPool: Map<string, ActiveConnection> = new Map<string, ActiveConnection>();
172-
173-
class ActiveConnection {
174-
private _authority: string;
175-
private _client: Promise<Client<RemoteAgentConnectionContext>>;
176-
private _disposeRunner: RunOnceScheduler;
177-
178-
constructor(authority: string, host: string, port: number) {
179-
this._authority = authority;
180-
this._client = connectRemoteAgentManagement(authority, host, port, `main`);
181-
this._disposeRunner = new RunOnceScheduler(() => this._dispose(), 5000);
182-
}
183-
184-
private _dispose(): void {
185-
this._disposeRunner.dispose();
186-
connectionPool.delete(this._authority);
187-
this._client.then((connection) => {
188-
connection.dispose();
189-
});
190-
}
191-
192-
public getClient(): Promise<Client<RemoteAgentConnectionContext>> {
193-
this._disposeRunner.schedule();
194-
return this._client;
195-
}
196-
}
197-
198-
const resolvedAuthorities = new Map<string, ResolvedAuthority>();
199-
ipc.on('vscode:remoteAuthorityResolved', (event: any, data: ResolvedAuthority) => {
200-
resolvedAuthorities.set(data.authority, data);
201-
});
202-
const resolveAuthority = (authority: string): ResolvedAuthority | null => {
203-
if (authority.indexOf('+') >= 0) {
204-
if (resolvedAuthorities.has(authority)) {
205-
return resolvedAuthorities.get(authority);
206-
}
207-
return null;
208-
} else {
209-
const [host, strPort] = authority.split(':');
210-
const port = parseInt(strPort, 10);
211-
return { authority, host, port, syncExtensions: false };
212-
}
213-
};
214-
215-
protocol.registerBufferProtocol(REMOTE_HOST_SCHEME, async (request, callback) => {
216-
if (request.method !== 'GET') {
217-
return callback(null);
218-
}
219-
const uri = URI.parse(request.url);
220-
221-
let activeConnection: ActiveConnection = null;
222-
if (connectionPool.has(uri.authority)) {
223-
activeConnection = connectionPool.get(uri.authority);
224-
} else {
225-
let resolvedAuthority = resolveAuthority(uri.authority);
226-
if (!resolvedAuthority) {
227-
callback(null);
228-
return;
229-
}
230-
activeConnection = new ActiveConnection(uri.authority, resolvedAuthority.host, resolvedAuthority.port);
231-
connectionPool.set(uri.authority, activeConnection);
232-
}
233-
try {
234-
const rawClient = await activeConnection.getClient();
235-
if (connectionPool.has(uri.authority)) { // not disposed in the meantime
236-
const channel = rawClient.getChannel(REMOTE_FILE_SYSTEM_CHANNEL_NAME);
237-
238-
// TODO@alex don't use call directly, wrap it around a `RemoteExtensionsFileSystemProvider`
239-
const fileContents = await channel.call<Uint8Array>('readFile', [uri]);
240-
callback(Buffer.from(fileContents));
241-
} else {
242-
callback(null);
243-
}
244-
} catch (err) {
245-
errors.onUnexpectedError(err);
246-
callback(null);
247-
}
248-
});
249-
250186
let macOpenFileURIs: URI[] = [];
251187
let runningTimeout: any = null;
252188
app.on('open-file', (event: Event, path: string) => {
@@ -315,39 +251,10 @@ export class CodeApplication extends Disposable {
315251
}
316252
});
317253

318-
ipc.on('vscode:toggleDevTools', (event: Event) => {
319-
event.sender.toggleDevTools();
320-
});
321-
322-
ipc.on('vscode:openDevTools', (event: Event) => {
323-
event.sender.openDevTools();
324-
});
325-
326-
ipc.on('vscode:reloadWindow', (event: Event) => {
327-
event.sender.reload();
328-
});
329-
330-
// Keyboard layout changes
331-
KeyboardLayoutMonitor.INSTANCE.onDidChangeKeyboardLayout(() => {
332-
if (this.windowsMainService) {
333-
this.windowsMainService.sendToAll('vscode:keyboardLayoutChanged', false);
334-
}
335-
});
336-
}
337-
338-
private isValidWebviewSource(source: string): boolean {
339-
if (!source) {
340-
return false;
341-
}
342-
343-
if (source === 'data:text/html;charset=utf-8,%3C%21DOCTYPE%20html%3E%0D%0A%3Chtml%20lang%3D%22en%22%20style%3D%22width%3A%20100%25%3B%20height%3A%20100%25%22%3E%0D%0A%3Chead%3E%0D%0A%09%3Ctitle%3EVirtual%20Document%3C%2Ftitle%3E%0D%0A%3C%2Fhead%3E%0D%0A%3Cbody%20style%3D%22margin%3A%200%3B%20overflow%3A%20hidden%3B%20width%3A%20100%25%3B%20height%3A%20100%25%22%3E%0D%0A%3C%2Fbody%3E%0D%0A%3C%2Fhtml%3E') {
344-
return true;
345-
}
346-
347-
const srcUri: any = URI.parse(source).fsPath.toLowerCase();
348-
const rootUri = URI.file(this.environmentService.appRoot).fsPath.toLowerCase();
254+
ipc.on('vscode:toggleDevTools', (event: Event) => event.sender.toggleDevTools());
255+
ipc.on('vscode:openDevTools', (event: Event) => event.sender.openDevTools());
349256

350-
return srcUri.startsWith(rootUri + nativeSep);
257+
ipc.on('vscode:reloadWindow', (event: Event) => event.sender.reload());
351258
}
352259

353260
private onUnexpectedError(err: Error): void {
@@ -391,7 +298,7 @@ export class CodeApplication extends Disposable {
391298
// This will help Windows to associate the running program with
392299
// any shortcut that is pinned to the taskbar and prevent showing
393300
// two icons in the taskbar for the same app.
394-
if (platform.isWindows && product.win32AppUserModelId) {
301+
if (isWindows && product.win32AppUserModelId) {
395302
app.setAppUserModelId(product.win32AppUserModelId);
396303
}
397304

@@ -402,7 +309,7 @@ export class CodeApplication extends Disposable {
402309
// Explicitly opt out of the patch here before creating any windows.
403310
// See: https://github.com/Microsoft/vscode/issues/35361#issuecomment-399794085
404311
try {
405-
if (platform.isMacintosh && this.configurationService.getValue<boolean>('window.nativeTabs') === true && !systemPreferences.getUserDefault('NSUseImprovedLayoutPass', 'boolean')) {
312+
if (isMacintosh && this.configurationService.getValue<boolean>('window.nativeTabs') === true && !systemPreferences.getUserDefault('NSUseImprovedLayoutPass', 'boolean')) {
406313
systemPreferences.setUserDefault('NSUseImprovedLayoutPass', 'boolean', true as any);
407314
}
408315
} catch (error) {
@@ -631,8 +538,6 @@ export class CodeApplication extends Disposable {
631538
// Propagate to clients
632539
const windowsMainService = this.windowsMainService = accessor.get(IWindowsMainService); // TODO@Joao: unfold this
633540

634-
const args = this.environmentService.args;
635-
636541
// Create a URL handler which forwards to the last active window
637542
const activeWindowManager = new ActiveWindowManager(windowsService);
638543
const activeWindowRouter = new StaticRouter(ctx => activeWindowManager.getActiveClientId().then(id => ctx === id));
@@ -641,7 +546,7 @@ export class CodeApplication extends Disposable {
641546

642547
// On Mac, Code can be running without any open windows, so we must create a window to handle urls,
643548
// if there is none
644-
if (platform.isMacintosh) {
549+
if (isMacintosh) {
645550
const environmentService = accessor.get(IEnvironmentService);
646551

647552
urlService.registerHandler({
@@ -662,6 +567,7 @@ export class CodeApplication extends Disposable {
662567
urlService.registerHandler(multiplexURLHandler);
663568

664569
// Watch Electron URLs and forward them to the UrlService
570+
const args = this.environmentService.args;
665571
const urls = args['open-url'] ? args._urls : [];
666572
const urlListener = new ElectronURLListener(urls, urlService, this.windowsMainService);
667573
this._register(urlListener);
@@ -690,7 +596,7 @@ export class CodeApplication extends Disposable {
690596
const windowsMainService = accessor.get(IWindowsMainService);
691597

692598
let windowsMutex: Mutex | null = null;
693-
if (platform.isWindows) {
599+
if (isWindows) {
694600

695601
// Setup Windows mutex
696602
try {
@@ -726,6 +632,14 @@ export class CodeApplication extends Disposable {
726632
}
727633
}
728634

635+
// Remote Authorities
636+
this.handleRemoteAuthorities();
637+
638+
// Keyboard layout changes
639+
KeyboardLayoutMonitor.INSTANCE.onDidChangeKeyboardLayout(() => {
640+
this.windowsMainService.sendToAll('vscode:keyboardLayoutChanged', false);
641+
});
642+
729643
// Jump List
730644
this.historyMainService.updateWindowsJumpList();
731645
this.historyMainService.onRecentlyOpenedChange(() => this.historyMainService.updateWindowsJumpList());
@@ -734,4 +648,87 @@ export class CodeApplication extends Disposable {
734648
const sharedProcessSpawn = this._register(new RunOnceScheduler(() => getShellEnvironment().then(userEnv => this.sharedProcess.spawn(userEnv)), 3000));
735649
sharedProcessSpawn.schedule();
736650
}
651+
652+
private handleRemoteAuthorities(): void {
653+
const connectionPool: Map<string, ActiveConnection> = new Map<string, ActiveConnection>();
654+
655+
class ActiveConnection {
656+
private _authority: string;
657+
private _client: Promise<Client<RemoteAgentConnectionContext>>;
658+
private _disposeRunner: RunOnceScheduler;
659+
660+
constructor(authority: string, host: string, port: number) {
661+
this._authority = authority;
662+
this._client = connectRemoteAgentManagement(authority, host, port, `main`);
663+
this._disposeRunner = new RunOnceScheduler(() => this._dispose(), 5000);
664+
}
665+
666+
private _dispose(): void {
667+
this._disposeRunner.dispose();
668+
connectionPool.delete(this._authority);
669+
this._client.then((connection) => {
670+
connection.dispose();
671+
});
672+
}
673+
674+
public getClient(): Promise<Client<RemoteAgentConnectionContext>> {
675+
this._disposeRunner.schedule();
676+
return this._client;
677+
}
678+
}
679+
680+
const resolvedAuthorities = new Map<string, ResolvedAuthority>();
681+
ipc.on('vscode:remoteAuthorityResolved', (event: any, data: ResolvedAuthority) => {
682+
resolvedAuthorities.set(data.authority, data);
683+
});
684+
685+
const resolveAuthority = (authority: string): ResolvedAuthority | null => {
686+
if (authority.indexOf('+') >= 0) {
687+
if (resolvedAuthorities.has(authority)) {
688+
return resolvedAuthorities.get(authority);
689+
}
690+
return null;
691+
} else {
692+
const [host, strPort] = authority.split(':');
693+
const port = parseInt(strPort, 10);
694+
return { authority, host, port, syncExtensions: false };
695+
}
696+
};
697+
698+
protocol.registerBufferProtocol(REMOTE_HOST_SCHEME, async (request, callback) => {
699+
if (request.method !== 'GET') {
700+
return callback(null);
701+
}
702+
const uri = URI.parse(request.url);
703+
704+
let activeConnection: ActiveConnection = null;
705+
if (connectionPool.has(uri.authority)) {
706+
activeConnection = connectionPool.get(uri.authority);
707+
} else {
708+
let resolvedAuthority = resolveAuthority(uri.authority);
709+
if (!resolvedAuthority) {
710+
callback(null);
711+
return;
712+
}
713+
activeConnection = new ActiveConnection(uri.authority, resolvedAuthority.host, resolvedAuthority.port);
714+
connectionPool.set(uri.authority, activeConnection);
715+
}
716+
try {
717+
const rawClient = await activeConnection.getClient();
718+
if (connectionPool.has(uri.authority)) { // not disposed in the meantime
719+
const channel = rawClient.getChannel(REMOTE_FILE_SYSTEM_CHANNEL_NAME);
720+
721+
// TODO@alex don't use call directly, wrap it around a `RemoteExtensionsFileSystemProvider`
722+
const fileContents = await channel.call<Uint8Array>('readFile', [uri]);
723+
callback(Buffer.from(fileContents));
724+
} else {
725+
callback(null);
726+
}
727+
} catch (err) {
728+
errors.onUnexpectedError(err);
729+
callback(null);
730+
}
731+
});
732+
}
737733
}
734+

0 commit comments

Comments
 (0)