[eric] browser: guard capture-page on churning webviews to dodge the V8 crash

This commit is contained in:
ciregenz
2026-06-04 11:26:50 -07:00
parent 6b737f2d8e
commit ad75228abe
2 changed files with 31 additions and 2 deletions
+14 -2
View File
@@ -2206,8 +2206,20 @@ ipcMain.handle('install-update', async () => {
});
ipcMain.handle('capture-page', async (event, rect) => {
const image = await event.sender.capturePage(rect || undefined);
return image.toDataURL();
// Capturing a webContents whose GPU surface is mid-recycle (a webview navigating
// a heavy SPA) can crash the renderer (SharedImage 'non-existent mailbox' ->
// V8 ToLocalChecked). The caller now waits for webviews to settle, but guard
// here too: skip a gone/crashed/loading sender and never encode an empty image,
// returning null so the dashboard keeps its last good preview instead of dying.
try {
const wc = event.sender;
if (!wc || wc.isDestroyed() || wc.isCrashed() || wc.isLoading()) return null;
const image = await wc.capturePage(rect || undefined);
if (!image || image.isEmpty()) return null;
return image.toDataURL();
} catch {
return null;
}
});
ipcMain.handle('open-external', (_event, url) => {
+17
View File
@@ -23,6 +23,7 @@ export interface BrowserWebview extends HTMLElement {
canGoForward: () => boolean;
getURL: () => string;
getTitle: () => string;
isLoading: () => boolean;
capturePage: (rect?: { x: number; y: number; width: number; height: number }) => Promise<ElectronNativeImage>;
executeJavaScript: (code: string) => Promise<any>;
sendInputEvent: (event: any) => void;
@@ -64,3 +65,19 @@ export function findBrowserByWebContentsId(wcId: number): string | undefined {
}
return undefined;
}
// True if ANY registered webview is mid-navigation. Capturing the dashboard
// (which composites live webview pixels) while a webview's GPU surface is being
// recycled crashes the renderer (SharedImage 'non-existent mailbox' -> V8
// ToLocalChecked), so the thumbnail capture must wait until they've settled.
export function anyWebviewLoading(): boolean {
for (const wv of registry.values()) {
try {
if (typeof wv.isLoading === 'function' && wv.isLoading()) return true;
} catch {
// a torn-down webview can throw; treat as "not safe to capture"
return true;
}
}
return false;
}