From 75a08f128cf4a6ac68e7a7e433cdb1620084d856 Mon Sep 17 00:00:00 2001 From: yhh Date: Mon, 12 Oct 2026 01:57:50 -0700 Subject: [PATCH] fix(electron): attach a parked browser page again when it is shown Switching away from a built-in browser tab and back drew a white page until the window was resized: a view parked offscreen and moved back with setBounds alone keeps a widget that does not repaint. The shell already knows that attaching a view again wakes its widget (it does so on minimize and restore); a page that was parked now gets the same when it is shown. --- desktop/electron/src/browserviews.js | 4 +++ desktop/electron/test/unit.mjs | 40 ++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/desktop/electron/src/browserviews.js b/desktop/electron/src/browserviews.js index b1d9e21a75..481a0b85ab 100644 --- a/desktop/electron/src/browserviews.js +++ b/desktop/electron/src/browserviews.js @@ -152,6 +152,10 @@ class BrowserViews { if (id !== targetId) this.putAway(other.view, other); } this.shown = targetId; + // A page that was parked comes back as a view that is attached but whose + // widget never repaints until the window's geometry changes; attaching it + // again is what wakes it, the same as after a minimize. + if (!entry.at) this.win.contentView.removeChildView(entry.view); this.win.contentView.addChildView(entry.view); entry.view.setBounds(at); entry.at = at; diff --git a/desktop/electron/test/unit.mjs b/desktop/electron/test/unit.mjs index 468bd89f1f..834c326140 100644 --- a/desktop/electron/test/unit.mjs +++ b/desktop/electron/test/unit.mjs @@ -2059,3 +2059,43 @@ test("revealLogs opens only the folder the shell itself names, and reports why i assert.deepEqual(await revealLogs(refusing, "/user/logs"), { error: "no application is associated with this folder" }); assert.deepEqual(await revealLogs(shell, ""), { error: "the logs folder is unknown" }); }); + +// The built-in browser drew a white page after switching away from a tab and +// back until the window was resized: a parked view moved onscreen with +// setBounds alone does not repaint. Bringing it back attaches it again. +test("a parked page is attached again when it is shown, and a page already on screen is left alone", () => { + const Module = require("node:module"); + const load = Module._load; + Module._load = function (request, ...rest) { + if (request === "electron") return { WebContentsView: class {}, session: { fromPartition: () => ({}) } }; + return load.call(this, request, ...rest); + }; + let BrowserViews; + try { + ({ BrowserViews } = require("../src/browserviews.js")); + } finally { + Module._load = load; + } + const calls = []; + const win = { + on() {}, + isDestroyed: () => false, + getContentBounds: () => ({ width: 1200, height: 800 }), + contentView: { addChildView: () => calls.push("add"), removeChildView: () => calls.push("remove") }, + }; + const views = new BrowserViews({ win, kernelOrigin: "http://127.0.0.1:1" }); + const view = { setBounds: (b) => calls.push("bounds " + b.x), webContents: { isDestroyed: () => false } }; + views.entries.set("t1", { view, at: null }); + const rect = { x: 10, y: 20, width: 600, height: 400 }; + + views.show("t1", rect); + assert.deepEqual(calls, ["remove", "add", "bounds 10"]); + calls.length = 0; + views.show("t1", rect); + assert.deepEqual(calls, [], "the same rectangle on a page already shown does no work"); + views.hide(); + calls.length = 0; + views.show("t1", rect); + assert.deepEqual(calls, ["remove", "add", "bounds 10"], "a page put away and shown again is attached again"); +}); +