Files
ghostty-rs/docs/rewrite/notes/verification-V3.md
T
ddidderr 3fd4ea6ae9 test(apprt-gtk): replay mouse input and verify real-world TUIs
The GTK mouse handlers now delegate to *_impl methods taking button and
modifier state, so the real controllers and the debug input replay share
one code path. The replay hook gained mouse-move/press/release, click,
drag, scroll, resize, clipboard-set/dump, windows-dump and
window-screenshot steps (replayed presses bypass the focus-transfer
first-click rule since the replay window isn't compositor-focused).

Verified in the real app on Wayland (docs/rewrite/notes/verification-
V3.md): nvim (colors, status line, cursor shapes, alt-screen restore),
htop (rendering, mouse-click column sorting), less (alternate scroll),
tmux (splits, status bar), drag/double/triple-click selection into
PRIMARY, clipboard copy, context menu, scrollback and reflow on resize,
CJK/emoji/ZWJ/nerd-font widths, kitty graphics images and the unsafe
paste confirmation dialog. No product bugs were found.

Test Plan:
- cargo test -p ghostty-apprt-gtk (incl. parse_mouse_steps)
2026-10-12 05:02:48 +02:00

3.6 KiB

Verification V3 (real GTK app, real programs, mouse input)

Replay hook extensions (crates/ghostty-apprt-gtk/src/debug_input.rs, class/surface.rs)

New steps: mouse-move x y [mods], mouse-press|mouse-release|click <btn> [mods], drag x1 y1 x2 y2 [mods], scroll dx dy, resize w h, clipboard-set, clipboard-dump (also logs context-menu visibility), windows-dump (toplevels + widget tree, shows AdwDialogs), window-screenshot (GTK render of the whole window incl. headerbar/dialogs; the GL area content may differ from screenshot). The GTK handlers mouse_down/mouse_up/mouse_motion/scroll_vertical were split into *_impl methods (taking button/modifier state instead of a GdkEvent) so the replay runs the exact same code as the gesture controllers. The replay passes assume_focus=true for presses: the replayed window is not compositor-focused, and the "first click only transfers focus" suppression would otherwise eat every click. Parser unit test parse_mouse_steps added.

Scenarios (GTK, Wayland, release profile)

Scenario Result
nvim (-e nvim file.rs): syntax colors, ligatures, status line, :q PASS. Insert mode bar cursor OK.
nvim from shell, :q: alternate screen restore PASS (prompt + prior output intact).
htop: meters, colors, box/bars, F10 PASS. Mouse click on MEM% header sorts (mouse reporting; clicking twice toggles asc/desc). F10 quits.
less on 300 lines: wheel in alt screen, q PASS. 5 wheel ticks -> 15 lines (3 arrow keys per tick, DECSET 1007), q restores.
tmux: start, ctrl+b %, status bar, exit PASS.
shell drag selection PASS (highlight; text lands in PRIMARY via copy-on-select).
double-click word / triple-click line PASS ("beta"; whole line).
ctrl+shift+c PASS (CLIPBOARD gets the selection).
right-click PASS: context popover becomes visible (context menu visible = true).
wheel scrollback (10 ticks = 30 lines) PASS.
long wrapped line + window resize (shrink, grow) PASS: reflow correct both ways, viewport preserved.
unicode: CJK, emoji, ZWJ family, combining, fullwidth, powerline/nerd glyphs, box drawing PASS: widths/alignment correct.
kitty graphics (PNG, a=T, c=8,r=4) PASS: image rendered at the right cell size, text flows after it.
multi-line paste into cat (no bracketed paste) PASS: core rejects as unsafe, GhosttyClipboardConfirmationDialog is created and mapped (widget tree dump). The dialog isn't visible in the render-texture screenshot, only verified structurally.
Raw mouse bytes (SGR 1006, button 1/3, wheel) PASS: ESC[<0;10;5M/m, ESC[<2;.., ESC[<64;.. x3 per tick.
Kitty keyboard protocol (flags 1/31) from key steps PASS (CSI u with text/release events).

Bugs

No product bugs found in this pass. Observations:

  • Release profile keeps debug-assertions = true (workspace Cargo.toml), so the "debug build" banner shows; use --profile production to get the real release look.
  • screenshot returns the renderer's last presented frame; right after input it can be one frame stale. Use >= 1 s waits.
  • Replay limits: key <printable> bypasses the IM; text commits bypass key events (plain bytes even under kitty flags "report all keys"); window is not compositor-focused so cursor is hollow and clicks need assume_focus.
  • nvim leaves swap files when the replay is quit mid-edit; a later nvim of the same file prompts (E325) and swallows keystrokes. This looked like a bug at first but is nvim behaviour (use nvim -n).

Remaining

  • Confirm/deny of the paste dialog by interacting with it not exercised; IME via real input method not exercised.
  • Horizontal scroll (tab switching) not replayed.