Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some editors and aux window fixes #195326

Merged
merged 13 commits into from
Oct 11, 2023
4 changes: 2 additions & 2 deletions src/vs/base/parts/sandbox/electron-sandbox/globals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export const process: ISandboxNodeProcess = globals.vscode.process;
export const context: ISandboxContext = globals.vscode.context;

export interface IGlobalsSlim {
readonly ipcRenderer: Pick<import('vs/base/parts/sandbox/electron-sandbox/electronTypes').IpcRenderer, 'send'>;
readonly ipcRenderer: Pick<import('vs/base/parts/sandbox/electron-sandbox/electronTypes').IpcRenderer, 'send' | 'invoke'>;
readonly webFrame: import('vs/base/parts/sandbox/electron-sandbox/electronTypes').WebFrame;
}

Expand All @@ -138,7 +138,7 @@ export function getGlobals(win: Window): IGlobalsSlim | undefined {

const auxiliaryWindowCandidate = win as unknown as {
vscode: {
ipcRenderer: Pick<import('vs/base/parts/sandbox/electron-sandbox/electronTypes').IpcRenderer, 'send'>;
ipcRenderer: Pick<import('vs/base/parts/sandbox/electron-sandbox/electronTypes').IpcRenderer, 'send' | 'invoke'>;
webFrame: import('vs/base/parts/sandbox/electron-sandbox/electronTypes').WebFrame;
};
};
Expand Down
13 changes: 12 additions & 1 deletion src/vs/base/parts/sandbox/electron-sandbox/preload-slim.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
* A minimal set of methods exposed from Electron's `ipcRenderer`
* to support communication to main process.
*
* @typedef {Pick<import('./electronTypes').IpcRenderer, 'send'>} IpcRenderer
* @typedef {Pick<import('./electronTypes').IpcRenderer, 'send' | 'invoke'>} IpcRenderer
*
* @type {IpcRenderer}
*/
Expand All @@ -41,6 +41,17 @@
if (validateIPC(channel)) {
ipcRenderer.send(channel, ...args);
}
},

/**
* @param {string} channel
* @param {any[]} args
* @returns {Promise<any> | never}
*/
invoke(channel, ...args) {
if (validateIPC(channel)) {
return ipcRenderer.invoke(channel, ...args);
}
}
},

Expand Down
12 changes: 9 additions & 3 deletions src/vs/code/electron-main/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@ import { ElectronPtyHostStarter } from 'vs/platform/terminal/electron-main/elect
import { PtyHostService } from 'vs/platform/terminal/node/ptyHostService';
import { NODE_REMOTE_RESOURCE_CHANNEL_NAME, NODE_REMOTE_RESOURCE_IPC_METHOD_NAME, NodeRemoteResourceResponse, NodeRemoteResourceRouter } from 'vs/platform/remote/common/electronRemoteResources';
import { Lazy } from 'vs/base/common/lazy';
import { AuxiliaryWindow } from 'vs/platform/windows/electron-main/auxiliaryWindow';
import { IAuxiliaryWindowsMainService } from 'vs/platform/auxiliaryWindow/electron-main/auxiliaryWindows';
import { AuxiliaryWindowsMainService } from 'vs/platform/auxiliaryWindow/electron-main/auxiliaryWindowsMainService';

