Skip to content

fix(menubar): fix popover layout-recursion crash on macOS 26/27#265

Open
Leewallace017 wants to merge 1 commit into
hamed-elfayome:mainfrom
Leewallace017:fix/popover-layout-recursion-crash
Open

fix(menubar): fix popover layout-recursion crash on macOS 26/27#265
Leewallace017 wants to merge 1 commit into
hamed-elfayome:mainfrom
Leewallace017:fix/popover-layout-recursion-crash

Conversation

@Leewallace017

@Leewallace017 Leewallace017 commented Jun 25, 2026

Copy link
Copy Markdown

Description

On macOS 26/27, clicking the menu bar icon can crash the app with EXC_BAD_ACCESS ("Thread stack size exceeded due to excessive recursion"). The main thread overflows in an unbounded AppKit/SwiftUI layout loop while the popover is being shown.

Root cause: the popover's NSHostingController uses sizingOptions = .preferredContentSize (added in #200 to fix positioning), which continuously re-pushes the SwiftUI content size into the popover window. With NSPopover.animates = true, macOS 26/27's updated SwiftUI never converges the animated resize:

NSPopover.show
  -> NSHostingView.windowDidLayout
    -> updateAnimatedWindowSize
      -> _NSPopoverWindow.setFrame:display:
        -> layout   (repeats ~6,500x) -> stack overflow

This is the layout-recursion fragility flagged in #64, escalated from a warning into a hard crash by the newer SwiftUI. Reproduced on macOS 27.0 (build 26A5353q), Apple Silicon.

Changes

  • Fix the crash: disable the native popover animation (animates = false) in setupPopover() and recreatePopover(), so the animated window resize can no longer feed the loop. The preferredContentSize/sizingOptions sizing from fix(popover): Fix popover positioning offset and menubar overlap #200 is left intact, so the popover's content-hugging size and position are unchanged.
  • Keep an animated open: replace the native animation with a custom SwiftUI fade + scale-from-top entrance in PopoverContentView. It runs purely as an opacity/transform on the fixed-size view, so it cannot re-trigger the window-resize loop.
  • Fix a dismiss/re-open race: clicking the status item could occasionally close and immediately re-open the popover (the outside-click monitor and the button action racing). The popover now records its last close time, and togglePopover ignores a re-open within 0.25s of a close.

Screenshots / Screen Recordings

Screen recording (open animation + click-to-toggle + no crash) attached below.

Checklist

  • I have tested these changes on a running build (Xcode 27 on macOS 27): repeated open/close with no crash, animated open, polished sizing, reliable click-to-toggle
popover-crash-fix-demo.mp4
  • I have attached screenshots/recordings for any visual changes
  • I have not introduced App Group or grouped Keychain usage
  • N/A — no new user-facing strings

Clicking the menu bar icon could crash the app with EXC_BAD_ACCESS
("Thread stack size exceeded due to excessive recursion") on macOS 26/27.
The NSHostingController's sizingOptions = .preferredContentSize (added in
hamed-elfayome#200 for positioning) continuously re-pushes the SwiftUI content size into
the popover window, and with NSPopover.animates = true the animated resize
never converges on the newer SwiftUI: windowDidLayout ->
updateAnimatedWindowSize -> setFrame -> layout, overflowing the main-thread
stack. This is the layout-recursion fragility noted in hamed-elfayome#64, escalated into
a hard crash.

- Disable the native popover animation (animates = false) in setupPopover()
  and recreatePopover() so the animated resize can no longer loop. The fixed
  preferredContentSize/sizingOptions keep hamed-elfayome#200's content sizing/positioning.
- Replace the lost open animation with a custom SwiftUI fade + scale-from-top
  entrance in PopoverContentView, applied to the fixed-size view so it can't
  re-trigger the window-resize loop.
- Fix a dismiss/re-open race surfaced by the timing change: clicking the
  status item could close and immediately re-open the popover. Record the
  last close time and have togglePopover ignore a re-open within 0.25s.

Tested on a running build (Xcode 27, macOS 27): repeated open/close with no
crash, animated open, polished sizing, reliable click-to-toggle.
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