Skip to content

Parent ConPTY console windows to the Dormouse window on Windows - #1394

Merged
nedtwigg merged 2 commits into
mainfrom
conpty-reparenting
Oct 27, 2026
Merged

nedtwigg merged 2 commits into
mainfrom
conpty-reparenting

Conversation

@nedtwigg

@nedtwigg nedtwigg commented Oct 27, 2026 •

Copy link
Copy Markdown
Member

On Windows, a dialog that a terminal program opens owned by its console window's root owner (MSAL/WAM sign-in, e.g. Connect-AzAccount) had no tie to Dormouse: ConPTY's hidden console window has no owner, so the first click into Dormouse buried the dialog behind it. This uses node-pty's setParentWindow (microsoft/node-pty#995, already in our pinned 1.2.0-beta.18) so the window holding a PTY owns its console window — the same mechanism VS Code's integrated terminal turned on by default in microsoft/vscode#342784.

What changes

  • Spawn: Rust reads the spawning window's HWND and sends its native-order bytes (hex) beside the webview's options in pty:spawn; the sidecar calls setParentWindow in the same tick, before the shell launches. A webview cannot supply a handle, it is never persisted, and a refusal is logged without blocking the terminal.
  • Transfers: a new pty:parentWindow line re-parents at adopt_done (to the target) and at every hand-back (to the source) — never at a transfer's start, when a tear-out's window does not exist yet.
  • Recovery (Re-enable the parent window when a modal dialog's process dies microsoft/node-pty#996): a modal dialog disables its owner, and one whose process dies leaves it disabled for good. A Rust thread re-enables a window that stays disabled, unminimized, with no visible window in its owner chain over two ticks. Unlike Hosted page: plans, pricing, and the founding ladder #996's proposal (shell exit only), this also covers a child dialog process dying while the shell survives.
  • macOS/Linux: unchanged. VS Code: not feasible with supported APIs (only the proposed, Insiders-only window.nativeHandle), recorded under ## Future in docs/specs/standalone.md.

Spec: docs/specs/standalone.md → "Console window parenting", evidence in its rationale.

Tested in a real Tauri dev build (Windows 11)

Using standalone/scripts/conpty-dialog-probe.ps1 (a MessageBoxW owned by GetAncestor(GetConsoleWindow(), GA_ROOTOWNER)):

Scenario Result
Before this change Dialog owned by the console window; clicking Dormouse buries it
Initial spawn, split pane Owned by its window; stays above it
Workspace torn out, then moved back Owned by the new window, then by main; only the owner is disabled
Normal dismissal Re-enabled; keyboard back in the xterm
Pane killed (dor kill) with dialog up Dialog gone; re-enabled within 0.2 s
Only the dialog's process killed, shell alive Re-enabled about 1 s later; shell usable
Window minimized with dialog up Stays disabled; dialog returns on restore

Hand-back is pinned by a source-scan test rather than driven live. Known tradeoffs (as in VS Code): the modal locks its whole window while open, and after a dead dialog Windows hands foreground to another app, so the user clicks back in.

Before merging

  • Real WAM sign-in on Windows: Connect-AzAccount (or az login) in a dev build opens its picker above Dormouse, owned by the pane's window.

🤖 Generated with Claude Code

Verified: Connect-AzAccount in a dev build opened its account picker above Dormouse and signed in.

A dialog a console program owns by its console window's root owner (MSAL
sign-in, Connect-AzAccount) had no tie to Dormouse and fell behind it on the
first click. Rust now hands each PTY's window HWND to node-pty's
setParentWindow at spawn, and again where a Workspace transfer settles
(adoption or hand-back). A recovery thread re-enables a window left disabled
by a dialog whose process died (microsoft/node-pty#996), shell or child.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Deploying mouseterm with  Cloudflare Pages  Cloudflare Pages

Latest commit: 2219c8a
Status: ✅  Deploy successful!
Preview URL: https://9143ddcc.mouseterm.pages.dev
Branch Preview URL: https://conpty-reparenting.mouseterm.pages.dev

View logs

@dormouse-bot dormouse-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No findings on the code. I'm holding the approval only because the description's "Before merging" item is still unchecked: the real WAM sign-in test (Connect-AzAccount / az login opening its picker above Dormouse, owned by the pane's window). That test also covers something the MessageBoxW probe can't: whether WAM's picker counts as an owned visible window to the recovery walk, so the 1 s re-enable never fires while the picker is up.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@nedtwigg
nedtwigg merged commit 014cb37 into main Oct 27, 2026
17 checks passed
@nedtwigg
nedtwigg deleted the conpty-reparenting branch October 27, 2026 17:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants