Skip to content

Commit 3286b5f

Browse files
authored
fix: handle BrowserView reparenting (electron#27000)
1 parent 6307b52 commit 3286b5f

File tree

2 files changed

+36
-2
lines changed

2 files changed

+36
-2
lines changed

shell/browser/api/electron_api_base_window.cc

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,14 @@ void BaseWindow::AddBrowserView(v8::Local<v8::Value> value) {
755755
auto get_that_view = browser_views_.find(browser_view->ID());
756756
if (get_that_view == browser_views_.end()) {
757757
if (browser_view->web_contents()) {
758+
// If we're reparenting a BrowserView, ensure that it's detached from
759+
// its previous owner window.
760+
auto* owner_window = browser_view->web_contents()->owner_window();
761+
if (owner_window && owner_window != window_.get()) {
762+
owner_window->RemoveBrowserView(browser_view->view());
763+
browser_view->web_contents()->SetOwnerWindow(nullptr);
764+
}
765+
758766
window_->AddBrowserView(browser_view->view());
759767
browser_view->web_contents()->SetOwnerWindow(window_.get());
760768
}
@@ -1076,9 +1084,14 @@ void BaseWindow::ResetBrowserViews() {
10761084
v8::Local<v8::Value>::New(isolate(), item.second),
10771085
&browser_view) &&
10781086
!browser_view.IsEmpty()) {
1087+
// There's a chance that the BrowserView may have been reparented - only
1088+
// reset if the owner window is *this* window.
10791089
if (browser_view->web_contents()) {
1080-
window_->RemoveBrowserView(browser_view->view());
1081-
browser_view->web_contents()->SetOwnerWindow(nullptr);
1090+
auto* owner_window = browser_view->web_contents()->owner_window();
1091+
if (owner_window == window_.get()) {
1092+
browser_view->web_contents()->SetOwnerWindow(nullptr);
1093+
owner_window->RemoveBrowserView(browser_view->view());
1094+
}
10821095
}
10831096
}
10841097

spec-main/api-browser-view-spec.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,27 @@ describe('BrowserView module', () => {
158158
w.addBrowserView(view1);
159159
}).to.not.throw();
160160
});
161+
162+
it('can handle BrowserView reparenting', async () => {
163+
view = new BrowserView();
164+
165+
w.addBrowserView(view);
166+
view.webContents.loadURL('about:blank');
167+
await emittedOnce(view.webContents, 'did-finish-load');
168+
169+
const w2 = new BrowserWindow({ show: false });
170+
w2.addBrowserView(view);
171+
172+
w.close();
173+
174+
view.webContents.loadURL(`file://${fixtures}/pages/blank.html`);
175+
await emittedOnce(view.webContents, 'did-finish-load');
176+
177+
// Clean up - the afterEach hook assumes the webContents on w is still alive.
178+
w = new BrowserWindow({ show: false });
179+
w2.close();
180+
w2.destroy();
181+
});
161182
});
162183

163184
describe('BrowserWindow.removeBrowserView()', () => {

0 commit comments

Comments
 (0)