/**
* The main VS Code application. There will only ever be one instance,
Expand All @@ -132,6 +133,7 @@ export class CodeApplication extends Disposable {
};

private windowsMainService: IWindowsMainService | undefined;
private auxiliaryWindowsMainService: IAuxiliaryWindowsMainService | undefined;
private nativeHostMainService: INativeHostMainService | undefined;

constructor(
Expand Down Expand Up @@ -386,7 +388,7 @@ export class CodeApplication extends Disposable {
// Child Window: delegate to `AuxiliaryWindow` class
const isChildWindow = contents?.opener?.url.startsWith(`${Schemas.vscodeFileResource}://${VSCODE_AUTHORITY}/`);
if (isChildWindow) {
this.mainInstantiationService.createInstance(AuxiliaryWindow, contents);
this.auxiliaryWindowsMainService?.registerWindow(contents);
}

// Block any in-page navigation
Expand All @@ -406,7 +408,7 @@ export class CodeApplication extends Disposable {

return {
action: 'allow',
overrideBrowserWindowOptions: AuxiliaryWindow.open(this.mainInstantiationService)
overrideBrowserWindowOptions: this.auxiliaryWindowsMainService?.createWindow()
};
}

Expand Down Expand Up @@ -459,6 +461,8 @@ export class CodeApplication extends Disposable {

//#region Bootstrap IPC Handlers

validatedIpcMain.handle('vscode:getWindowId', event => Promise.resolve(event.sender.id));

validatedIpcMain.handle('vscode:fetchShellEnv', event => {

// Prefer to use the args and env from the target window
Expand Down Expand Up @@ -992,6 +996,7 @@ export class CodeApplication extends Disposable {

// Windows
services.set(IWindowsMainService, new SyncDescriptor(WindowsMainService, [machineId, this.userEnv], false));
services.set(IAuxiliaryWindowsMainService, new SyncDescriptor(AuxiliaryWindowsMainService, undefined, false));

// Dialogs
const dialogMainService = new DialogMainService(this.logService, this.productService);
Expand Down Expand Up @@ -1210,6 +1215,7 @@ export class CodeApplication extends Disposable {

private async openFirstWindow(accessor: ServicesAccessor, initialProtocolUrls: IInitialProtocolUrls | undefined): Promise<ICodeWindow[]> {
const windowsMainService = this.windowsMainService = accessor.get(IWindowsMainService);
this.auxiliaryWindowsMainService = accessor.get(IAuxiliaryWindowsMainService);

const context = isLaunchedFromCli(process.env) ? OpenContext.CLI : OpenContext.DESKTOP;
const args = this.environmentMainService.args;
Expand Down
71 changes: 71 additions & 0 deletions src/vs/platform/auxiliaryWindow/electron-main/auxiliaryWindow.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { BrowserWindow, WebContents } from 'electron';
import { Emitter, Event } from 'vs/base/common/event';
import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService';
import { BaseWindow } from 'vs/platform/windows/electron-main/windowImpl';

export interface IAuxiliaryWindow {

readonly onDidClose: Event<void>;

readonly id: number;
readonly win: BrowserWindow | null;

focus(options?: { force: boolean }): void;
}

export class AuxiliaryWindow extends BaseWindow implements IAuxiliaryWindow {

readonly id = this.contents.id;

private readonly _onDidClose = this._register(new Emitter<void>());
readonly onDidClose = this._onDidClose.event;

private _win: BrowserWindow | null = null;
get win() {
if (!this._win) {
const window = BrowserWindow.fromWebContents(this.contents);
if (window) {
this._win = window;
this.registerWindowListeners(window);
}
}

return this._win;
}

protected getWin(): BrowserWindow | null {
return this.win;
}

constructor(
private readonly contents: WebContents,
@IEnvironmentMainService private readonly environmentMainService: IEnvironmentMainService
) {
super();

this.create();
}

private create(): void {

// Handle devtools argument
if (this.environmentMainService.args['open-devtools'] === true) {
this.contents.openDevTools({ mode: 'bottom' });
}
}

private registerWindowListeners(window: BrowserWindow): void {

// Window close
window.on('closed', () => {
this._onDidClose.fire();

this.dispose();
});
}
}
21 changes: 21 additions & 0 deletions src/vs/platform/auxiliaryWindow/electron-main/auxiliaryWindows.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { BrowserWindowConstructorOptions, WebContents } from 'electron';
import { IAuxiliaryWindow } from 'vs/platform/auxiliaryWindow/electron-main/auxiliaryWindow';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';

export const IAuxiliaryWindowsMainService = createDecorator<IAuxiliaryWindowsMainService>('auxiliaryWindowsMainService');

export interface IAuxiliaryWindowsMainService {

readonly _serviceBrand: undefined;

createWindow(): BrowserWindowConstructorOptions;
registerWindow(webContents: WebContents): void;

getWindowById(windowId: number): IAuxiliaryWindow | undefined;
getFocusedWindow(): IAuxiliaryWindow | undefined;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { BrowserWindow, BrowserWindowConstructorOptions, WebContents } from 'electron';
import { Event } from 'vs/base/common/event';
import { FileAccess } from 'vs/base/common/network';
import { AuxiliaryWindow, IAuxiliaryWindow } from 'vs/platform/auxiliaryWindow/electron-main/auxiliaryWindow';
import { IAuxiliaryWindowsMainService } from 'vs/platform/auxiliaryWindow/electron-main/auxiliaryWindows';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { defaultBrowserWindowOptions } from 'vs/platform/windows/electron-main/windows';

export class AuxiliaryWindowsMainService implements IAuxiliaryWindowsMainService {

declare readonly _serviceBrand: undefined;

private readonly windows = new Map<number, IAuxiliaryWindow>();

constructor(
@IInstantiationService private readonly instantiationService: IInstantiationService
) { }

createWindow(): BrowserWindowConstructorOptions {
return this.instantiationService.invokeFunction(defaultBrowserWindowOptions, undefined, {
webPreferences: {
preload: FileAccess.asFileUri('vs/base/parts/sandbox/electron-sandbox/preload-slim.js').fsPath
}
});
}

registerWindow(webContents: WebContents): void {
const auxiliaryWindow = this.instantiationService.createInstance(AuxiliaryWindow, webContents);
this.windows.set(auxiliaryWindow.id, auxiliaryWindow);

Event.once(auxiliaryWindow.onDidClose)(() => this.windows.delete(auxiliaryWindow.id));
}

getWindowById(windowId: number): IAuxiliaryWindow | undefined {
return this.windows.get(windowId);
}

getFocusedWindow(): IAuxiliaryWindow | undefined {
const window = BrowserWindow.getFocusedWindow();
if (window) {
return this.getWindowById(window.id);
}

return undefined;
}
}
4 changes: 2 additions & 2 deletions src/vs/platform/native/common/native.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export interface ICommonNativeHostService {
maximizeWindow(): Promise<void>;
unmaximizeWindow(): Promise<void>;
minimizeWindow(): Promise<void>;
moveWindowTop(): Promise<void>;
moveWindowTop(options?: { targetWindowId?: number }): Promise<void>;

/**
* Only supported on Windows and macOS. Updates the window controls to match the title bar size.
Expand All @@ -96,7 +96,7 @@ export interface ICommonNativeHostService {
* should only be used if it is necessary to steal focus from the current
* focused application which may not be VSCode.
*/
focusWindow(options?: { windowId?: number; force?: boolean }): Promise<void>;
focusWindow(options?: { targetWindowId?: number; force?: boolean }): Promise<void>;

// Dialogs
showMessageBox(options: MessageBoxOptions): Promise<MessageBoxReturnValue>;
Expand Down