Skip to content

Commit 0d85351

Browse files
author
Benjamin Pasero
committed
simple IPC: allow to encode static context (windowId)
1 parent 809bb97 commit 0d85351

3 files changed

Lines changed: 81 additions & 39 deletions

File tree

src/vs/platform/electron/electron-browser/electronService.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,16 @@
66
import { IElectronService } from 'vs/platform/electron/node/electron';
77
import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService';
88
import { createSimpleChannelProxy } from 'vs/platform/ipc/node/simpleIpcProxy';
9+
import { IWindowService } from 'vs/platform/windows/common/windows';
910

1011
export class ElectronService {
1112

1213
_serviceBrand: undefined;
1314

14-
constructor(@IMainProcessService mainProcessService: IMainProcessService) {
15-
return createSimpleChannelProxy<IElectronService>(mainProcessService.getChannel('electron'));
15+
constructor(
16+
@IMainProcessService mainProcessService: IMainProcessService,
17+
@IWindowService windowService: IWindowService
18+
) {
19+
return createSimpleChannelProxy<IElectronService>(mainProcessService.getChannel('electron'), windowService.windowId);
1620
}
1721
}

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

Lines changed: 38 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,13 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6-
import { IElectronService } from 'vs/platform/electron/node/electron';
7-
import { IWindowsMainService, ICodeWindow } from 'vs/platform/windows/electron-main/windows';
6+
import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows';
87
import { MessageBoxOptions, MessageBoxReturnValue, shell, OpenDevToolsOptions, SaveDialogOptions, SaveDialogReturnValue, OpenDialogOptions, OpenDialogReturnValue } from 'electron';
98
import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService';
109
import { OpenContext, INativeOpenDialogOptions } from 'vs/platform/windows/common/windows';
1110
import { isMacintosh } from 'vs/base/common/platform';
1211

13-
export class ElectronMainService implements IElectronService {
12+
export class ElectronMainService {
1413

1514
_serviceBrand: undefined;
1615

@@ -22,20 +21,16 @@ export class ElectronMainService implements IElectronService {
2221

2322
//#region Window
2423

25-
private get window(): ICodeWindow | undefined {
26-
return this.windowsMainService.getFocusedWindow() || this.windowsMainService.getLastActiveWindow();
27-
}
28-
29-
async windowCount(): Promise<number> {
24+
async windowCount(windowId: number): Promise<number> {
3025
return this.windowsMainService.getWindowCount();
3126
}
3227

33-
async openEmptyWindow(options?: { reuse?: boolean }): Promise<void> {
28+
async openEmptyWindow(windowId: number, options?: { reuse?: boolean }): Promise<void> {
3429
this.windowsMainService.openEmptyWindow(OpenContext.API, options);
3530
}
3631

37-
async toggleFullScreen(): Promise<void> {
38-
const window = this.window;
32+
async toggleFullScreen(windowId: number): Promise<void> {
33+
const window = this.windowsMainService.getWindowById(windowId);
3934
if (window) {
4035
window.toggleFullScreen();
4136
}
@@ -45,51 +40,59 @@ export class ElectronMainService implements IElectronService {
4540

4641
//#region Dialog
4742

48-
async showMessageBox(options: MessageBoxOptions): Promise<MessageBoxReturnValue> {
49-
return this.windowsMainService.showMessageBox(options, this.window);
43+
async showMessageBox(windowId: number, options: MessageBoxOptions): Promise<MessageBoxReturnValue> {
44+
return this.windowsMainService.showMessageBox(options, this.windowsMainService.getWindowById(windowId));
5045
}
5146

52-
async showSaveDialog(options: SaveDialogOptions): Promise<SaveDialogReturnValue> {
53-
return this.windowsMainService.showSaveDialog(options, this.window);
47+
async showSaveDialog(windowId: number, options: SaveDialogOptions): Promise<SaveDialogReturnValue> {
48+
return this.windowsMainService.showSaveDialog(options, this.windowsMainService.getWindowById(windowId));
5449
}
5550

56-
async showOpenDialog(options: OpenDialogOptions): Promise<OpenDialogReturnValue> {
57-
return this.windowsMainService.showOpenDialog(options, this.window);
51+
async showOpenDialog(windowId: number, options: OpenDialogOptions): Promise<OpenDialogReturnValue> {
52+
return this.windowsMainService.showOpenDialog(options, this.windowsMainService.getWindowById(windowId));
5853
}
5954

60-
async pickFileFolderAndOpen(options: INativeOpenDialogOptions): Promise<void> {
55+
async pickFileFolderAndOpen(windowId: number, options: INativeOpenDialogOptions): Promise<void> {
56+
options.windowId = windowId;
57+
6158
return this.windowsMainService.pickFileFolderAndOpen(options);
6259
}
6360

64-
async pickFileAndOpen(options: INativeOpenDialogOptions): Promise<void> {
61+
async pickFileAndOpen(windowId: number, options: INativeOpenDialogOptions): Promise<void> {
62+
options.windowId = windowId;
63+
6564
return this.windowsMainService.pickFileAndOpen(options);
6665
}
6766

68-
async pickFolderAndOpen(options: INativeOpenDialogOptions): Promise<void> {
67+
async pickFolderAndOpen(windowId: number, options: INativeOpenDialogOptions): Promise<void> {
68+
options.windowId = windowId;
69+
6970
return this.windowsMainService.pickFolderAndOpen(options);
7071
}
7172

72-
async pickWorkspaceAndOpen(options: INativeOpenDialogOptions): Promise<void> {
73+
async pickWorkspaceAndOpen(windowId: number, options: INativeOpenDialogOptions): Promise<void> {
74+
options.windowId = windowId;
75+
7376
return this.windowsMainService.pickWorkspaceAndOpen(options);
7477
}
7578

7679
//#endregion
7780

7881
//#region OS
7982

80-
async showItemInFolder(path: string): Promise<void> {
83+
async showItemInFolder(windowId: number, path: string): Promise<void> {
8184
shell.showItemInFolder(path);
8285
}
8386

84-
async setRepresentedFilename(path: string): Promise<void> {
85-
const window = this.window;
87+
async setRepresentedFilename(windowId: number, path: string): Promise<void> {
88+
const window = this.windowsMainService.getWindowById(windowId);
8689
if (window) {
8790
window.setRepresentedFilename(path);
8891
}
8992
}
9093

91-
async setDocumentEdited(edited: boolean): Promise<void> {
92-
const window = this.window;
94+
async setDocumentEdited(windowId: number, edited: boolean): Promise<void> {
95+
const window = this.windowsMainService.getWindowById(windowId);
9396
if (window) {
9497
window.win.setDocumentEdited(edited);
9598
}
@@ -99,12 +102,12 @@ export class ElectronMainService implements IElectronService {
99102

100103
//#region Lifecycle
101104

102-
async relaunch(options?: { addArgs?: string[], removeArgs?: string[] }): Promise<void> {
105+
async relaunch(windowId: number, options?: { addArgs?: string[], removeArgs?: string[] }): Promise<void> {
103106
return this.lifecycleMainService.relaunch(options);
104107
}
105108

106-
async reload(): Promise<void> {
107-
const window = this.window;
109+
async reload(windowId: number): Promise<void> {
110+
const window = this.windowsMainService.getWindowById(windowId);
108111
if (window) {
109112
return this.windowsMainService.reload(window);
110113
}
@@ -114,15 +117,15 @@ export class ElectronMainService implements IElectronService {
114117

115118
//#region Development
116119

117-
async openDevTools(options?: OpenDevToolsOptions): Promise<void> {
118-
const window = this.window;
120+
async openDevTools(windowId: number, options?: OpenDevToolsOptions): Promise<void> {
121+
const window = this.windowsMainService.getWindowById(windowId);
119122
if (window) {
120123
window.win.webContents.openDevTools(options);
121124
}
122125
}
123126

124-
async toggleDevTools(): Promise<void> {
125-
const window = this.window;
127+
async toggleDevTools(windowId: number): Promise<void> {
128+
const window = this.windowsMainService.getWindowById(windowId);
126129
if (window) {
127130
const contents = window.win.webContents;
128131
if (isMacintosh && window.hasHiddenTitleBarStyle() && !window.isFullScreen() && !contents.isDevToolsOpened()) {
@@ -137,9 +140,9 @@ export class ElectronMainService implements IElectronService {
137140

138141
//#region Connectivity
139142

140-
async resolveProxy(url: string): Promise<string | undefined> {
143+
async resolveProxy(windowId: number, url: string): Promise<string | undefined> {
141144
return new Promise(resolve => {
142-
const window = this.window;
145+
const window = this.windowsMainService.getWindowById(windowId);
143146
if (window && window.win && window.win.webContents && window.win.webContents.session) {
144147
window.win.webContents.session.resolveProxy(url, proxy => resolve(proxy));
145148
} else {

src/vs/platform/ipc/node/simpleIpcProxy.ts

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,27 @@ import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
1111
// for a very basic process <=> process communication over methods.
1212
//
1313

14+
interface ISimpleChannelProxyContext {
15+
__$simpleIPCContextMarker: boolean;
16+
proxyContext: unknown;
17+
}
18+
19+
function serializeContext(proxyContext?: unknown): ISimpleChannelProxyContext | undefined {
20+
if (proxyContext) {
21+
return { __$simpleIPCContextMarker: true, proxyContext };
22+
}
23+
24+
return undefined;
25+
}
26+
27+
function deserializeContext(candidate?: ISimpleChannelProxyContext | undefined): unknown | undefined {
28+
if (candidate && candidate.__$simpleIPCContextMarker === true) {
29+
return candidate.proxyContext;
30+
}
31+
32+
return undefined;
33+
}
34+
1435
export class SimpleServiceProxyChannel implements IServerChannel {
1536

1637
private service: { [key: string]: unknown };
@@ -26,19 +47,33 @@ export class SimpleServiceProxyChannel implements IServerChannel {
2647
call(_: unknown, command: string, args: any[]): Promise<any> {
2748
const target = this.service[command];
2849
if (typeof target === 'function') {
50+
const context = deserializeContext(args[0]);
51+
if (context) {
52+
args[0] = context;
53+
}
54+
2955
return target.apply(this.service, args);
3056
}
3157

3258
throw new Error(`Method not found: ${command}`);
3359
}
3460
}
3561

36-
export function createSimpleChannelProxy<T>(channel: IChannel): T {
62+
export function createSimpleChannelProxy<T>(channel: IChannel, context?: unknown): T {
63+
const serializedContext = serializeContext(context);
64+
3765
return new Proxy({}, {
3866
get(_target, propKey, _receiver) {
3967
if (typeof propKey === 'string') {
4068
return function (...args: any[]) {
41-
return channel.call(propKey, args);
69+
let methodArgs: any[];
70+
if (serializedContext) {
71+
methodArgs = [context, ...args];
72+
} else {
73+
methodArgs = args;
74+
}
75+
76+
return channel.call(propKey, methodArgs);
4277
};
4378
}
4479

0 commit comments

Comments
 (0)