Skip to content

Port round 2 from upstream cmux: close race, scroll boost, monitor identity - #150

Merged
arzafran merged 5 commits into
mainfrom
feat/port-upstream-fixes-r2
Jul 20, 2026
Merged

Port round 2 from upstream cmux: close race, scroll boost, monitor identity#150
arzafran merged 5 commits into
mainfrom
feat/port-upstream-fixes-r2

Conversation

@arzafran

Copy link
Copy Markdown
Member

What this does

Second round of fixes brought over from upstream cmux, same shape as #130. Three user-visible annoyances go away: a spurious "close tab?" prompt when closing a terminal that just opened, runaway scrolling with high-res mouse wheels, and restored windows landing on the wrong monitor after unplugging a display or sleep/wake.

Closes #135.

Summary

Nine upstream commits were analyzed against our tree; three produced real changes, six were not applicable because they patch upstream features this fork never had. Every port is an adaptation, not a raw cherry-pick.

Ported:

  • 2e03978ae1 close-confirmation-before-tty-attach race. Upstream gates on ghostty C API exports (foreground_pid/tty_name) our ghostty fork doesn't have; we gate the unknown-activity fallback on our own surfaceTTYNames telemetry instead. Lands as two commits per the regression policy: failing test first, fix second.
  • da4e4bc460 precise-scroll boost gating. Our scrollWheel doubled precise deltas unconditionally — the exact upstream bug. The decision now lives in a pure GhosttyTerminalScrollBoost struct with four-case unit coverage; only gesture-phase devices get the 2x boost. The wheel classifier is unit-tested; the real-device behavior (high-res mouse vs trackpad) still deserves a manual spin.
  • 7a06b39766 + the geometry tie-break from 021379f054: stable per-monitor identity (CGDisplayCreateUUIDFromDisplayID) persisted alongside displayID, matched first on restore, geometry tie-break for duplicates, full fallback for old snapshots (field is Optional; pre-existing sessions decode fine).

Not applicable (recorded so the next port round doesn't re-litigate):

  • 0e7447ac2c mirror-state display signatures and 31b9021448 frame-ring sanitization: patch a per-configuration frame-memory system (windowConfigFrames/SessionConfigFramePolicy) we never built.
  • The capture-guard half of 021379f054: no continuous capture guard exists here.
  • b0f7b0bf89 link-through-panel-mapping: our TerminalPanel.id is structurally identical to its surface id, so the id-space bug can't occur; the deep-link feature it protects doesn't exist here.
  • b0cfd2cbb5/856d255728 hover-close reconciliation and 493d5ad707 closure capture: both fix upstream's AppKit list-with-cell-reuse sidebar; ours is SwiftUI with stable per-workspace identity and no reuse.

Test Plan

  • New unit tests: WorkspaceCloseConfirmationTests (4, red-then-green across the two commits), GhosttyScrollPreciseBoostTests (4), two stable-identity cases in SessionPersistenceTests
  • Full SessionPersistenceTests suite (54) green — old-snapshot compatibility covered
  • Tagged debug build launches; test_workspace_split_title_updates.py green against it (same files as the close-race fix)
  • Manual: high-res mouse wheel vs trackpad scrolling; monitor unplug/replug restore on real hardware
  • CI green

arzafran added 5 commits July 20, 2026 15:02
Adapted from upstream cmux regression 49a0cd8559: right after a terminal
is created, no shell state has been reported and no TTY is known, so
there is nothing to lose and closing must not prompt. The ghostty
needs-confirm fallback can spuriously return true in that window.

testUnknownActivityWithoutTTYNeverConfirms fails on purpose; the fix
lands in the next commit so CI proves the test catches the race.
Ported from upstream cmux 2e03978ae1, adapted to our shell-integration
telemetry: upstream gates on ghostty_surface_foreground_pid/tty_name,
which our ghostty fork does not export, so we gate the unknown-activity
fallback on surfaceTTYNames instead — no confirmation until a TTY has
been reported for the panel. promptIdle/commandRunning behavior is
unchanged, and once a TTY is known the ghostty fallback is honored as
before.
)

Ported from upstream cmux da4e4bc460. Trackpads and Magic Mouse drive a
gesture phase and keep the historical 2x precise-delta boost; high-res
free-spin wheels report precise deltas with empty phase/momentumPhase
and were getting the boost stacked on top of the OS's own wheel
acceleration, producing runaway scrolling. The boost decision now lives
in GhosttyTerminalScrollBoost, a pure struct with unit coverage; the
precision bit forwarded to ghostty_surface_mouse_scroll is unchanged.
)

Ported from upstream cmux 7a06b39766 plus the geometry tie-break from
021379f054. macOS can reassign CGDirectDisplayID numbers across monitor
unplug/replug and sleep/wake, so restoring by raw displayID could land
windows on the wrong monitor or off-screen. Display snapshots now also
persist a CGDisplayCreateUUIDFromDisplayID-backed stableID; restore
matches on it first, tie-breaking duplicates by geometry, and falls back
to the old displayID matching for snapshots saved before this change.

Not ported from the upstream cluster (0e7447ac2c, 31b9021448, the
capture-guard half of 021379f054): they patch a per-configuration frame
ring and mirror-signature system this fork never had.
@arzafran
arzafran merged commit 1d12c39 into main Jul 20, 2026
4 of 7 checks passed
@arzafran
arzafran deleted the feat/port-upstream-fixes-r2 branch July 20, 2026 18:20
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.

Port round 2 from upstream cmux: multi-monitor restore, close race, verified mediums

1 participant