Skip to content

fix: menu-bar hover/click freeze — bound NSMenu-hosted charts + cut macOS 26 vibrancy cost#22

Open
johnlarkin1 wants to merge 1 commit into
mainfrom
fix-menu-hover-freeze
Open

fix: menu-bar hover/click freeze — bound NSMenu-hosted charts + cut macOS 26 vibrancy cost#22
johnlarkin1 wants to merge 1 commit into
mainfrom
fix-menu-hover-freeze

Conversation

@johnlarkin1

Copy link
Copy Markdown
Owner

Summary

Fixes the menu-bar hover/click freeze (which on a busy system could freeze the whole machine) and reduces hover lag on macOS 26. Root cause found by profiling: per-process sample + system JetsamEvent analysis pointed at NSMenu-hosted SwiftUI chart layout, not a CPU spin.

Root cause

  1. Catastrophic freeze (whole machine): The NSMenu-hosted chart views ended with .frame(minWidth: self.width, maxWidth: .infinity). When NSMenu runs its optimal-size pass (_maximumSizeForScreen) against a hosted NSHostingView, the maxWidth: .infinity lets it feed a screen-sized width into the chart and its inner GeometryReader, ballooning the layout/backing-store allocation. On an already memory-busy system this spiked memory pressure enough to trigger a system-wide jetsam — i.e. a whole-computer freeze. (A JetsamEvent fired at the exact moment of repro; the per-process CPU sample was idle, consistent with memory pressure rather than a CPU loop.)

  2. Hover lag (macOS 26): MenuCardItemHostingView / MenuHostingView forced allowsVibrancy = true, so every menu highlight re-composited the hosted SwiftUI views against the Liquid Glass backdrop — measured at several ms per highlight transition.

Changes

  • Bound all five problem charts to their explicit width (matching the already-safe StorageBreakdownMenuView): PlanUtilizationHistoryChartMenuView, CostHistoryChartMenuView, CreditsHistoryChartMenuView, UsageBreakdownChartMenuView, ZaiHourlyUsageChartMenuView.
  • Disable allowsVibrancy on macOS 26+ for the menu-card hosting views (kept on older macOS where it's cheap and the look matters).

6 files, +9/−7.

Verification

  • swift build ✅, ./Scripts/lint.sh lint 0 violations ✅, swift test ✅ (3 unrelated OpenAI-web/Codex-refresh timing tests flake under parallel load on a busy machine; pass in isolation).
  • Installed locally; no new JetsamEvent after the fix.

Known follow-up (not in this PR)

Profiling also showed that switching provider tabs rebuilds the entire menu (populateMenu ~38 ms, dominated by reconstructing all SwiftUI NSHostingViews from scratch — model/data work is only ~2 ms). That per-switch teardown+rebuild is an architectural cost and will be addressed separately.

🤖 Generated with Claude Code

…ancy cost on macOS 26

Two menu-rendering fixes found via profiling a hover/click freeze:

1. Catastrophic freeze: the NSMenu-hosted chart views declared
   `.frame(minWidth: width, maxWidth: .infinity)`. NSMenu's optimal-size
   pass (_maximumSizeForScreen) could feed a screen-sized width into the
   hosted chart + its inner GeometryReader, ballooning the layout/backing-
   store allocation. On a busy system this spiked memory pressure hard
   enough to trigger a system-wide jetsam (whole-machine freeze). Bound all
   five charts to their explicit `width`, matching the already-safe
   StorageBreakdownMenuView.

2. Hover lag: MenuCardItemHostingView / MenuHostingView forced
   allowsVibrancy = true, so every menu highlight re-composited the hosted
   SwiftUI views against the Liquid Glass backdrop on macOS 26. Disable
   vibrancy on macOS 26+ (kept on older macOS where it is cheap).

Files: PlanUtilizationHistoryChartMenuView, CostHistoryChartMenuView,
CreditsHistoryChartMenuView, UsageBreakdownChartMenuView,
ZaiHourlyUsageChartMenuView, StatusItemController+MenuPresentation.

Note: the per-tab-switch full menu rebuild (~38ms in populateMenu, mostly
NSHostingView construction) is a separate, architectural cost tracked as
follow-up work.

Co-Authored-By: Claude Opus 4.8 (1M context) <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