From 41020b1b65080e7d879bf075f73164fb33d5d14f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Sun, 23 Aug 2026 20:21:32 +0000 Subject: [PATCH] build the wine prefix after the display exists, not before MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A cold install could never work. `winetricks -q vb6run` runs Microsoft's redistributable, and that installer creates a window even when told to be quiet — so with no DISPLAY wine cannot load a graphics driver, the installer dies, and winetricks reports `returned status 43`. That message names neither wine nor a display, and reads like a corrupt download. ensurePrefix ran before Xvfb started, because building a prefix looks like preparation rather than something that needs a screen. It never showed up in testing here: this machine's prefix was seeded from the pre-extraction one, so the build path only ever ran against a prefix that was already complete. The first genuine cold install — alpha — failed on the first Start. Diagnosed from `err:winediag:nodrv_CreateWindow` in the wine output, which is the only line that says what is actually wrong. Order is now display, prefix, game. ensurePrefix takes the display explicitly rather than reading the ambient environment, so it cannot silently run without one again, and a failed build now tears the display down instead of leaving an Xvfb behind. Verified by moving this machine's prefix aside and starting cold: prefix built from nothing, msvbvm60.dll installed, session up with the window at 152x214, Z: confined, socket mode 700, and RFB 003.008 through the platform relay. Co-Authored-By: Claude Opus 5 Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043 --- sidecar/prefix.ts | 18 +++++++++++++++--- sidecar/session.ts | 15 +++++++++------ 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/sidecar/prefix.ts b/sidecar/prefix.ts index 051c528..d96feea 100644 --- a/sidecar/prefix.ts +++ b/sidecar/prefix.ts @@ -50,7 +50,19 @@ export type PrefixResult = { ok: boolean; detail: string }; * `winetricks -q vb6run` fetches Microsoft's own `VB6.0-KB290887-X86.exe` and verifies its checksum before * unpacking, which is why this does not carry a redistributable of its own. */ -export async function ensurePrefix(log: (line: string) => void): Promise { +export async function ensurePrefix(log: (line: string) => void, display: string): Promise { + // THE DISPLAY IS NOT OPTIONAL, and this cost a cold install to learn. + // + // `winetricks -q vb6run` runs Microsoft's redistributable, and that installer creates a window even + // when told to be quiet. With no `DISPLAY` wine cannot load a graphics driver, the installer dies, and + // winetricks reports `returned status 43` — which names neither wine nor a display and reads like a + // corrupt download. + // + // This used to run BEFORE Xvfb started, because building a prefix looks like preparation rather than + // something that needs a screen. It never showed up here: this machine's prefix was seeded from an + // older one, so the build path only ever ran on a prefix that was already complete. The first genuine + // cold install — alpha — failed immediately. + const env = { ...WINE_ENV, DISPLAY: display }; // Before the early return as well: an existing prefix may predate this, or have had `z:` restored by a // wine upgrade. It is a few `unlink` calls, so it is cheaper to re-assert than to detect. if (prefixReady()) { @@ -69,14 +81,14 @@ export async function ensurePrefix(log: (line: string) => void): Promise void): Promise { return status(); } - const built = await ensurePrefix(log); - if (!built.ok) { - lastError = built.detail; - return status(); - } - // ── the display ── if (!alive(xvfb)) { display = pickDisplay(); @@ -156,6 +150,15 @@ async function startInner(log: (line: string) => void): Promise { } } + // The prefix is built HERE, after the display exists and before the game needs it. Not earlier: the VB6 + // installer opens a window, so a prefix built without a display fails in a way that names neither. + const built = await ensurePrefix(log, display!); + if (!built.ok) { + lastError = built.detail; + await stop(); + return status(); + } + const env = { ...WINE_ENV, DISPLAY: display! }; // ── the game ──