From 0d85351dc4a14938cffa95db93805accc08bb789 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 20 Sep 2019 10:31:28 +0200 Subject: [PATCH] simple IPC: allow to encode static context (windowId) --- .../electron-browser/electronService.ts | 8 +- .../electron-main/electronMainService.ts | 73 ++++++++++--------- src/vs/platform/ipc/node/simpleIpcProxy.ts | 39 +++++++++- 3 files changed, 81 insertions(+), 39 deletions(-) diff --git a/src/vs/platform/electron/electron-browser/electronService.ts b/src/vs/platform/electron/electron-browser/electronService.ts index 0a88c90efc511..b1c6db59d4f45 100644 --- a/src/vs/platform/electron/electron-browser/electronService.ts +++ b/src/vs/platform/electron/electron-browser/electronService.ts @@ -6,12 +6,16 @@ import { IElectronService } from 'vs/platform/electron/node/electron'; import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; import { createSimpleChannelProxy } from 'vs/platform/ipc/node/simpleIpcProxy'; +import { IWindowService } from 'vs/platform/windows/common/windows'; export class ElectronService { _serviceBrand: undefined; - constructor(@IMainProcessService mainProcessService: IMainProcessService) { - return createSimpleChannelProxy(mainProcessService.getChannel('electron')); + constructor( + @IMainProcessService mainProcessService: IMainProcessService, + @IWindowService windowService: IWindowService + ) { + return createSimpleChannelProxy(mainProcessService.getChannel('electron'), windowService.windowId); } } diff --git a/src/vs/platform/electron/electron-main/electronMainService.ts b/src/vs/platform/electron/electron-main/electronMainService.ts index be75c818a502b..b749273dacfb8 100644 --- a/src/vs/platform/electron/electron-main/electronMainService.ts +++ b/src/vs/platform/electron/electron-main/electronMainService.ts @@ -3,14 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IElectronService } from 'vs/platform/electron/node/electron'; -import { IWindowsMainService, ICodeWindow } from 'vs/platform/windows/electron-main/windows'; +import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows'; import { MessageBoxOptions, MessageBoxReturnValue, shell, OpenDevToolsOptions, SaveDialogOptions, SaveDialogReturnValue, OpenDialogOptions, OpenDialogReturnValue } from 'electron'; import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import { OpenContext, INativeOpenDialogOptions } from 'vs/platform/windows/common/windows'; import { isMacintosh } from 'vs/base/common/platform'; -export class ElectronMainService implements IElectronService { +export class ElectronMainService { _serviceBrand: undefined; @@ -22,20 +21,16 @@ export class ElectronMainService implements IElectronService { //#region Window - private get window(): ICodeWindow | undefined { - return this.windowsMainService.getFocusedWindow() || this.windowsMainService.getLastActiveWindow(); - } - - async windowCount(): Promise { + async windowCount(windowId: number): Promise { return this.windowsMainService.getWindowCount(); } - async openEmptyWindow(options?: { reuse?: boolean }): Promise { + async openEmptyWindow(windowId: number, options?: { reuse?: boolean }): Promise { this.windowsMainService.openEmptyWindow(OpenContext.API, options); } - async toggleFullScreen(): Promise { - const window = this.window; + async toggleFullScreen(windowId: number): Promise { + const window = this.windowsMainService.getWindowById(windowId); if (window) { window.toggleFullScreen(); } @@ -45,31 +40,39 @@ export class ElectronMainService implements IElectronService { //#region Dialog - async showMessageBox(options: MessageBoxOptions): Promise { - return this.windowsMainService.showMessageBox(options, this.window); + async showMessageBox(windowId: number, options: MessageBoxOptions): Promise { + return this.windowsMainService.showMessageBox(options, this.windowsMainService.getWindowById(windowId)); } - async showSaveDialog(options: SaveDialogOptions): Promise { - return this.windowsMainService.showSaveDialog(options, this.window); + async showSaveDialog(windowId: number, options: SaveDialogOptions): Promise { + return this.windowsMainService.showSaveDialog(options, this.windowsMainService.getWindowById(windowId)); } - async showOpenDialog(options: OpenDialogOptions): Promise { - return this.windowsMainService.showOpenDialog(options, this.window); + async showOpenDialog(windowId: number, options: OpenDialogOptions): Promise { + return this.windowsMainService.showOpenDialog(options, this.windowsMainService.getWindowById(windowId)); } - async pickFileFolderAndOpen(options: INativeOpenDialogOptions): Promise { + async pickFileFolderAndOpen(windowId: number, options: INativeOpenDialogOptions): Promise { + options.windowId = windowId; + return this.windowsMainService.pickFileFolderAndOpen(options); } - async pickFileAndOpen(options: INativeOpenDialogOptions): Promise { + async pickFileAndOpen(windowId: number, options: INativeOpenDialogOptions): Promise { + options.windowId = windowId; + return this.windowsMainService.pickFileAndOpen(options); } - async pickFolderAndOpen(options: INativeOpenDialogOptions): Promise { + async pickFolderAndOpen(windowId: number, options: INativeOpenDialogOptions): Promise { + options.windowId = windowId; + return this.windowsMainService.pickFolderAndOpen(options); } - async pickWorkspaceAndOpen(options: INativeOpenDialogOptions): Promise { + async pickWorkspaceAndOpen(windowId: number, options: INativeOpenDialogOptions): Promise { + options.windowId = windowId; + return this.windowsMainService.pickWorkspaceAndOpen(options); } @@ -77,19 +80,19 @@ export class ElectronMainService implements IElectronService { //#region OS - async showItemInFolder(path: string): Promise { + async showItemInFolder(windowId: number, path: string): Promise { shell.showItemInFolder(path); } - async setRepresentedFilename(path: string): Promise { - const window = this.window; + async setRepresentedFilename(windowId: number, path: string): Promise { + const window = this.windowsMainService.getWindowById(windowId); if (window) { window.setRepresentedFilename(path); } } - async setDocumentEdited(edited: boolean): Promise { - const window = this.window; + async setDocumentEdited(windowId: number, edited: boolean): Promise { + const window = this.windowsMainService.getWindowById(windowId); if (window) { window.win.setDocumentEdited(edited); } @@ -99,12 +102,12 @@ export class ElectronMainService implements IElectronService { //#region Lifecycle - async relaunch(options?: { addArgs?: string[], removeArgs?: string[] }): Promise { + async relaunch(windowId: number, options?: { addArgs?: string[], removeArgs?: string[] }): Promise { return this.lifecycleMainService.relaunch(options); } - async reload(): Promise { - const window = this.window; + async reload(windowId: number): Promise { + const window = this.windowsMainService.getWindowById(windowId); if (window) { return this.windowsMainService.reload(window); } @@ -114,15 +117,15 @@ export class ElectronMainService implements IElectronService { //#region Development - async openDevTools(options?: OpenDevToolsOptions): Promise { - const window = this.window; + async openDevTools(windowId: number, options?: OpenDevToolsOptions): Promise { + const window = this.windowsMainService.getWindowById(windowId); if (window) { window.win.webContents.openDevTools(options); } } - async toggleDevTools(): Promise { - const window = this.window; + async toggleDevTools(windowId: number): Promise { + const window = this.windowsMainService.getWindowById(windowId); if (window) { const contents = window.win.webContents; if (isMacintosh && window.hasHiddenTitleBarStyle() && !window.isFullScreen() && !contents.isDevToolsOpened()) { @@ -137,9 +140,9 @@ export class ElectronMainService implements IElectronService { //#region Connectivity - async resolveProxy(url: string): Promise { + async resolveProxy(windowId: number, url: string): Promise { return new Promise(resolve => { - const window = this.window; + const window = this.windowsMainService.getWindowById(windowId); if (window && window.win && window.win.webContents && window.win.webContents.session) { window.win.webContents.session.resolveProxy(url, proxy => resolve(proxy)); } else { diff --git a/src/vs/platform/ipc/node/simpleIpcProxy.ts b/src/vs/platform/ipc/node/simpleIpcProxy.ts index 43e4cdbc31fb0..ebc3b351366aa 100644 --- a/src/vs/platform/ipc/node/simpleIpcProxy.ts +++ b/src/vs/platform/ipc/node/simpleIpcProxy.ts @@ -11,6 +11,27 @@ import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; // for a very basic process <=> process communication over methods. // +interface ISimpleChannelProxyContext { + __$simpleIPCContextMarker: boolean; + proxyContext: unknown; +} + +function serializeContext(proxyContext?: unknown): ISimpleChannelProxyContext | undefined { + if (proxyContext) { + return { __$simpleIPCContextMarker: true, proxyContext }; + } + + return undefined; +} + +function deserializeContext(candidate?: ISimpleChannelProxyContext | undefined): unknown | undefined { + if (candidate && candidate.__$simpleIPCContextMarker === true) { + return candidate.proxyContext; + } + + return undefined; +} + export class SimpleServiceProxyChannel implements IServerChannel { private service: { [key: string]: unknown }; @@ -26,6 +47,11 @@ export class SimpleServiceProxyChannel implements IServerChannel { call(_: unknown, command: string, args: any[]): Promise { const target = this.service[command]; if (typeof target === 'function') { + const context = deserializeContext(args[0]); + if (context) { + args[0] = context; + } + return target.apply(this.service, args); } @@ -33,12 +59,21 @@ export class SimpleServiceProxyChannel implements IServerChannel { } } -export function createSimpleChannelProxy(channel: IChannel): T { +export function createSimpleChannelProxy(channel: IChannel, context?: unknown): T { + const serializedContext = serializeContext(context); + return new Proxy({}, { get(_target, propKey, _receiver) { if (typeof propKey === 'string') { return function (...args: any[]) { - return channel.call(propKey, args); + let methodArgs: any[]; + if (serializedContext) { + methodArgs = [context, ...args]; + } else { + methodArgs = args; + } + + return channel.call(propKey, methodArgs); }; }