Skip to content

Commit d4b310e

Browse files
committed
fix UI calls from shared process
fix microsoft#54070
1 parent ed9171b commit d4b310e

9 files changed

Lines changed: 68 additions & 36 deletions

File tree

src/vs/base/parts/ipc/common/ipc.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,8 @@ export interface IChannelClient {
9494
* channels (each from a separate client) to pick from.
9595
*/
9696
export interface IClientRouter {
97-
routeCall(command: string, arg: any): string;
98-
routeEvent(event: string, arg: any): string;
97+
routeCall(command: string, arg: any): TPromise<string>;
98+
routeEvent(event: string, arg: any): TPromise<string>;
9999
}
100100

101101
/**
@@ -433,24 +433,20 @@ export class IPCServer implements IChannelServer, IRoutingChannelClient, IDispos
433433

434434
getChannel<T extends IChannel>(channelName: string, router: IClientRouter): T {
435435
const call = (command: string, arg: any) => {
436-
const id = router.routeCall(command, arg);
436+
const channelPromise = router.routeCall(command, arg)
437+
.then(id => this.getClient(id))
438+
.then(client => client.getChannel(channelName));
437439

438-
if (!id) {
439-
return TPromise.wrapError(new Error('Client id should be provided'));
440-
}
441-
442-
return getDelayedChannel(this.getClient(id).then(client => client.getChannel(channelName)))
440+
return getDelayedChannel(channelPromise)
443441
.call(command, arg);
444442
};
445443

446444
const listen = (event: string, arg: any) => {
447-
const id = router.routeEvent(event, arg);
448-
449-
if (!id) {
450-
return TPromise.wrapError(new Error('Client id should be provided'));
451-
}
445+
const channelPromise = router.routeEvent(event, arg)
446+
.then(id => this.getClient(id))
447+
.then(client => client.getChannel(channelName));
452448

453-
return getDelayedChannel(this.getClient(id).then(client => client.getChannel(channelName)))
449+
return getDelayedChannel(channelPromise)
454450
.listen(event, arg);
455451
};
456452

@@ -462,6 +458,10 @@ export class IPCServer implements IChannelServer, IRoutingChannelClient, IDispos
462458
}
463459

464460
private getClient(clientId: string): TPromise<IChannelClient> {
461+
if (!clientId) {
462+
return TPromise.wrapError(new Error('Client id should be provided'));
463+
}
464+
465465
const client = this.channelClients[clientId];
466466

467467
if (client) {

src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ function main(server: Server, initData: ISharedProcessInitData, configuration: I
6767
process.once('exit', () => dispose(disposables));
6868

6969
const environmentService = new EnvironmentService(initData.args, process.execPath);
70-
const logLevelClient = new LogLevelSetterChannelClient(server.getChannel('loglevel', { routeCall: () => 'main', routeEvent: () => 'main' }));
70+
const mainRoute = () => TPromise.as('main');
71+
const logLevelClient = new LogLevelSetterChannelClient(server.getChannel('loglevel', { routeCall: mainRoute, routeEvent: mainRoute }));
7172
const logService = new FollowerLogService(logLevelClient, createSpdLogService('sharedprocess', initData.logLevel, environmentService.logsPath));
7273
disposables.push(logService);
7374

@@ -78,21 +79,13 @@ function main(server: Server, initData: ISharedProcessInitData, configuration: I
7879
services.set(IConfigurationService, new SyncDescriptor(ConfigurationService));
7980
services.set(IRequestService, new SyncDescriptor(RequestService));
8081

81-
const windowsChannel = server.getChannel('windows', { routeCall: () => 'main', routeEvent: () => 'main' });
82+
const windowsChannel = server.getChannel('windows', { routeCall: mainRoute, routeEvent: mainRoute });
8283
const windowsService = new WindowsChannelClient(windowsChannel);
8384
services.set(IWindowsService, windowsService);
8485

8586
const activeWindowManager = new ActiveWindowManager(windowsService);
86-
const dialogChannel = server.getChannel('dialog', {
87-
routeCall: () => {
88-
logService.info('Routing dialog call request to the client', activeWindowManager.activeClientId);
89-
return activeWindowManager.activeClientId;
90-
},
91-
routeEvent: () => {
92-
logService.info('Routing dialog listen request to the client', activeWindowManager.activeClientId);
93-
return activeWindowManager.activeClientId;
94-
}
95-
});
87+
const route = () => activeWindowManager.getActiveClientId();
88+
const dialogChannel = server.getChannel('dialog', { routeCall: route, routeEvent: route });
9689
services.set(IDialogService, new DialogChannelClient(dialogChannel));
9790

9891
const instantiationService = new InstantiationService(services);

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ export class CodeApplication {
426426

427427
// Create a URL handler which forwards to the last active window
428428
const activeWindowManager = new ActiveWindowManager(windowsService);
429-
const route = () => activeWindowManager.activeClientId;
429+
const route = () => activeWindowManager.getActiveClientId();
430430
const urlHandlerChannel = this.electronIpcServer.getChannel('urlHandler', { routeCall: route, routeEvent: route });
431431
const multiplexURLHandler = new URLHandlerChannelClient(urlHandlerChannel);
432432

src/vs/platform/driver/electron-main/driver.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,12 @@ class WindowRouter implements IClientRouter {
2727

2828
constructor(private windowId: number) { }
2929

30-
routeCall(): string {
31-
return `window:${this.windowId}`;
30+
routeCall(): TPromise<string> {
31+
return TPromise.as(`window:${this.windowId}`);
3232
}
3333

34-
routeEvent(): string {
35-
return `window:${this.windowId}`;
34+
routeEvent(): TPromise<string> {
35+
return TPromise.as(`window:${this.windowId}`);
3636
}
3737
}
3838

src/vs/platform/windows/common/windows.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ export interface IWindowsService {
162162
getWindowCount(): TPromise<number>;
163163
log(severity: string, ...messages: string[]): TPromise<void>;
164164
showItemInFolder(path: string): TPromise<void>;
165+
getActiveWindowId(): TPromise<number | undefined>;
165166

166167
// This needs to be handled from browser process to prevent
167168
// foreground ordering issues on Windows
@@ -357,19 +358,31 @@ export interface IRunActionInWindowRequest {
357358
export class ActiveWindowManager implements IDisposable {
358359

359360
private disposables: IDisposable[] = [];
360-
private _activeWindowId: number;
361+
private firstActiveWindowIdPromise: TPromise<any> | null;
362+
private _activeWindowId: number | undefined;
361363

362364
constructor(@IWindowsService windowsService: IWindowsService) {
363365
const onActiveWindowChange = latch(anyEvent(windowsService.onWindowOpen, windowsService.onWindowFocus));
364366
onActiveWindowChange(this.setActiveWindow, this, this.disposables);
367+
368+
this.firstActiveWindowIdPromise = windowsService.getActiveWindowId()
369+
.then(id => (typeof this._activeWindowId === 'undefined') && this.setActiveWindow(id));
365370
}
366371

367372
private setActiveWindow(windowId: number) {
373+
if (this.firstActiveWindowIdPromise) {
374+
this.firstActiveWindowIdPromise = null;
375+
}
376+
368377
this._activeWindowId = windowId;
369378
}
370379

371-
get activeClientId(): string {
372-
return `window:${this._activeWindowId}`;
380+
getActiveClientId(): TPromise<string> {
381+
if (this.firstActiveWindowIdPromise) {
382+
return this.firstActiveWindowIdPromise;
383+
}
384+
385+
return TPromise.as(`window:${this._activeWindowId}`);
373386
}
374387

375388
dispose() {

src/vs/platform/windows/common/windowsIpc.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ export interface IWindowsChannel extends IChannel {
6868
call(command: 'toggleSharedProcess'): TPromise<void>;
6969
call(command: 'log', arg: [string, string[]]): TPromise<void>;
7070
call(command: 'showItemInFolder', arg: string): TPromise<void>;
71+
call(command: 'getActiveWindowId'): TPromise<number>;
7172
call(command: 'openExternal', arg: string): TPromise<boolean>;
7273
call(command: 'startCrashReporter', arg: CrashReporterStartOptions): TPromise<void>;
7374
call(command: 'openAccessibilityOptions'): TPromise<void>;
@@ -166,6 +167,7 @@ export class WindowsChannel implements IWindowsChannel {
166167
case 'quit': return this.service.quit();
167168
case 'log': return this.service.log(arg[0], arg[1]);
168169
case 'showItemInFolder': return this.service.showItemInFolder(arg);
170+
case 'getActiveWindowId': return this.service.getActiveWindowId();
169171
case 'openExternal': return this.service.openExternal(arg);
170172
case 'startCrashReporter': return this.service.startCrashReporter(arg);
171173
case 'openAccessibilityOptions': return this.service.openAccessibilityOptions();
@@ -364,6 +366,10 @@ export class WindowsChannelClient implements IWindowsService {
364366
return this.channel.call('showItemInFolder', path);
365367
}
366368

369+
getActiveWindowId(): TPromise<number | undefined> {
370+
return this.channel.call('getActiveWindowId');
371+
}
372+
367373
openExternal(url: string): TPromise<boolean> {
368374
return this.channel.call('openExternal', url);
369375
}

src/vs/platform/windows/electron-main/windowsService.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import product from 'vs/platform/node/product';
1414
import { IWindowsService, OpenContext, INativeOpenDialogOptions, IEnterWorkspaceResult, IMessageBoxResult, IDevToolsOptions } from 'vs/platform/windows/common/windows';
1515
import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment';
1616
import { shell, crashReporter, app, Menu, clipboard, BrowserWindow } from 'electron';
17-
import { Event, fromNodeEventEmitter, mapEvent, filterEvent, anyEvent } from 'vs/base/common/event';
17+
import { Event, fromNodeEventEmitter, mapEvent, filterEvent, anyEvent, latch } from 'vs/base/common/event';
1818
import { IURLService, IURLHandler } from 'vs/platform/url/common/url';
1919
import { ILifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain';
2020
import { IWindowsMainService, ISharedProcess } from 'vs/platform/windows/electron-main/windows';
@@ -32,6 +32,8 @@ export class WindowsService implements IWindowsService, IURLHandler, IDisposable
3232

3333
private disposables: IDisposable[] = [];
3434

35+
private _activeWindowId: number | undefined;
36+
3537
readonly onWindowOpen: Event<number> = filterEvent(fromNodeEventEmitter(app, 'browser-window-created', (_, w: Electron.BrowserWindow) => w.id), id => !!this.windowsMainService.getWindowById(id));
3638
readonly onWindowFocus: Event<number> = anyEvent(
3739
mapEvent(filterEvent(mapEvent(this.windowsMainService.onWindowsCountChanged, () => this.windowsMainService.getLastActiveWindow()), w => !!w), w => w.id),
@@ -54,6 +56,10 @@ export class WindowsService implements IWindowsService, IURLHandler, IDisposable
5456
@ILogService private logService: ILogService
5557
) {
5658
urlService.registerHandler(this);
59+
60+
// remember last active window id
61+
latch(anyEvent(this.onWindowOpen, this.onWindowFocus))
62+
(id => this._activeWindowId = id, null, this.disposables);
5763
}
5864

5965
pickFileFolderAndOpen(options: INativeOpenDialogOptions): TPromise<void> {
@@ -435,6 +441,10 @@ export class WindowsService implements IWindowsService, IURLHandler, IDisposable
435441
return TPromise.as(null);
436442
}
437443

444+
getActiveWindowId(): TPromise<number | undefined> {
445+
return TPromise.as(this._activeWindowId);
446+
}
447+
438448
openExternal(url: string): TPromise<boolean> {
439449
this.logService.trace('windowsService#openExternal');
440450
return TPromise.as(shell.openExternal(url));

src/vs/workbench/services/dialogs/electron-browser/dialogService.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { isLinux, isWindows } from 'vs/base/common/platform';
1313
import { IWindowService } from 'vs/platform/windows/common/windows';
1414
import { mnemonicButtonLabel } from 'vs/base/common/labels';
1515
import { IDialogService, IConfirmation, IConfirmationResult, IDialogOptions } from 'vs/platform/dialogs/common/dialogs';
16+
import { ILogService } from 'vs/platform/log/common/log';
1617

1718
interface IMassagedMessageBoxOptions {
1819

@@ -34,10 +35,13 @@ export class DialogService implements IDialogService {
3435
_serviceBrand: any;
3536

3637
constructor(
37-
@IWindowService private windowService: IWindowService
38+
@IWindowService private windowService: IWindowService,
39+
@ILogService private logService: ILogService
3840
) { }
3941

4042
confirm(confirmation: IConfirmation): TPromise<IConfirmationResult> {
43+
this.logService.trace('DialogService#confirm', confirmation.message);
44+
4145
const { options, buttonIndexMap } = this.massageMessageBoxOptions(this.getConfirmOptions(confirmation));
4246

4347
return this.windowService.showMessageBox(options).then(result => {
@@ -86,6 +90,8 @@ export class DialogService implements IDialogService {
8690
}
8791

8892
show(severity: Severity, message: string, buttons: string[], dialogOptions?: IDialogOptions): TPromise<number> {
93+
this.logService.trace('DialogService#show', message);
94+
8995
const { options, buttonIndexMap } = this.massageMessageBoxOptions({
9096
message,
9197
buttons,

src/vs/workbench/test/workbenchTestServices.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1295,6 +1295,10 @@ export class TestWindowsService implements IWindowsService {
12951295
return TPromise.as(void 0);
12961296
}
12971297

1298+
getActiveWindowId(): TPromise<number | undefined> {
1299+
return TPromise.as(undefined);
1300+
}
1301+
12981302
// This needs to be handled from browser process to prevent
12991303
// foreground ordering issues on Windows
13001304
openExternal(url: string): TPromise<boolean> {

0 commit comments

Comments
 (0)