Closed general

View toggle from a foreground window must return foreground: create-then-swap relaunch (traced root cause: close-first drops the foreground lock)

John Lauer · 3mo ago ·closed by John Lauer

John (2026-08-10): toggling the wiki view from a FOREGROUND window must bring the replacement window back to the FOREGROUND; AI-initiated opens stay background (that default now behaves well). Current behavior: the replacement arrives in the background despite foreground:true + osRaise + a delayed second raise (2.0.57).

ROOT CAUSE (traced, not guessed): the relaunch closes the old window FIRST. The moment it dies, Windows moves foreground to the next app (usually the editor), so by raise time our process no longer owns foreground and SetForegroundWindow is denied by the foreground lock. Retries lose the same way.

FIX: CREATE-THEN-SWAP. Launch the replacement window under a temp session id, restore all tabs, raise it WHILE the old window still holds foreground (same-app focus handoff is permitted), then close the old window and rename the temp session to the original id (preserving owner, hwnd claims, jump list, AUMID). Only when the ORIGINAL window was foreground and the caller is a USER_CALLERS identity; AI-driven toggles keep background semantics. Also removes the zero-window dead-air gap during the switch.

Touches: pup_wiki_set_view relaunch block (v1.9.29 carry-tabs), session map rename, persisted-claims handoff, AUMID/jumplist restamp ordering. Gate with the menu ralph plus a new foreground assertion (desktop_get_foreground == new hwnd immediately after swap).

1 Reply

John Lauer · 3mo ago

Shipped in pup 2.0.130, exactly per the traced root cause: CREATE-THEN-SWAP.

When the toggled window was FOREGROUND at click time (checked against osGetForegroundWindow + the session hwnd BEFORE teardown) and the caller is a USER_CALLERS identity (taskbar jump list / toolbar popup), the relaunch now: launches the replacement under a temp id, restores every tab, raises it WHILE the old window still holds the foreground lock (same-app focus handoff is permitted), THEN closes the old window and renames the temp session to the original id, carrying owner, hwnd claim, session file, jump list, and AUMID (the brand sweep restamps titles/badges off the renamed map entry). One more raise after the old window dies, which we now own the lock for. The zero-window dead-air gap is gone too, the replacement exists before the original closes.

AI-driven toggles and background-window toggles keep the legacy close-first path and background semantics unchanged. Any swap failure logs, cleans up the temp session, and falls back to the legacy relaunch, so the toggle can never end with no window. Response carries swap:true when the new path ran.

John Lauer closed this · 3mo ago

Log in to reply.