Browse Source

fix: handle closing `webContents` in `BrowserView`s (#37451)

* fix: handle closing webContents in BrowserViews

Co-authored-by: Shelley Vohr <[email protected]>

* test: add window.close() test

Co-authored-by: Shelley Vohr <[email protected]>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <[email protected]>
trop[bot] 2 years ago
parent
commit
c3dfd55224

+ 3 - 0
shell/browser/api/electron_api_browser_view.cc

@@ -126,6 +126,9 @@ BrowserView::~BrowserView() {
 }
 
 void BrowserView::WebContentsDestroyed() {
+  if (owner_window())
+    owner_window()->window()->RemoveDraggableRegionProvider(this);
+
   api_web_contents_ = nullptr;
   web_contents_.Reset();
   Unpin();

+ 6 - 2
shell/browser/api/electron_api_browser_window.cc

@@ -112,6 +112,7 @@ BrowserWindow::~BrowserWindow() {
     api_web_contents_->RemoveObserver(this);
     // Destroy the WebContents.
     OnCloseContents();
+    api_web_contents_->Destroy();
   }
 }
 
@@ -139,7 +140,6 @@ void BrowserWindow::WebContentsDestroyed() {
 
 void BrowserWindow::OnCloseContents() {
   BaseWindow::ResetBrowserViews();
-  api_web_contents_->Destroy();
 }
 
 void BrowserWindow::OnRendererResponsive(content::RenderProcessHost*) {
@@ -198,7 +198,11 @@ void BrowserWindow::OnCloseButtonClicked(bool* prevent_default) {
 
   // Trigger beforeunload events for associated BrowserViews.
   for (NativeBrowserView* view : window_->browser_views()) {
-    auto* vwc = view->GetInspectableWebContents()->GetWebContents();
+    auto* iwc = view->GetInspectableWebContents();
+    if (!iwc)
+      continue;
+
+    auto* vwc = iwc->GetWebContents();
     auto* api_web_contents = api::WebContents::From(vwc);
 
     // Required to make beforeunload handler work.

+ 1 - 3
shell/browser/api/electron_api_web_contents.cc

@@ -1224,9 +1224,7 @@ void WebContents::CloseContents(content::WebContents* source) {
   for (ExtendedWebContentsObserver& observer : observers_)
     observer.OnCloseContents();
 
-  // If there are observers, OnCloseContents will call Destroy()
-  if (observers_.empty())
-    Destroy();
+  Destroy();
 }
 
 void WebContents::ActivateContents(content::WebContents* source) {

+ 18 - 0
spec/api-browser-view-spec.ts

@@ -345,6 +345,24 @@ describe('BrowserView module', () => {
       const [code] = await emittedOnce(rc.process, 'exit');
       expect(code).to.equal(0);
     });
+
+    it('emits the destroyed event when webContents.close() is called', async () => {
+      view = new BrowserView();
+      w.setBrowserView(view);
+      await view.webContents.loadFile(path.join(fixtures, 'pages', 'a.html'));
+
+      view.webContents.close();
+      await emittedOnce(view.webContents, 'destroyed');
+    });
+
+    it('emits the destroyed event when window.close() is called', async () => {
+      view = new BrowserView();
+      w.setBrowserView(view);
+      await view.webContents.loadFile(path.join(fixtures, 'pages', 'a.html'));
+
+      view.webContents.executeJavaScript('window.close()');
+      await emittedOnce(view.webContents, 'destroyed');
+    });
   });
 
   describe('window.open()', () => {