fix: potentially closed webContents in BrowserView (#42633)

This commit is contained in:
Shelley Vohr 2024-07-08 12:13:53 +02:00 committed by GitHub
parent 2f4a46f47a
commit cb2e7f130b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 107 additions and 21 deletions

View file

@ -4,6 +4,9 @@ const v8Util = process._linkedBinding('electron_common_v8_util');
export default class BrowserView {
#webContentsView: WebContentsView;
#ownerWindow: BrowserWindow | null = null;
#destroyListener: ((e: any) => void) | null = null;
// AutoResize state
#resizeListener: ((...args: any[]) => void) | null = null;
@ -17,6 +20,9 @@ export default class BrowserView {
}
webPreferences.type = 'browserView';
this.#webContentsView = new WebContentsView({ webPreferences });
this.#destroyListener = this.#onDestroy.bind(this);
this.#webContentsView.webContents.once('destroyed', this.#destroyListener);
}
get webContents () {
@ -55,23 +61,39 @@ export default class BrowserView {
// Internal methods
get ownerWindow (): BrowserWindow | null {
return !this.webContents.isDestroyed() ? this.webContents.getOwnerBrowserWindow() : null;
return this.#ownerWindow;
}
// We can't rely solely on the webContents' owner window because
// a webContents can be closed by the user while the BrowserView
// remains alive and attached to a BrowserWindow.
set ownerWindow (w: BrowserWindow | null) {
if (this.webContents.isDestroyed()) return;
const oldWindow = this.webContents.getOwnerBrowserWindow();
if (oldWindow && this.#resizeListener) {
oldWindow.off('resize', this.#resizeListener);
if (this.#ownerWindow && this.#resizeListener) {
this.#ownerWindow.off('resize', this.#resizeListener);
this.#resizeListener = null;
}
this.webContents._setOwnerWindow(w);
if (this.webContents && !this.webContents.isDestroyed()) {
this.webContents._setOwnerWindow(w);
}
this.#ownerWindow = w;
if (w) {
this.#lastWindowSize = w.getBounds();
w.on('resize', this.#resizeListener = this.#autoResize.bind(this));
w.on('closed', () => {
this.#ownerWindow = null;
this.#destroyListener = null;
});
}
}
#onDestroy () {
// Ensure that if #webContentsView's webContents is destroyed,
// the WebContentsView is removed from the view hierarchy.
this.#ownerWindow?.contentView.removeChildView(this.webContentsView);
}
#autoHorizontalProportion: {width: number, left: number} | null = null;
#autoVerticalProportion: {height: number, top: number} | null = null;
#autoResize () {