Skip to content

perf: cache portal split-divider regions off the hover/keyboard hot path (#18, upstream #6587)#30

Merged
arzafran merged 2 commits into
mainfrom
fix/portal-hittest-cache
Jun 25, 2026
Merged

perf: cache portal split-divider regions off the hover/keyboard hot path (#18, upstream #6587)#30
arzafran merged 2 commits into
mainfrom
fix/portal-hittest-cache

Conversation

@arzafran

Copy link
Copy Markdown
Member

Closes #18 (upstream cmux manaflow-ai#6587). Portal host views recursively walked the entire AppKit view tree to find split-divider regions on every cursorUpdate/mouseMoved/hitTest (and, for the browser portal, every keyboard event too) — a typing-latency hot path.

Fix: cache the divider regions (cachedDividerRegions), invalidate on geometry change, and add the missing isPointerEvent guard to BrowserWindowPortal.hitTest so keyboard events skip the work entirely.

Adversarial review caught a stale-cache bug (and it's fixed here): a split add/remove divides space within the host's fixed frame, so the frame hooks never fire and the cache went stale → the new divider was ungrabbable. Now resetCursorRects() drops the cache before re-warming, and the split-change sync path (NSSplitView.didResizeSubviewsNotification) forces invalidateCursorRects, so a new divider is immediately grabbable. Cache is per-cursor-rect-cycle, so the per-event walk is still eliminated.

Triaged + implemented + adversarially reviewed via ultracode; the review found and the fix addresses the stale-cache regression.

arzafran added 2 commits June 25, 2026 14:51
…flow-ai#6587 review)

The adversarial review found a stale-cache bug: the cache was invalidated only on
the host view's frame hooks (setFrameSize/setFrameOrigin/viewDidMoveToWindow), but
adding/removing a split pane divides space WITHIN the host's fixed boundary — the
host frame doesn't change, so none of those fire and the cache held stale divider
regions. Result: a newly-added divider was ungrabbable (cursor stayed arrow,
clicks passed through to the surface) until something else resized the host.

Fix (both WindowTerminalHostView/WindowTerminalPortal and the Browser equivalents):
- resetCursorRects() now drops `cachedDividerRegions` before re-warming, so the
  cache is fresh per cursor-rect cycle (not per pointer event — perf preserved).
- synchronizeAllEntriesFromExternalGeometryChange() (driven by
  NSSplitView.didResizeSubviewsNotification) now calls invalidateCursorRects(for:)
  on the host, forcing resetCursorRects → cache drop, even when the host frame is
  unchanged. So a split add/remove makes the new divider immediately grabbable.
@arzafran arzafran merged commit f6352de into main Jun 25, 2026
8 checks passed
@arzafran arzafran deleted the fix/portal-hittest-cache branch June 25, 2026 18:58
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.

Tagged DEV/staging builds surface the public Sparkle 'Update Available' pill

1 participant