Skip to content

fix(toolbar): open the quick switcher panel on macOS 15#1806

Merged
datlechin merged 3 commits into
mainfrom
fix/quick-switcher-macos-15
Jul 3, 2026
Merged

fix(toolbar): open the quick switcher panel on macOS 15#1806
datlechin merged 3 commits into
mainfrom
fix/quick-switcher-macos-15

Conversation

@datlechin

@datlechin datlechin commented Jul 3, 2026

Copy link
Copy Markdown
Member

Problem

On macOS 15 the Quick Switcher never opens. Clicking the toolbar button or pressing the shortcut does nothing. The same build works on macOS 26.

Root cause

The 0.51.0 floating panel rewrite (#1644) sized the panel from NSHostingView.fittingSize, measured before any layout pass, and relied on SwiftUI's automatic window sizing to correct it afterwards. Apple removed that eager sizing in macOS 15 (release note issue 118586136), so on Sequoia the borderless panel stays at zero size: invisible. The invisible panel never becomes key, so the resign-key dismissal never clears isPresented, and every later trigger hits the toggle's "dismiss" branch. macOS 26 only worked because the init-time measurement happened to land on the right size there.

The automatic sizing machinery is also unsafe in the other direction: when the window size and SwiftUI's ideal size disagree, NSHostingView.updateAnimatedWindowSize recurses until the stack overflows (reproduced twice in the test host, confirmed by crash report stacks).

Fix

QuickSwitcherPanel.swift only. The panel no longer depends on automatic window sizing in either direction:

  • Panel size is explicit: measured with NSHostingController.sizeThatFits(in:) against the screen's visible frame and applied before the panel is ordered front. sizingOptions is empty.
  • Content growth (results loading) reports through onGeometryChange; the controller applies it with setContentSize, which flows through the existing windowDidResize re-anchoring.
  • Dismissal follows the standard palette pattern: .nonactivatingPanel, the panel closes itself in resignKey() and on Escape via close(), and the controller clears its state only in windowWillClose (which also detaches the content so SwiftUI tears it down and the key event monitor is removed, fixing a pre-existing monitor leak). The panel stays non-main so the document window keeps its active appearance. A stale "presented" flag can no longer occur.

Entry points, panel content, and the search field are unchanged.

Tests

QuickSwitcherPanelControllerTests grew from 6 to 10 cases, including a non-zero-frame assertion after construction that fails against the old code. All pass locally. No UI automation: floating panel key-window ordering is not deterministic in headless CI, and CI has no macOS 15 runner.

Manual verification on a macOS 15 machine still needed: toolbar button opens, shortcut opens, second trigger closes, Escape closes, click outside closes, panel stays top-centered as results load.

@datlechin datlechin force-pushed the fix/quick-switcher-macos-15 branch from f29edaf to 631a76c Compare July 3, 2026 02:50

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f29edaf273

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

func windowWillCloseClearsPresentedState() {
let controller = QuickSwitcherPanelController()
controller.present(Text(verbatim: "content"), over: nil)
controller.windowWillClose(Notification(name: NSWindow.willCloseNotification))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Close the panel instead of faking willClose

Because present has just ordered the panel front, calling the delegate method directly only drops the controller's reference; it never closes or orders out the NSPanel. In this test target AppKit keeps ordered-in windows alive, so this test (and the similar no-op test below) can leave an orphan key panel around to affect later tests; exercise the real close path instead of invoking windowWillClose by hand.

Useful? React with 👍 / 👎.

@datlechin datlechin merged commit eca07cf into main Jul 3, 2026
3 checks passed
@datlechin datlechin deleted the fix/quick-switcher-macos-15 branch July 3, 2026 03:30
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