cmux NEXT: a drag's mouse-up sends each terminal's newest grid to its program in that turn

Merged
LA
14h ago
+81-4

cmux-ad m29, the RESIZE OWNER's step (a): when a person lets go of a divider or column edge, each terminal's program now gets the drag's newest size in the mouse-up's turn. Before, that size waited in the 25 ms coalescing window (or for the next frame), so the program started its last redraw late.

Follows #36631 (drags send coalesced shown grids, merged at 9511b2df1c8).

Why

  • The release-cut film of px-col-drag-2 on build 155b3f25 (STATUS 15707): after the mouse-up at video frame 520, the full-screen test program read 78x48 at 521, 72x48 at 522-524 and 71x48 (final, whole) only from 525, 4 refreshes after its pane stopped. Reduce Motion: the same 4 refreshes.
  • At the mouse-up nothing reached the terminals: ScreenContentView.resizeGestureReleased() only set .releasing and asked for frames, and the drag's newest grid stayed in TerminalGridReportCoalescer until its window fired or the release's landing flushed it. In the film the last size was also still in flight at the mouse-up (trace frame 526).

Fix

  • PaneResizeGestureFollowing gets paneResizeGestureReleased() (default: nothing). ScreenContentView.resizeGestureReleased() calls it on every listener in the mouse-up's turn, before the release's layout lands.
  • TerminalHostView passes it to its current surface's TerminalGridReporter.release():
    • no size in flight: the grid that waits in the 25 ms window goes now (coalescer.flush());
    • a newer size in flight (asked of Ghostty, not shown yet): the waiting grid is older and is dropped (coalescer.cancel()), and the in-flight size's grid goes the moment its frame shows, not coalesced (sendsAwaitedNow).
  • No new timer. Sizes that a release spring moves through after the mouse-up coalesce again. now() (every report at rest, forced or final) clears the flag.

Changelog

  • Fixed: When you let go of a divider or column edge, the program in each terminal gets its final size at once instead of up to a frame or 25 ms later.

Tests

DividerDragTerminalResizeCountTests.aDragsLastGridGoesInTheMouseUpTurn: a ManualClock that never moves, 6 drag frames of 12 pt (the window still waits), then .ended; right after it, no grid may wait and the coalescer's last sent grid must be the view's fitted grid. No sleeps.

RunRefStepResult
red5a43d99988d (test only, on feat fed792be995)6f2da2498c034ca8e842a177 (aws-m4pro-2)FAIL as expected: p1: its last drag grid still waits after the mouse-up (a frame or 25 ms more), lastSent → nil == fittedGrid → 65x46; the same for p2 (82x46). The suite's other test passed.
green: 7 suites28f5faa1f7da3eddfee9398c62f8ebc1114ci-step m29e-green exited 0: 7 suites, 37 tests; aDragsLastGridGoesInTheMouseUpTurn passed
app build28f5faa1f7d1e38143aad69eb517adf1d0adone (cmux DEV m29-endflush-v1)
launch smoke (fresh-home)build 1e38143a57a1b05359a79b10a4d01164the app launched: fresh-home launch smoke OK: up 30s, Home at 12.0s, no crash (validator at feat 4822eb5d7ea); the client's verdict is a base finding (below)

Green suites: DividerDragTerminalResizeCountTests, DividerDragTerminalSteadyTests, TerminalGridReportCoalescerTests, PaneResizeGestureTests, SplitTerminalResizeCountTests, DividerDragFollowsPointerTests, DividerModifierDragTests.

No capture: the change is when a terminal's program gets its size at a drag's mouse-up; a still cannot show it. pixel-perfect films px-col-drag-2 on a build with it after the merge, and the refresh count from the mouse-up to the program whole goes in STATUS (base: 4 on 155b3f25).

Observed / Not run

  • Base finding, not this PR (the launch passed): the hq cmux-ci fresh-home client posts cmux-ci/fresh-home failure, "Home did not render in a visible window", on every fresh-home run since at least 00:09Z (receipts for #36906, #36901, #36962, #36017 and this PR, five Macs, four validator commits). The validator (scripts/ci/fresh_home_launch_smoke.py) has counted the first-run Bring your history page over Home as a healthy launch since #34475 and passes these runs, but the client re-checks report.home_tab, which is set only when Home's tab is selected, and the first-run page leaves it unselected. The screenshot shows the window with the sidebar, Home, the first-run page and the Command Palette tip.
  • Observed: the red, green, build and launch smoke above; the prepush gate and check-no-godfiles (ScreenContentView+ResizeGesture keeps its line count; TerminalHostView.swift is not touched).
  • Known gap (P2, the RESIZE OWNER's read of 28f5faa1f7d): shownCancelled(live:) ignores sendsAwaitedNow. If the presenter cancels the in-flight size after the mouse-up while the drag still lives (the view hid or left its window before its frame landed), that grid goes coalesced (up to 25 ms) instead of now, and the flag stays set, so the next drag's first shown grid goes uncoalesced. A new drag that starts before the awaited frame shows inherits the flag the same way. #36478 (T-KEYS) changes shownCancelled, so the fix and its red test land after both PRs merge, on the combined code.
  • Not run: a film with the fix (pixel-perfect, after the merge); no review (feat-cmux-next m26/m30 rule: compile, launch and focused red/green).