Skip to content

Native Windows port: Direct2D/DirectWrite rendering over ConPTY#28

Open
ucsandman wants to merge 2 commits into
dedene:mainfrom
ucsandman:windows-port
Open

Native Windows port: Direct2D/DirectWrite rendering over ConPTY#28
ucsandman wants to merge 2 commits into
dedene:mainfrom
ucsandman:windows-port

Conversation

@ucsandman

Copy link
Copy Markdown

Summary

This PR adds a complete native Windows port of Zentty as a self-contained Rust workspace under rust/ — no Electron, no web views. It brings the core Zentty experience to Windows: worklanes, panes with splits, a sidebar with live agent-status pills, the command palette, global search, and theming.

Nothing outside rust/ is touched except: a "Windows" section in the README, a short "Windows port" note in AGENTS.md, and two .gitignore entries (rust/target/, rust/dist/). The macOS app is unaffected.

Architecture

Four crates, with the platform-agnostic logic kept separate so it stays reusable:

Crate Role
zentty-core Worklanes, panes, layout, command palette, themes, task runner, agent-IPC protocol, session restore
zentty-terminal Screen model, selection, search, clipboard, clean-copy pipeline
zentty-pty ConPTY pseudo-console sessions, output streaming, shell-exit detection
zentty-win Win32 shell: DXGI flip-model swapchain + ID2D1DeviceContext rendering, DirectWrite text, all UI chrome

Notable Windows-specific engineering:

  • Rendering: flip-model swapchain (plain ID2D1HwndRenderTarget never composites under DWM), grayscale text AA, per-monitor DPI scaling of fonts and chrome, device-loss recovery (D2DERR_RECREATE_TARGET, device-removed, resize failures) with HARDWARE→WARP fallback.
  • Terminal: measured DirectWrite cell metrics drive PTY sizing and pixel-accurate selection hit-testing; cursor blinks at the system caret rate (respects reduced-motion); window title follows OSC titles; bell flashes the taskbar.
  • Robustness: a pane closes itself when its shell exits (last pane closes the window); PTY spawn failures surface a MessageBox at startup and degrade gracefully in-session; ellipsis trimming on all chrome text; WCAG AA contrast on status pills.
  • Packaging: multi-resolution icon embedded via winresource, GUI subsystem with a MessageBox fatal-error fallback, rust/scripts/package-windows.ps1 produces a portable zip with per-user install/uninstall scripts (Start-menu shortcut, no admin); the cargo-wix MSI route is documented in the README.

Testing

From rust/ on Windows (Rust MSVC toolchain + Windows 10/11 SDK):

cargo build --release --workspace
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace

All green at time of submission: 549 tests passing, clippy clean with -D warnings. The suite covers the logic crates plus the Win32 shell (input encoding, layout/metrics, agent-IPC named-pipe transport, ConPTY exit detection, desktop session behavior).

Run it: .\target\release\zentty-win-desktop.exeCtrl+Shift+P opens the palette, Ctrl+D splits. Full keyboard map is in the README's Windows section.

Known limitations

  • ConPTY repaints the viewport differentially and never feeds scrollback, so the scrollback model is implemented and tested but stays empty in live sessions (documented in code).
  • The zip package is unsigned; MSI/signing steps are documented but require the WiX toolset and a certificate.

🤖 Generated with Claude Code

ucsandman and others added 2 commits June 9, 2026 16:30
Adds a 4-crate Rust workspace under rust/ implementing Zentty as a native
Windows app (no Electron, no web views):

- zentty-core: platform-agnostic logic (worklanes, panes, layout, command
  palette, themes, task runner, agent IPC protocol, session restore)
- zentty-terminal: screen model, selection, search, clipboard, clean-copy
- zentty-pty: ConPTY pseudo-console sessions with exit detection
- zentty-win: Win32 shell — DXGI flip-model swapchain + ID2D1DeviceContext
  rendering, DirectWrite text with grayscale AA and ellipsis-trimmed chrome,
  per-monitor DPI scaling, dark immersive title bar, sidebar with agent
  status pills, pane splits with focus ring, command palette and global
  search overlays, built-in themes (default dark / gruvbox / dracula),
  full keyboard mapping, window-title + bell integration, device-loss
  recovery with WARP fallback, shell-exit pane auto-close

Packaging: multi-resolution icon embedded via winresource, GUI subsystem
with MessageBox fatal-error fallback, portable zip + per-user
install/uninstall scripts (Start-menu shortcut, no admin), documented
cargo-wix MSI route. README gains a Windows section with build/run/test/
install steps and the keyboard map; AGENTS.md documents the rust/ gates.

Gates: cargo build --release, clippy -D warnings, 549 tests — all green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Clicking a non-focused pane or a sidebar row (worklane header or pane
row) now moves focus there, Windows Terminal-style: the focusing click
is swallowed and never starts a selection. Pane and sidebar-row ids are
threaded into the render model; the renderer records per-pane and
per-sidebar-row hit rects at draw time so hit-testing matches the
geometry actually drawn at any DPI.

Also adds opt-in WM_KEYDOWN/WM_CHAR input tracing via
ZENTTY_DEBUG_INPUT_LOG=<file> (logs vk + modifier state + effect
discriminant only, never key payloads) to diagnose shortcut issues that
only reproduce on real keyboards.

+9 tests (hit-rect lookup, focus-by-id session paths).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

1 participant