From 5d70ccdb1264d9b2fa09899ea826c5fad0ca8ceb Mon Sep 17 00:00:00 2001 From: Wooseong Kim Date: Thu, 1 Oct 2026 20:21:10 +0900 Subject: [PATCH 1/3] fix(browser): focus the owning split when the page guest is focused Guest webview focus does not bubble to the overlay, so Ctrl+Tab kept the previously focused split. Address-bar focus still stays put. Fixes #22144 --- .../bind-browser-page-webview-listeners.ts | 15 +++++- .../browser-guest-owning-group.test.ts | 46 +++++++++++++++++++ .../host-guest/browser-guest-owning-group.ts | 36 +++++++++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 src/renderer/src/components/browser-pane/host-guest/browser-guest-owning-group.test.ts create mode 100644 src/renderer/src/components/browser-pane/host-guest/browser-guest-owning-group.ts diff --git a/src/renderer/src/components/browser-pane/host-guest/bind-browser-page-webview-listeners.ts b/src/renderer/src/components/browser-pane/host-guest/bind-browser-page-webview-listeners.ts index f8699324889c..a05ed509bca4 100644 --- a/src/renderer/src/components/browser-pane/host-guest/bind-browser-page-webview-listeners.ts +++ b/src/renderer/src/components/browser-pane/host-guest/bind-browser-page-webview-listeners.ts @@ -1,5 +1,7 @@ +import { useAppStore } from '@/store' import { normalizeBrowserNavigationUrl } from '../../../../../shared/browser-url' import { ORCA_BROWSER_BLANK_URL } from '../../../../../shared/constants' +import { focusOwningGroupForBrowserGuest } from './browser-guest-owning-group' import { parkBrowserPageViewport } from './browser-page-viewport' import { subscribeBrowserSystemResume } from './browser-system-resume' import { @@ -147,7 +149,18 @@ export function bindBrowserPageWebviewListeners({ webview.addEventListener('dom-ready', handleDomReady) webview.addEventListener('render-process-gone', guestRecovery.recoverRenderer) webview.addEventListener('destroyed', handleGuestDestroyed) - webview.addEventListener('focus', dismissAddressBarSuggestions) + webview.addEventListener('focus', () => { + dismissAddressBarSuggestions() + // Why: the guest does not bubble focus to the overlay, so the owning split + // stays stale and Ctrl+Tab targets the previous group (#22144). + const state = useAppStore.getState() + focusOwningGroupForBrowserGuest({ + worktreeId, + browserTabId, + unifiedTabsByWorktree: state.unifiedTabsByWorktree, + focusGroup: state.focusGroup + }) + }) webview.addEventListener('did-start-loading', handleDidStartLoading) webview.addEventListener('did-start-navigation', handleDidStartNavigation) webview.addEventListener('did-redirect-navigation', handleDidRedirectNavigation) diff --git a/src/renderer/src/components/browser-pane/host-guest/browser-guest-owning-group.test.ts b/src/renderer/src/components/browser-pane/host-guest/browser-guest-owning-group.test.ts new file mode 100644 index 000000000000..47a10206757b --- /dev/null +++ b/src/renderer/src/components/browser-pane/host-guest/browser-guest-owning-group.test.ts @@ -0,0 +1,46 @@ +import { describe, expect, it, vi } from 'vitest' +import { focusOwningGroupForBrowserGuest } from './browser-guest-owning-group' + +const browserTab = { + contentType: 'browser' as const, + entityId: 'page-1', + groupId: 'group-2' +} + +describe('focusOwningGroupForBrowserGuest', () => { + it('focuses the split that owns the browser page', () => { + const focusGroup = vi.fn() + focusOwningGroupForBrowserGuest({ + worktreeId: 'wt-1', + browserTabId: 'page-1', + unifiedTabsByWorktree: { 'wt-1': [browserTab] }, + focusGroup + }) + expect(focusGroup).toHaveBeenCalledTimes(1) + expect(focusGroup).toHaveBeenCalledWith('wt-1', 'group-2') + }) + + it('does not move the focused split when the page is not in a group yet', () => { + const focusGroup = vi.fn() + focusOwningGroupForBrowserGuest({ + worktreeId: 'wt-1', + browserTabId: 'page-1', + unifiedTabsByWorktree: { + 'wt-1': [{ contentType: 'terminal', entityId: 'page-1', groupId: 'group-1' }] + }, + focusGroup + }) + expect(focusGroup).not.toHaveBeenCalled() + }) + + it('ignores the same page id on another worktree', () => { + const focusGroup = vi.fn() + focusOwningGroupForBrowserGuest({ + worktreeId: 'wt-1', + browserTabId: 'page-1', + unifiedTabsByWorktree: { 'wt-2': [browserTab] }, + focusGroup + }) + expect(focusGroup).not.toHaveBeenCalled() + }) +}) diff --git a/src/renderer/src/components/browser-pane/host-guest/browser-guest-owning-group.ts b/src/renderer/src/components/browser-pane/host-guest/browser-guest-owning-group.ts new file mode 100644 index 000000000000..36933b7517df --- /dev/null +++ b/src/renderer/src/components/browser-pane/host-guest/browser-guest-owning-group.ts @@ -0,0 +1,36 @@ +import type { Tab } from '../../../../../shared/tab-types' + +type BrowserGuestTab = Pick + +/** The split that owns this browser page, or undefined while the tab is mid-move. */ +export function owningGroupIdForBrowserGuest( + tabs: readonly BrowserGuestTab[] | undefined, + browserTabId: string +): string | undefined { + for (const tab of tabs ?? []) { + if (tab.contentType === 'browser' && tab.entityId === browserTabId) { + return tab.groupId + } + } + return undefined +} + +/** + * Guest webview focus does not bubble to the overlay, so Ctrl+Tab would keep + * the previously focused split (#22144). Address-bar focus never reaches here. + */ +export function focusOwningGroupForBrowserGuest(args: { + worktreeId: string + browserTabId: string + unifiedTabsByWorktree: Readonly> + focusGroup: (worktreeId: string, groupId: string) => void +}): void { + const groupId = owningGroupIdForBrowserGuest( + args.unifiedTabsByWorktree[args.worktreeId], + args.browserTabId + ) + if (!groupId) { + return + } + args.focusGroup(args.worktreeId, groupId) +} From ccfcf1a0339afd4c89169baca77059d664f4129a Mon Sep 17 00:00:00 2001 From: Wooseong Kim Date: Thu, 1 Oct 2026 20:33:15 +0900 Subject: [PATCH 2/3] fix(browser): focus the split that owns the page workspace Co-authored-by: Cursor --- ...ind-browser-page-webview-listeners.test.ts | 116 ++++++++++++++++++ .../bind-browser-page-webview-listeners.ts | 14 ++- .../browser-guest-owning-group.test.ts | 12 +- .../host-guest/browser-guest-owning-group.ts | 13 +- 4 files changed, 138 insertions(+), 17 deletions(-) create mode 100644 src/renderer/src/components/browser-pane/host-guest/bind-browser-page-webview-listeners.test.ts diff --git a/src/renderer/src/components/browser-pane/host-guest/bind-browser-page-webview-listeners.test.ts b/src/renderer/src/components/browser-pane/host-guest/bind-browser-page-webview-listeners.test.ts new file mode 100644 index 000000000000..6cd0ac3cb17f --- /dev/null +++ b/src/renderer/src/components/browser-pane/host-guest/bind-browser-page-webview-listeners.test.ts @@ -0,0 +1,116 @@ +import { describe, expect, it, vi } from 'vitest' +import type { AttachBrowserPageWebviewArgs } from './attach-browser-page-webview' + +const focusGroup = vi.hoisted(() => vi.fn()) +const dismissAddressBarSuggestions = vi.hoisted(() => vi.fn()) + +vi.mock('@/store', () => ({ + useAppStore: { + getState: () => ({ + unifiedTabsByWorktree: { + 'wt-1': [{ contentType: 'browser', entityId: 'workspace-1', groupId: 'group-9' }] + }, + focusGroup + }) + } +})) + +vi.mock('./browser-page-webview-guest-session', () => ({ + createBrowserPageWebviewGuestSession: () => ({ + guestRecovery: { + validateAfterResume: () => {}, + recoverRenderer: () => {}, + retryRecovery: () => {}, + dispose: () => {} + }, + handleDidAttach: () => {}, + handleDomReady: () => {}, + handleGuestDestroyed: () => {} + }) +})) + +vi.mock('./browser-page-webview-loading-handlers', () => ({ + createBrowserPageWebviewLoadingHandlers: () => ({ + handleDidStartLoading: () => {}, + handleDidStopLoading: () => {}, + handleFailLoad: () => {} + }) +})) + +vi.mock('./browser-page-webview-navigation-handlers', () => ({ + createBrowserPageWebviewNavigationHandlers: () => ({ + handleDidStartNavigation: () => {}, + handleDidRedirectNavigation: () => {}, + handleFullDidNavigate: () => {}, + handleDidNavigateInPage: () => {}, + handleTitleUpdate: () => {}, + handleFaviconUpdate: () => {}, + handleAnnotationViewportMessage: () => {} + }) +})) + +vi.mock('./browser-system-resume', () => ({ + subscribeBrowserSystemResume: () => () => {} +})) + +vi.mock('./browser-page-viewport', () => ({ + parkBrowserPageViewport: () => {} +})) + +vi.mock('./webview-registry', () => ({ + isBrowserPageRendererRecoveryPending: () => false, + moveFocusToRendererBeforeWebviewDetach: () => {} +})) + +type Listener = (event?: unknown) => void + +function fakeWebview(): Electron.WebviewTag & { + listeners: Map> +} { + const listeners = new Map>() + return { + listeners, + addEventListener(type: string, listener: Listener) { + const bucket = listeners.get(type) ?? new Set() + bucket.add(listener) + listeners.set(type, bucket) + }, + removeEventListener(type: string, listener: Listener) { + listeners.get(type)?.delete(listener) + } + } as Electron.WebviewTag & { listeners: Map> } +} + +describe('bindBrowserPageWebviewListeners guest focus', () => { + it('focuses the workspace tab and removes that same callback on cleanup', async () => { + const { bindBrowserPageWebviewListeners } = + await import('./bind-browser-page-webview-listeners') + const webview = fakeWebview() + const cleanup = bindBrowserPageWebviewListeners({ + container: { removeEventListener: () => {} } as HTMLDivElement, + webview, + needsInitialNavigation: false, + onContainerDragOver: () => {}, + onContainerDrop: () => {}, + dismissAddressBarSuggestions, + args: { + browserTabId: 'page-1', + workspaceId: 'workspace-1', + worktreeId: 'wt-1', + isPaintableRef: { current: false }, + validateVisibleGuestRegistrationRef: { current: () => {} }, + retryGuestRecoveryRef: { current: () => {} }, + webviewRef: { current: null } + } as AttachBrowserPageWebviewArgs + }) + + const focusListeners = webview.listeners.get('focus') + expect(focusListeners?.size).toBe(1) + focusListeners?.forEach((listener) => listener()) + expect(dismissAddressBarSuggestions).toHaveBeenCalledTimes(1) + expect(focusGroup).toHaveBeenCalledWith('wt-1', 'group-9') + + cleanup() + expect(webview.listeners.get('focus')?.size ?? 0).toBe(0) + }) +}) diff --git a/src/renderer/src/components/browser-pane/host-guest/bind-browser-page-webview-listeners.ts b/src/renderer/src/components/browser-pane/host-guest/bind-browser-page-webview-listeners.ts index a05ed509bca4..d679425d92d9 100644 --- a/src/renderer/src/components/browser-pane/host-guest/bind-browser-page-webview-listeners.ts +++ b/src/renderer/src/components/browser-pane/host-guest/bind-browser-page-webview-listeners.ts @@ -149,18 +149,20 @@ export function bindBrowserPageWebviewListeners({ webview.addEventListener('dom-ready', handleDomReady) webview.addEventListener('render-process-gone', guestRecovery.recoverRenderer) webview.addEventListener('destroyed', handleGuestDestroyed) - webview.addEventListener('focus', () => { + // Why: the guest does not bubble focus to the overlay, so the owning split + // stays stale and Ctrl+Tab targets the previous group (#22144). The same + // function is removed on cleanup; the webview outlives detach. + const handleGuestFocus = (): void => { dismissAddressBarSuggestions() - // Why: the guest does not bubble focus to the overlay, so the owning split - // stays stale and Ctrl+Tab targets the previous group (#22144). const state = useAppStore.getState() focusOwningGroupForBrowserGuest({ worktreeId, - browserTabId, + workspaceId, unifiedTabsByWorktree: state.unifiedTabsByWorktree, focusGroup: state.focusGroup }) - }) + } + webview.addEventListener('focus', handleGuestFocus) webview.addEventListener('did-start-loading', handleDidStartLoading) webview.addEventListener('did-start-navigation', handleDidStartNavigation) webview.addEventListener('did-redirect-navigation', handleDidRedirectNavigation) @@ -198,7 +200,7 @@ export function bindBrowserPageWebviewListeners({ webview.removeEventListener('dom-ready', handleDomReady) webview.removeEventListener('render-process-gone', guestRecovery.recoverRenderer) webview.removeEventListener('destroyed', handleGuestDestroyed) - webview.removeEventListener('focus', dismissAddressBarSuggestions) + webview.removeEventListener('focus', handleGuestFocus) webview.removeEventListener('did-start-loading', handleDidStartLoading) webview.removeEventListener('did-start-navigation', handleDidStartNavigation) webview.removeEventListener('did-redirect-navigation', handleDidRedirectNavigation) diff --git a/src/renderer/src/components/browser-pane/host-guest/browser-guest-owning-group.test.ts b/src/renderer/src/components/browser-pane/host-guest/browser-guest-owning-group.test.ts index 47a10206757b..fd7c88a063eb 100644 --- a/src/renderer/src/components/browser-pane/host-guest/browser-guest-owning-group.test.ts +++ b/src/renderer/src/components/browser-pane/host-guest/browser-guest-owning-group.test.ts @@ -3,7 +3,7 @@ import { focusOwningGroupForBrowserGuest } from './browser-guest-owning-group' const browserTab = { contentType: 'browser' as const, - entityId: 'page-1', + entityId: 'workspace-1', groupId: 'group-2' } @@ -12,7 +12,7 @@ describe('focusOwningGroupForBrowserGuest', () => { const focusGroup = vi.fn() focusOwningGroupForBrowserGuest({ worktreeId: 'wt-1', - browserTabId: 'page-1', + workspaceId: 'workspace-1', unifiedTabsByWorktree: { 'wt-1': [browserTab] }, focusGroup }) @@ -20,13 +20,13 @@ describe('focusOwningGroupForBrowserGuest', () => { expect(focusGroup).toHaveBeenCalledWith('wt-1', 'group-2') }) - it('does not move the focused split when the page is not in a group yet', () => { + it('does not match a page id against the workspace id stored on the tab', () => { const focusGroup = vi.fn() focusOwningGroupForBrowserGuest({ worktreeId: 'wt-1', - browserTabId: 'page-1', + workspaceId: 'page-1', unifiedTabsByWorktree: { - 'wt-1': [{ contentType: 'terminal', entityId: 'page-1', groupId: 'group-1' }] + 'wt-1': [{ contentType: 'browser', entityId: 'workspace-1', groupId: 'group-1' }] }, focusGroup }) @@ -37,7 +37,7 @@ describe('focusOwningGroupForBrowserGuest', () => { const focusGroup = vi.fn() focusOwningGroupForBrowserGuest({ worktreeId: 'wt-1', - browserTabId: 'page-1', + workspaceId: 'workspace-1', unifiedTabsByWorktree: { 'wt-2': [browserTab] }, focusGroup }) diff --git a/src/renderer/src/components/browser-pane/host-guest/browser-guest-owning-group.ts b/src/renderer/src/components/browser-pane/host-guest/browser-guest-owning-group.ts index 36933b7517df..7344fe1d609e 100644 --- a/src/renderer/src/components/browser-pane/host-guest/browser-guest-owning-group.ts +++ b/src/renderer/src/components/browser-pane/host-guest/browser-guest-owning-group.ts @@ -2,13 +2,16 @@ import type { Tab } from '../../../../../shared/tab-types' type BrowserGuestTab = Pick -/** The split that owns this browser page, or undefined while the tab is mid-move. */ +/** + * The split that owns this browser workspace, or undefined while the tab is mid-move. + * Unified browser tabs store the workspace id in `entityId`, not the live page id. + */ export function owningGroupIdForBrowserGuest( tabs: readonly BrowserGuestTab[] | undefined, - browserTabId: string + workspaceId: string ): string | undefined { for (const tab of tabs ?? []) { - if (tab.contentType === 'browser' && tab.entityId === browserTabId) { + if (tab.contentType === 'browser' && tab.entityId === workspaceId) { return tab.groupId } } @@ -21,13 +24,13 @@ export function owningGroupIdForBrowserGuest( */ export function focusOwningGroupForBrowserGuest(args: { worktreeId: string - browserTabId: string + workspaceId: string unifiedTabsByWorktree: Readonly> focusGroup: (worktreeId: string, groupId: string) => void }): void { const groupId = owningGroupIdForBrowserGuest( args.unifiedTabsByWorktree[args.worktreeId], - args.browserTabId + args.workspaceId ) if (!groupId) { return From 56180cc26359fed410602d98585367def076d76a Mon Sep 17 00:00:00 2001 From: Wooseong Kim Date: Thu, 1 Oct 2026 20:56:07 +0900 Subject: [PATCH 3/3] fix(browser): drop the casts from the guest-focus listener test Guest focus is registered through one helper, and cleanup removes that same function. The test uses a small listener target instead of casting a partial webview. --- ...ind-browser-page-webview-listeners.test.ts | 82 +++---------------- .../bind-browser-page-webview-listeners.ts | 51 ++++++++---- 2 files changed, 48 insertions(+), 85 deletions(-) diff --git a/src/renderer/src/components/browser-pane/host-guest/bind-browser-page-webview-listeners.test.ts b/src/renderer/src/components/browser-pane/host-guest/bind-browser-page-webview-listeners.test.ts index 6cd0ac3cb17f..afa35da7cc8a 100644 --- a/src/renderer/src/components/browser-pane/host-guest/bind-browser-page-webview-listeners.test.ts +++ b/src/renderer/src/components/browser-pane/host-guest/bind-browser-page-webview-listeners.test.ts @@ -1,5 +1,4 @@ import { describe, expect, it, vi } from 'vitest' -import type { AttachBrowserPageWebviewArgs } from './attach-browser-page-webview' const focusGroup = vi.hoisted(() => vi.fn()) const dismissAddressBarSuggestions = vi.hoisted(() => vi.fn()) @@ -15,93 +14,36 @@ vi.mock('@/store', () => ({ } })) -vi.mock('./browser-page-webview-guest-session', () => ({ - createBrowserPageWebviewGuestSession: () => ({ - guestRecovery: { - validateAfterResume: () => {}, - recoverRenderer: () => {}, - retryRecovery: () => {}, - dispose: () => {} - }, - handleDidAttach: () => {}, - handleDomReady: () => {}, - handleGuestDestroyed: () => {} - }) -})) - -vi.mock('./browser-page-webview-loading-handlers', () => ({ - createBrowserPageWebviewLoadingHandlers: () => ({ - handleDidStartLoading: () => {}, - handleDidStopLoading: () => {}, - handleFailLoad: () => {} - }) -})) - -vi.mock('./browser-page-webview-navigation-handlers', () => ({ - createBrowserPageWebviewNavigationHandlers: () => ({ - handleDidStartNavigation: () => {}, - handleDidRedirectNavigation: () => {}, - handleFullDidNavigate: () => {}, - handleDidNavigateInPage: () => {}, - handleTitleUpdate: () => {}, - handleFaviconUpdate: () => {}, - handleAnnotationViewportMessage: () => {} - }) -})) +type Listener = () => void -vi.mock('./browser-system-resume', () => ({ - subscribeBrowserSystemResume: () => () => {} -})) - -vi.mock('./browser-page-viewport', () => ({ - parkBrowserPageViewport: () => {} -})) - -vi.mock('./webview-registry', () => ({ - isBrowserPageRendererRecoveryPending: () => false, - moveFocusToRendererBeforeWebviewDetach: () => {} -})) - -type Listener = (event?: unknown) => void - -function fakeWebview(): Electron.WebviewTag & { +function fakeWebview(): { listeners: Map> + addEventListener(type: 'focus', listener: Listener): void + removeEventListener(type: 'focus', listener: Listener): void } { const listeners = new Map>() return { listeners, - addEventListener(type: string, listener: Listener) { + addEventListener(type: 'focus', listener: Listener) { const bucket = listeners.get(type) ?? new Set() bucket.add(listener) listeners.set(type, bucket) }, - removeEventListener(type: string, listener: Listener) { + removeEventListener(type: 'focus', listener: Listener) { listeners.get(type)?.delete(listener) } - } as Electron.WebviewTag & { listeners: Map> } + } } -describe('bindBrowserPageWebviewListeners guest focus', () => { +describe('bindBrowserGuestFocus', () => { it('focuses the workspace tab and removes that same callback on cleanup', async () => { - const { bindBrowserPageWebviewListeners } = - await import('./bind-browser-page-webview-listeners') + const { bindBrowserGuestFocus } = await import('./bind-browser-page-webview-listeners') const webview = fakeWebview() - const cleanup = bindBrowserPageWebviewListeners({ - container: { removeEventListener: () => {} } as HTMLDivElement, + const cleanup = bindBrowserGuestFocus({ webview, - needsInitialNavigation: false, - onContainerDragOver: () => {}, - onContainerDrop: () => {}, dismissAddressBarSuggestions, - args: { - browserTabId: 'page-1', - workspaceId: 'workspace-1', - worktreeId: 'wt-1', - isPaintableRef: { current: false }, - validateVisibleGuestRegistrationRef: { current: () => {} }, - retryGuestRecoveryRef: { current: () => {} }, - webviewRef: { current: null } - } as AttachBrowserPageWebviewArgs + worktreeId: 'wt-1', + workspaceId: 'workspace-1' }) const focusListeners = webview.listeners.get('focus') diff --git a/src/renderer/src/components/browser-pane/host-guest/bind-browser-page-webview-listeners.ts b/src/renderer/src/components/browser-pane/host-guest/bind-browser-page-webview-listeners.ts index d679425d92d9..e1e7329a2a52 100644 --- a/src/renderer/src/components/browser-pane/host-guest/bind-browser-page-webview-listeners.ts +++ b/src/renderer/src/components/browser-pane/host-guest/bind-browser-page-webview-listeners.ts @@ -13,6 +13,34 @@ import { createBrowserPageWebviewGuestSession } from './browser-page-webview-gue import { createBrowserPageWebviewLoadingHandlers } from './browser-page-webview-loading-handlers' import { createBrowserPageWebviewNavigationHandlers } from './browser-page-webview-navigation-handlers' +type BrowserGuestFocusTarget = { + addEventListener(type: 'focus', listener: () => void): void + removeEventListener(type: 'focus', listener: () => void): void +} + +/** Registers one focus callback and returns the cleanup that removes that same function. */ +export function bindBrowserGuestFocus(input: { + webview: BrowserGuestFocusTarget + dismissAddressBarSuggestions: () => void + worktreeId: string + workspaceId: string +}): () => void { + // Why: the guest does not bubble focus to the overlay, so the owning split + // stays stale and Ctrl+Tab targets the previous group (#22144). + const handleGuestFocus = (): void => { + input.dismissAddressBarSuggestions() + const state = useAppStore.getState() + focusOwningGroupForBrowserGuest({ + worktreeId: input.worktreeId, + workspaceId: input.workspaceId, + unifiedTabsByWorktree: state.unifiedTabsByWorktree, + focusGroup: state.focusGroup + }) + } + input.webview.addEventListener('focus', handleGuestFocus) + return () => input.webview.removeEventListener('focus', handleGuestFocus) +} + export function bindBrowserPageWebviewListeners({ container, webview, @@ -149,20 +177,13 @@ export function bindBrowserPageWebviewListeners({ webview.addEventListener('dom-ready', handleDomReady) webview.addEventListener('render-process-gone', guestRecovery.recoverRenderer) webview.addEventListener('destroyed', handleGuestDestroyed) - // Why: the guest does not bubble focus to the overlay, so the owning split - // stays stale and Ctrl+Tab targets the previous group (#22144). The same - // function is removed on cleanup; the webview outlives detach. - const handleGuestFocus = (): void => { - dismissAddressBarSuggestions() - const state = useAppStore.getState() - focusOwningGroupForBrowserGuest({ - worktreeId, - workspaceId, - unifiedTabsByWorktree: state.unifiedTabsByWorktree, - focusGroup: state.focusGroup - }) - } - webview.addEventListener('focus', handleGuestFocus) + // The same function is removed on cleanup; the webview outlives detach. + const removeGuestFocus = bindBrowserGuestFocus({ + webview, + dismissAddressBarSuggestions, + worktreeId, + workspaceId + }) webview.addEventListener('did-start-loading', handleDidStartLoading) webview.addEventListener('did-start-navigation', handleDidStartNavigation) webview.addEventListener('did-redirect-navigation', handleDidRedirectNavigation) @@ -200,7 +221,7 @@ export function bindBrowserPageWebviewListeners({ webview.removeEventListener('dom-ready', handleDomReady) webview.removeEventListener('render-process-gone', guestRecovery.recoverRenderer) webview.removeEventListener('destroyed', handleGuestDestroyed) - webview.removeEventListener('focus', handleGuestFocus) + removeGuestFocus() webview.removeEventListener('did-start-loading', handleDidStartLoading) webview.removeEventListener('did-start-navigation', handleDidStartNavigation) webview.removeEventListener('did-redirect-navigation', handleDidRedirectNavigation)