Skip to content

Commit

Permalink
simple IPC: allow to encode static context (windowId)
Browse files Browse the repository at this point in the history
  • Loading branch information
bpasero committed Sep 20, 2019
1 parent 809bb97 commit 0d85351
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 39 deletions.
8 changes: 6 additions & 2 deletions src/vs/platform/electron/electron-browser/electronService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<IElectronService>(mainProcessService.getChannel('electron'));
constructor(
@IMainProcessService mainProcessService: IMainProcessService,
@IWindowService windowService: IWindowService
) {
return createSimpleChannelProxy<IElectronService>(mainProcessService.getChannel('electron'), windowService.windowId);
}
}
73 changes: 38 additions & 35 deletions src/vs/platform/electron/electron-main/electronMainService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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<number> {
async windowCount(windowId: number): Promise<number> {
return this.windowsMainService.getWindowCount();
}

async openEmptyWindow(options?: { reuse?: boolean }): Promise<void> {
async openEmptyWindow(windowId: number, options?: { reuse?: boolean }): Promise<void> {
this.windowsMainService.openEmptyWindow(OpenContext.API, options);
}

async toggleFullScreen(): Promise<void> {
const window = this.window;
async toggleFullScreen(windowId: number): Promise<void> {
const window = this.windowsMainService.getWindowById(windowId);
if (window) {
window.toggleFullScreen();
}
Expand All @@ -45,51 +40,59 @@ export class ElectronMainService implements IElectronService {

//#region Dialog

async showMessageBox(options: MessageBoxOptions): Promise<MessageBoxReturnValue> {
return this.windowsMainService.showMessageBox(options, this.window);
async showMessageBox(windowId: number, options: MessageBoxOptions): Promise<MessageBoxReturnValue> {
return this.windowsMainService.showMessageBox(options, this.windowsMainService.getWindowById(windowId));
}

async showSaveDialog(options: SaveDialogOptions): Promise<SaveDialogReturnValue> {
return this.windowsMainService.showSaveDialog(options, this.window);
async showSaveDialog(windowId: number, options: SaveDialogOptions): Promise<SaveDialogReturnValue> {
return this.windowsMainService.showSaveDialog(options, this.windowsMainService.getWindowById(windowId));
}

async showOpenDialog(options: OpenDialogOptions): Promise<OpenDialogReturnValue> {
return this.windowsMainService.showOpenDialog(options, this.window);
async showOpenDialog(windowId: number, options: OpenDialogOptions): Promise<OpenDialogReturnValue> {
return this.windowsMainService.showOpenDialog(options, this.windowsMainService.getWindowById(windowId));
}

async pickFileFolderAndOpen(options: INativeOpenDialogOptions): Promise<void> {
async pickFileFolderAndOpen(windowId: number, options: INativeOpenDialogOptions): Promise<void> {
options.windowId = windowId;

return this.windowsMainService.pickFileFolderAndOpen(options);
}

async pickFileAndOpen(options: INativeOpenDialogOptions): Promise<void> {
async pickFileAndOpen(windowId: number, options: INativeOpenDialogOptions): Promise<void> {
options.windowId = windowId;

return this.windowsMainService.pickFileAndOpen(options);
}

async pickFolderAndOpen(options: INativeOpenDialogOptions): Promise<void> {
async pickFolderAndOpen(windowId: number, options: INativeOpenDialogOptions): Promise<void> {
options.windowId = windowId;

return this.windowsMainService.pickFolderAndOpen(options);
}

async pickWorkspaceAndOpen(options: INativeOpenDialogOptions): Promise<void> {
async pickWorkspaceAndOpen(windowId: number, options: INativeOpenDialogOptions): Promise<void> {
options.windowId = windowId;

return this.windowsMainService.pickWorkspaceAndOpen(options);
}

//#endregion

//#region OS

async showItemInFolder(path: string): Promise<void> {
async showItemInFolder(windowId: number, path: string): Promise<void> {
shell.showItemInFolder(path);
}

async setRepresentedFilename(path: string): Promise<void> {
const window = this.window;
async setRepresentedFilename(windowId: number, path: string): Promise<void> {
const window = this.windowsMainService.getWindowById(windowId);
if (window) {
window.setRepresentedFilename(path);
}
}

async setDocumentEdited(edited: boolean): Promise<void> {
const window = this.window;
async setDocumentEdited(windowId: number, edited: boolean): Promise<void> {
const window = this.windowsMainService.getWindowById(windowId);
if (window) {
window.win.setDocumentEdited(edited);
}
Expand All @@ -99,12 +102,12 @@ export class ElectronMainService implements IElectronService {

//#region Lifecycle

async relaunch(options?: { addArgs?: string[], removeArgs?: string[] }): Promise<void> {
async relaunch(windowId: number, options?: { addArgs?: string[], removeArgs?: string[] }): Promise<void> {
return this.lifecycleMainService.relaunch(options);
}

async reload(): Promise<void> {
const window = this.window;
async reload(windowId: number): Promise<void> {
const window = this.windowsMainService.getWindowById(windowId);
if (window) {
return this.windowsMainService.reload(window);
}
Expand All @@ -114,15 +117,15 @@ export class ElectronMainService implements IElectronService {

//#region Development

async openDevTools(options?: OpenDevToolsOptions): Promise<void> {
const window = this.window;
async openDevTools(windowId: number, options?: OpenDevToolsOptions): Promise<void> {
const window = this.windowsMainService.getWindowById(windowId);
if (window) {
window.win.webContents.openDevTools(options);
}
}

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

//#region Connectivity

async resolveProxy(url: string): Promise<string | undefined> {
async resolveProxy(windowId: number, url: string): Promise<string | undefined> {
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 {
Expand Down
39 changes: 37 additions & 2 deletions src/vs/platform/ipc/node/simpleIpcProxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
Expand All @@ -26,19 +47,33 @@ export class SimpleServiceProxyChannel implements IServerChannel {
call(_: unknown, command: string, args: any[]): Promise<any> {
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);
}

throw new Error(`Method not found: ${command}`);
}
}

export function createSimpleChannelProxy<T>(channel: IChannel): T {
export function createSimpleChannelProxy<T>(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);
};
}

Expand Down

0 comments on commit 0d85351

Please sign in to comment.