diff --git a/src/vs/platform/native/common/native.ts b/src/vs/platform/native/common/native.ts index b3333190d1b62..6f0690c451b8f 100644 --- a/src/vs/platform/native/common/native.ts +++ b/src/vs/platform/native/common/native.ts @@ -75,6 +75,7 @@ export interface ICommonNativeHostService { getWindowCount(): Promise; getActiveWindowId(): Promise; getActiveWindowPosition(): Promise; + getActiveWindowNativeHandle(id: number): Promise; openWindow(options?: IOpenEmptyWindowOptions): Promise; openWindow(toOpen: IWindowOpenable[], options?: IOpenWindowOptions): Promise; diff --git a/src/vs/platform/native/electron-main/nativeHostMainService.ts b/src/vs/platform/native/electron-main/nativeHostMainService.ts index c9a79ccf673ed..1546c8f9f89d5 100644 --- a/src/vs/platform/native/electron-main/nativeHostMainService.ts +++ b/src/vs/platform/native/electron-main/nativeHostMainService.ts @@ -189,6 +189,10 @@ export class NativeHostMainService extends Disposable implements INativeHostMain return undefined; } + async getActiveWindowNativeHandle(windowId: number | undefined, id: number): Promise { + return this.windowById(id, windowId)?.win?.getNativeWindowHandle().toString('base64'); + } + openWindow(windowId: number | undefined, options?: IOpenEmptyWindowOptions): Promise; openWindow(windowId: number | undefined, toOpen: IWindowOpenable[], options?: IOpenWindowOptions): Promise; openWindow(windowId: number | undefined, arg1?: IOpenEmptyWindowOptions | IWindowOpenable[], arg2?: IOpenWindowOptions): Promise { diff --git a/src/vs/workbench/api/browser/mainThreadWindow.ts b/src/vs/workbench/api/browser/mainThreadWindow.ts index 29760af2182c4..602e567a2e655 100644 --- a/src/vs/workbench/api/browser/mainThreadWindow.ts +++ b/src/vs/workbench/api/browser/mainThreadWindow.ts @@ -11,6 +11,7 @@ import { extHostNamedCustomer, IExtHostContext } from '../../services/extensions import { ExtHostContext, ExtHostWindowShape, IOpenUriOptions, MainContext, MainThreadWindowShape } from '../common/extHost.protocol.js'; import { IHostService } from '../../services/host/browser/host.js'; import { IUserActivityService } from '../../services/userActivity/common/userActivityService.js'; +import { INativeHostService } from '../../../platform/native/common/native.js'; @extHostNamedCustomer(MainContext.MainThreadWindow) export class MainThreadWindow implements MainThreadWindowShape { @@ -21,6 +22,7 @@ export class MainThreadWindow implements MainThreadWindowShape { constructor( extHostContext: IExtHostContext, @IHostService private readonly hostService: IHostService, + @INativeHostService private readonly nativeHostService: INativeHostService, @IOpenerService private readonly openerService: IOpenerService, @IUserActivityService private readonly userActivityService: IUserActivityService, ) { @@ -29,17 +31,26 @@ export class MainThreadWindow implements MainThreadWindowShape { Event.latch(hostService.onDidChangeFocus) (this.proxy.$onDidChangeWindowFocus, this.proxy, this.disposables); userActivityService.onDidChangeIsActive(this.proxy.$onDidChangeWindowActive, this.proxy, this.disposables); + this.disposables.add(hostService.onDidChangeActiveWindow((id) => this.onDidChangeActiveWindow(id))); } dispose(): void { this.disposables.dispose(); } - $getInitialState() { - return Promise.resolve({ + private onDidChangeActiveWindow(id: number): void { + this.nativeHostService.getActiveWindowNativeHandle(id).then(nativeHandle => { + this.proxy.$onDidChangeActiveWindowHandle(nativeHandle); + }); + } + + async $getInitialState() { + const nativeHandle = await this.nativeHostService.getActiveWindowNativeHandle(this.nativeHostService.windowId); + return { isFocused: this.hostService.hasFocus, isActive: this.userActivityService.isActive, - }); + nativeHandle + }; } async $openUri(uriComponents: UriComponents, uriString: string | undefined, options: IOpenUriOptions): Promise { diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 2f20db169f796..1a7a08477fba7 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -439,7 +439,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I }, get handle(): string | undefined { checkProposedApiEnabled(extension, 'nativeWindowHandle'); - return initData.handle; + return extHostWindow.nativeHandle; } }; if (!initData.environment.extensionTestsLocationURI) { diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 2ddf94fa6b84d..d85dd5c506eeb 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1702,7 +1702,7 @@ export interface IOpenUriOptions { } export interface MainThreadWindowShape extends IDisposable { - $getInitialState(): Promise<{ isFocused: boolean; isActive: boolean }>; + $getInitialState(): Promise<{ isFocused: boolean; isActive: boolean; nativeHandle?: string }>; $openUri(uri: UriComponents, uriString: string | undefined, options: IOpenUriOptions): Promise; $asExternalUri(uri: UriComponents, options: IOpenUriOptions): Promise; } @@ -2596,6 +2596,7 @@ export interface ExtHostDecorationsShape { export interface ExtHostWindowShape { $onDidChangeWindowFocus(value: boolean): void; $onDidChangeWindowActive(value: boolean): void; + $onDidChangeActiveWindowHandle(handle: string | undefined): void; } export interface ExtHostLogLevelServiceShape { diff --git a/src/vs/workbench/api/common/extHostWindow.ts b/src/vs/workbench/api/common/extHostWindow.ts index 6f74b721b8a88..f938a25bbc6ee 100644 --- a/src/vs/workbench/api/common/extHostWindow.ts +++ b/src/vs/workbench/api/common/extHostWindow.ts @@ -11,6 +11,7 @@ import { createDecorator } from '../../../platform/instantiation/common/instanti import { IExtHostRpcService } from './extHostRpcService.js'; import { WindowState } from 'vscode'; import { ExtHostWindowShape, IOpenUriOptions, MainContext, MainThreadWindowShape } from './extHost.protocol.js'; +import { IExtHostInitDataService } from './extHostInitDataService.js'; export class ExtHostWindow implements ExtHostWindowShape { @@ -24,6 +25,7 @@ export class ExtHostWindow implements ExtHostWindowShape { private readonly _onDidChangeWindowState = new Emitter(); readonly onDidChangeWindowState: Event = this._onDidChangeWindowState.event; + private _nativeHandle: string | undefined = this._initData.handle; private _state = ExtHostWindow.InitialState; getState(): WindowState { @@ -40,14 +42,26 @@ export class ExtHostWindow implements ExtHostWindowShape { }; } - constructor(@IExtHostRpcService extHostRpc: IExtHostRpcService) { + constructor( + @IExtHostInitDataService private readonly _initData: IExtHostInitDataService, + @IExtHostRpcService extHostRpc: IExtHostRpcService + ) { this._proxy = extHostRpc.getProxy(MainContext.MainThreadWindow); - this._proxy.$getInitialState().then(({ isFocused, isActive }) => { + this._proxy.$getInitialState().then(({ isFocused, isActive, nativeHandle }) => { this.onDidChangeWindowProperty('focused', isFocused); this.onDidChangeWindowProperty('active', isActive); + this.$onDidChangeActiveWindowHandle(nativeHandle); }); } + get nativeHandle(): string | undefined { + return this._nativeHandle; + } + + $onDidChangeActiveWindowHandle(handle: string | undefined): void { + this._nativeHandle = handle; + } + $onDidChangeWindowFocus(value: boolean) { this.onDidChangeWindowProperty('focused', value); } diff --git a/src/vs/workbench/test/electron-sandbox/workbenchTestServices.ts b/src/vs/workbench/test/electron-sandbox/workbenchTestServices.ts index 46b3d633b41ae..3acce0cab4fea 100644 --- a/src/vs/workbench/test/electron-sandbox/workbenchTestServices.ts +++ b/src/vs/workbench/test/electron-sandbox/workbenchTestServices.ts @@ -85,6 +85,7 @@ export class TestNativeHostService implements INativeHostService { async getWindows(): Promise { return []; } async getActiveWindowId(): Promise { return undefined; } async getActiveWindowPosition(): Promise { return undefined; } + async getActiveWindowNativeHandle(): Promise { return undefined; } openWindow(options?: IOpenEmptyWindowOptions): Promise; openWindow(toOpen: IWindowOpenable[], options?: IOpenWindowOptions): Promise;