Theseus: the tab that was open at close loads on launch

Restore left every tab dormant, the active one included, so a fresh launch
showed the right tab highlighted over an empty page until it was clicked,
which reads as a broken restore. The active tab now loads as soon as the
toolbar has painted; every other restored tab stays dormant until it is
activated, so launch still costs one page renderer.
This commit is contained in:
Local Dev 2026-10-04 03:03:17 +02:00
parent 5e67f81a94
commit 6fd44db1d6

30
main.js
View file

@ -1353,18 +1353,13 @@ function loadSession() {
return { tabs: urls.map((url) => ({ url, title: "", favicon: null })), active }; return { tabs: urls.map((url) => ({ url, title: "", favicon: null })), active };
} catch { return empty; } } catch { return empty; }
} }
// Session restore, FULLY LAZY: nothing navigates at launch. Every restored // Session restore, lazy except for the page on screen: only the tab that was
// tab — including the one that was active at close — comes up as a dormant // active at close loads at launch. Every other restored tab comes up as a
// WebContentsView in the strip, painted from the saved title + favicon, and // dormant WebContentsView in the strip, painted from the saved title +
// only triggers a page load when the user asks for it specifically (clicks // favicon, and loads only when the user activates it (clicks the chip, hits
// the chip, hits reload, types in the URL bar). This drops the whole startup // reload, types in the URL bar). Launch therefore costs one page renderer
// renderer load to zero page renderers (chrome.html + the overlays + the // whether the session has 2 or 50 tabs, and a saved heavy page in the
// strip only), so launch is near-flat whether the session has 2 or 50 tabs // background doesn't come back as a 500 MB renderer nobody asked to see.
// and the RAM-at-launch footprint is just the chrome plus the strip —
// a saved heavy page doesn't come back as a 500 MB renderer the user
// didn't even ask to see. The previously active tab stays highlighted in
// the strip so the user can one-click it back; its content area sits with
// the tab's solid background until that happens.
function restoreTabs() { function restoreTabs() {
const saved = settings.restoreSession ? loadSession() : { tabs: [], active: 0 }; const saved = settings.restoreSession ? loadSession() : { tabs: [], active: 0 };
if (!saved.tabs.length) { createTab(); return; } if (!saved.tabs.length) { createTab(); return; }
@ -1372,16 +1367,19 @@ function restoreTabs() {
try { createTab(null, { background: true, pending: saved.tabs[i] }); } try { createTab(null, { background: true, pending: saved.tabs[i] }); }
catch (e) { console.warn("session restore: tab failed:", e?.message); } catch (e) { console.warn("session restore: tab failed:", e?.message); }
} }
// Pick the saved active slot as the chip the strip highlights at launch. // The tab that was active at close loads now — it is the page the user
// A plain setActive() would materialise it (defeating the point of fully- // sees, and leaving it blank until clicked read as a broken restore. Every
// lazy restore), so apply activeId + visibility by hand — the user // other tab stays dormant until it is activated. activeId + visibility are
// clicking that same chip is what triggers the first navigation. // applied by hand rather than through setActive(), which would also run
// the switch-time side effects (sidebar restore, nav push) for a tab the
// user did not switch to.
const idx = Math.min(Math.max(0, saved.active | 0), tabs.length - 1); const idx = Math.min(Math.max(0, saved.active | 0), tabs.length - 1);
const target = tabs[idx]; const target = tabs[idx];
if (target) { if (target) {
activeId = target.id; activeId = target.id;
try { target.view.setVisible(true); } catch {} try { target.view.setVisible(true); } catch {}
for (const t of tabs) if (t.id !== activeId) { try { t.view.setVisible(false); } catch {} } for (const t of tabs) if (t.id !== activeId) { try { t.view.setVisible(false); } catch {} }
if (target.pending) materializePending(target);
} }
emitTabs(); emitTabs();
} }