diff --git a/src/vs/platform/browserView/common/browserView.ts b/src/vs/platform/browserView/common/browserView.ts index a604525d9f1612..d186581be34e18 100644 --- a/src/vs/platform/browserView/common/browserView.ts +++ b/src/vs/platform/browserView/common/browserView.ts @@ -256,13 +256,19 @@ export function matchesBrowserViewAudience(candidate: IBrowserViewAudience, patt && (pattern.sessionId === undefined || pattern.sessionId === candidate.sessionId); } +/** Identifies the workbench window and optional Agents Window session that host a browser view. */ +export interface IBrowserViewHost { + readonly windowId: number; + readonly sessionId?: string; +} + /** * Summary information about a browser view, including its current state and * ownership. Returned by the main service when listing or creating views. */ export interface IBrowserViewInfo { readonly id: string; - readonly hostWindowId: number; + readonly host: IBrowserViewHost; readonly owner: IBrowserViewOwner; readonly associatedResource?: UriComponents; readonly state: IBrowserViewState; @@ -288,7 +294,7 @@ export interface IBrowserViewCreatedEvent { /** Host, ownership, storage, and initial access for a newly created browser view. */ export interface IBrowserViewCreationContext { - readonly hostWindowId: number; + readonly host: IBrowserViewHost; readonly owner: IBrowserViewOwner; readonly session: BrowserViewSessionSelector; /** Grants automation clients access before the view is announced to other processes. */ diff --git a/src/vs/platform/browserView/electron-main/browserView.ts b/src/vs/platform/browserView/electron-main/browserView.ts index 3d5e5a67985d61..6831bae3194932 100644 --- a/src/vs/platform/browserView/electron-main/browserView.ts +++ b/src/vs/platform/browserView/electron-main/browserView.ts @@ -7,7 +7,7 @@ import { screen, WebContentsView, webContents } from 'electron'; import { Disposable } from '../../../base/common/lifecycle.js'; import { Emitter, Event } from '../../../base/common/event.js'; import { VSBuffer } from '../../../base/common/buffer.js'; -import { IBrowserViewAudience, IBrowserViewBounds, IBrowserViewDevToolsStateEvent, IBrowserViewFocusEvent, IBrowserViewKeyDownEvent, IBrowserViewState, IBrowserViewNavigationEvent, IBrowserViewLoadingEvent, IBrowserViewLoadError, IBrowserViewTitleChangeEvent, IBrowserViewFaviconChangeEvent, IBrowserViewCaptureScreenshotOptions, IBrowserViewFindInPageOptions, IBrowserViewFindInPageResult, IBrowserViewVisibilityEvent, browserViewIsolatedWorldId, browserZoomFactors, browserZoomDefaultIndex, IBrowserViewOwner, IBrowserViewEditorOpenOptions, IBrowserViewPermissionRequestEvent, equalsBrowserViewAudience, isBrowserViewAssociatedResourceNavigation, matchesBrowserViewAudience } from '../common/browserView.js'; +import { IBrowserViewAudience, IBrowserViewBounds, IBrowserViewDevToolsStateEvent, IBrowserViewFocusEvent, IBrowserViewKeyDownEvent, IBrowserViewState, IBrowserViewNavigationEvent, IBrowserViewLoadingEvent, IBrowserViewLoadError, IBrowserViewTitleChangeEvent, IBrowserViewFaviconChangeEvent, IBrowserViewCaptureScreenshotOptions, IBrowserViewFindInPageOptions, IBrowserViewFindInPageResult, IBrowserViewVisibilityEvent, browserViewIsolatedWorldId, browserZoomFactors, browserZoomDefaultIndex, IBrowserViewOwner, IBrowserViewEditorOpenOptions, IBrowserViewPermissionRequestEvent, equalsBrowserViewAudience, isBrowserViewAssociatedResourceNavigation, matchesBrowserViewAudience, IBrowserViewHost } from '../common/browserView.js'; import { BrowserViewEmulator } from './browserViewEmulator.js'; import { BrowserViewInspector } from './browserViewInspector.js'; import { IWindowsMainService } from '../../windows/electron-main/windows.js'; @@ -123,7 +123,7 @@ export class BrowserView extends Disposable { constructor( public readonly id: string, - public readonly hostWindowId: number, + public readonly host: IBrowserViewHost, owner: IBrowserViewOwner, public readonly associatedResource: URI | undefined, public readonly session: BrowserSession, @@ -167,9 +167,9 @@ export class BrowserView extends Disposable { this._view.setBounds({ x: 0, y: 0, width: 1024, height: 768 }); this._view.setBackgroundColor('#FFFFFF'); - this._ownerWindow = this.windowsMainService.getWindowById(hostWindowId)!; + this._ownerWindow = this.windowsMainService.getWindowById(host.windowId)!; if (!this._ownerWindow) { - throw new Error(`Window with ID ${hostWindowId} not found`); + throw new Error(`Window with ID ${host.windowId} not found`); } this._register(this._ownerWindow.onDidClose(() => this.dispose())); this._register(this._ownerWindow.onWillLoad((e) => { diff --git a/src/vs/platform/browserView/electron-main/browserViewGroup.ts b/src/vs/platform/browserView/electron-main/browserViewGroup.ts index b235c432f59c51..a42b41d8cdb700 100644 --- a/src/vs/platform/browserView/electron-main/browserViewGroup.ts +++ b/src/vs/platform/browserView/electron-main/browserViewGroup.ts @@ -58,7 +58,7 @@ export class BrowserViewGroup extends Disposable implements ICDPBrowserTarget, I super(); this._register(this.browserViewMainService.onDidCreateBrowserView(({ info }) => { - if (info.hostWindowId !== this.targetContext.hostWindowId) { + if (info.host.windowId !== this.targetContext.host.windowId) { return; } @@ -91,7 +91,7 @@ export class BrowserViewGroup extends Disposable implements ICDPBrowserTarget, I } this._isActive = true; - const views = await this.browserViewMainService.getBrowserViews(this.targetContext.hostWindowId); + const views = await this.browserViewMainService.getBrowserViews(this.targetContext.host.windowId); await Promise.all(views.map(async info => { const view = this.browserViewMainService.tryGetBrowserView(info.id); if (view) { @@ -241,7 +241,7 @@ export class BrowserViewGroup extends Disposable implements ICDPBrowserTarget, I const view = target.view.getWebContentsView(); const viewBounds = view.getBounds(); return { - windowId: this.targetContext.hostWindowId, + windowId: this.targetContext.host.windowId, bounds: { left: viewBounds.x, top: viewBounds.y, diff --git a/src/vs/platform/browserView/electron-main/browserViewMainService.ts b/src/vs/platform/browserView/electron-main/browserViewMainService.ts index a21b231300fd9e..d7676a4a66c9cb 100644 --- a/src/vs/platform/browserView/electron-main/browserViewMainService.ts +++ b/src/vs/platform/browserView/electron-main/browserViewMainService.ts @@ -128,7 +128,7 @@ export class BrowserViewMainService extends Disposable implements IBrowserViewMa private _getViewInfo(view: BrowserView): IBrowserViewInfo { return { id: view.id, - hostWindowId: view.hostWindowId, + host: view.host, owner: view.owner, associatedResource: view.associatedResource, state: view.getState() @@ -138,7 +138,7 @@ export class BrowserViewMainService extends Disposable implements IBrowserViewMa async getBrowserViews(windowId?: number): Promise { const result: IBrowserViewInfo[] = []; for (const [, view] of this.browserViews) { - if (windowId !== undefined && view.hostWindowId !== windowId) { + if (windowId !== undefined && view.host.windowId !== windowId) { continue; } result.push(this._getViewInfo(view)); @@ -379,7 +379,7 @@ export class BrowserViewMainService extends Disposable implements IBrowserViewMa this._ensureWindowCloseSubscription(windowId); for (const [, view] of this.browserViews) { - if (view.hostWindowId === windowId) { + if (view.host.windowId === windowId) { if (didThemeChange) { view.inspector.setTheme(config.theme); } @@ -427,13 +427,13 @@ export class BrowserViewMainService extends Disposable implements IBrowserViewMa /** * Create a browser view backed by the given {@link BrowserSession}. */ - private _createNativeBrowserView(id: string, hostWindowId: number, owner: IBrowserViewOwner, browserSession: BrowserSession, associatedResource?: URI, options?: Electron.WebContentsViewConstructorOptions): BrowserView { + private _createNativeBrowserView(id: string, host: IBrowserViewCreationContext['host'], owner: IBrowserViewOwner, browserSession: BrowserSession, associatedResource?: URI, options?: Electron.WebContentsViewConstructorOptions): BrowserView { if (this.browserViews.has(id)) { throw new Error(`Browser view with id ${id} already exists`); } browserSession.connectStorage(this.applicationStorageMainService); - const windowConfiguration = this._windowConfigurations.get(hostWindowId); + const windowConfiguration = this._windowConfigurations.get(host.windowId); if (typeof windowConfiguration?.maxHistoryEntries === 'number') { browserSession.history.setMaxEntries(windowConfiguration.maxHistoryEntries); } @@ -444,14 +444,14 @@ export class BrowserViewMainService extends Disposable implements IBrowserViewMa const view = this.instantiationService.createInstance( BrowserView, id, - hostWindowId, + host, owner, associatedResource, browserSession, // Child views share their host, owner, and storage, but do not implicitly inherit agent access. (childOwner, url, electronOptions, editorOptions) => { return this._createBrowserView(generateUuid(), { - hostWindowId, + host, owner: childOwner, session: browserSession.id, initialUrl: url || undefined @@ -474,8 +474,8 @@ export class BrowserViewMainService extends Disposable implements IBrowserViewMa } private _createBrowserView(id: string, options: IBrowserViewCreateOptions, editorOpenRequest?: IBrowserViewEditorOpenOptions, electronOptions?: Electron.WebContentsViewConstructorOptions): BrowserView { - const browserSession = this._resolveBrowserSession(id, options.hostWindowId, options.session); - const view = this._createNativeBrowserView(id, options.hostWindowId, options.owner, browserSession, URI.revive(options.associatedResource), electronOptions); + const browserSession = this._resolveBrowserSession(id, options.host.windowId, options.session); + const view = this._createNativeBrowserView(id, options.host, options.owner, browserSession, URI.revive(options.associatedResource), electronOptions); if (options.initialAudiences) { view.setAudiences(options.initialAudiences); } @@ -516,7 +516,7 @@ export class BrowserViewMainService extends Disposable implements IBrowserViewMa return; } - const windowConfiguration = this._windowConfigurations.get(view.hostWindowId); + const windowConfiguration = this._windowConfigurations.get(view.host.windowId); const inspectTarget = windowConfiguration?.aiFeaturesDisabled ? undefined : params.frame && await view.inspector.getElementHandle(BrowserViewInspectElementId.ContextMenuTarget, params.frame); @@ -527,7 +527,7 @@ export class BrowserViewMainService extends Disposable implements IBrowserViewMa label: localize('browser.contextMenu.openLinkInNewTab', 'Open Link in New Tab'), click: () => { void this.openNew(params.linkURL, { - hostWindowId: view.hostWindowId, + host: view.host, owner: view.owner, session: view.session.id, }, { preserveFocus: true, background: true }, 'browserLinkBackground'); @@ -557,7 +557,7 @@ export class BrowserViewMainService extends Disposable implements IBrowserViewMa label: localize('browser.contextMenu.openImageInNewTab', 'Open Image in New Tab'), click: () => { void this.openNew(params.srcURL!, { - hostWindowId: view.hostWindowId, + host: view.host, owner: view.owner, session: view.session.id, }, { preserveFocus: true, background: true }, 'browserLinkBackground'); diff --git a/src/vs/platform/browserView/node/playwrightService.ts b/src/vs/platform/browserView/node/playwrightService.ts index 25fdd3ef5d3225..d3bb90c07c6fc3 100644 --- a/src/vs/platform/browserView/node/playwrightService.ts +++ b/src/vs/platform/browserView/node/playwrightService.ts @@ -117,7 +117,9 @@ export class PlaywrightService extends Disposable implements IPlaywrightService const group = await this.browserViewGroupRemoteService.createGroup( { audience: { type: 'agent', sessionId } }, { - hostWindowId: this.windowId, + host: { + windowId: this.windowId + }, ...getAgentBrowserViewCreationDefaults(sessionId, this.useSessionStorageAffinity ? sessionId : undefined) } ); diff --git a/src/vs/workbench/contrib/browserView/common/browserView.ts b/src/vs/workbench/contrib/browserView/common/browserView.ts index 4bb35e476f1b73..5274edb2b689d5 100644 --- a/src/vs/workbench/contrib/browserView/common/browserView.ts +++ b/src/vs/workbench/contrib/browserView/common/browserView.ts @@ -57,6 +57,7 @@ import { IBrowserDeviceProfile, IBrowserViewPermissionRequestEvent, IBrowserElementSelectionState, + IBrowserViewHost, } from '../../../../platform/browserView/common/browserView.js'; import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js'; import { isLocalhostAuthority } from '../../../../platform/url/common/trustedDomains.js'; @@ -362,6 +363,7 @@ export interface IBrowserViewCDPService { */ export interface IBrowserViewModel extends IDisposable { readonly id: string; + readonly host: IBrowserViewHost; readonly owner: IBrowserViewOwner; readonly associatedResource: URI | undefined; readonly url: string; @@ -486,6 +488,7 @@ export class BrowserViewModel extends Disposable implements IBrowserViewModel { constructor( readonly id: string, + readonly host: IBrowserViewHost, owner: IBrowserViewOwner, readonly associatedResource: URI | undefined, initialState: IBrowserViewState, diff --git a/src/vs/workbench/contrib/browserView/electron-browser/browserViewCDPService.ts b/src/vs/workbench/contrib/browserView/electron-browser/browserViewCDPService.ts index abf2c74f1e0982..b90f439389b18f 100644 --- a/src/vs/workbench/contrib/browserView/electron-browser/browserViewCDPService.ts +++ b/src/vs/workbench/contrib/browserView/electron-browser/browserViewCDPService.ts @@ -30,7 +30,9 @@ export class BrowserViewCDPService extends Disposable implements IBrowserViewCDP return this._groupService.createGroup( { browserIds: [browserId] }, { - hostWindowId: mainWindow.vscodeWindowId, + host: { + windowId: mainWindow.vscodeWindowId + }, owner: { type: 'user' }, session: { scope: BrowserViewStorageScope.Ephemeral } } diff --git a/src/vs/workbench/contrib/browserView/electron-browser/browserViewWorkbenchService.ts b/src/vs/workbench/contrib/browserView/electron-browser/browserViewWorkbenchService.ts index 99f97400015066..3e987b284d8c43 100644 --- a/src/vs/workbench/contrib/browserView/electron-browser/browserViewWorkbenchService.ts +++ b/src/vs/workbench/contrib/browserView/electron-browser/browserViewWorkbenchService.ts @@ -175,7 +175,7 @@ export class BrowserViewWorkbenchService extends Disposable implements IBrowserV // Listen for new browser views this._register(this._browserViewService.onDidCreateBrowserView(e => { - if (e.info.hostWindowId !== this._mainWindowId) { + if (e.info.host.windowId !== this._mainWindowId) { return; // Not for this window } @@ -363,7 +363,9 @@ export class BrowserViewWorkbenchService extends Disposable implements IBrowserV const info = await this._browserViewService.getOrCreateBrowserView( id, { - hostWindowId: this._mainWindowId, + host: { + windowId: this._mainWindowId + }, owner: createOptions?.owner ?? { type: 'user' }, associatedResource, session: createOptions?.session ?? { scope: await this._resolveStorageScope() }, @@ -451,7 +453,7 @@ export class BrowserViewWorkbenchService extends Disposable implements IBrowserV : initialUrl ? { ...info.state, url: initialUrl } : info.state; - const model = this.instantiationService.createInstance(BrowserViewModel, info.id, info.owner, associatedResource, state, this._browserViewService); + const model = this.instantiationService.createInstance(BrowserViewModel, info.id, info.host, info.owner, associatedResource, state, this._browserViewService); // Sanity: both pass and assign the model to be sure. It will no-op if already set. this._getOrCreateLazy({ id: info.id, associatedResource, url: initialUrl }, model).model = model;