Skip to content

Commit 31fcc86

Browse files
committed
bug-fix: keep HUD above fullscreen windows
1 parent 152de27 commit 31fcc86

2 files changed

Lines changed: 36 additions & 9 deletions

File tree

Sources/Spotlight/SpotlightWindow.swift

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,13 @@ public final class SpotlightWindowController {
2121
/// that app's fullscreen Space.
2222
/// `.canJoinAllSpaces` keeps the panel reachable from every Space,
2323
/// `.fullScreenAuxiliary` lets it sit alongside fullscreen windows,
24-
/// `.stationary` stops it being dragged along during Space
25-
/// transitions (which would otherwise yank focus during the swipe),
26-
/// and `.ignoresCycle` keeps this transient HUD out of Cmd-` cycling.
24+
/// `.transient` keeps it in the floating Spaces group. `.stationary`
25+
/// looks tempting for all-space overlays, but AppKit treats it like
26+
/// desktop chrome; fullscreen Spaces can then leave a reused panel
27+
/// behind the fullscreen layer.
28+
/// `.ignoresCycle` keeps this transient HUD out of Cmd-` cycling.
2729
nonisolated static let panelCollectionBehavior: NSWindow.CollectionBehavior = [
28-
.canJoinAllApplications, .canJoinAllSpaces, .fullScreenAuxiliary, .stationary, .ignoresCycle
30+
.canJoinAllApplications, .canJoinAllSpaces, .fullScreenAuxiliary, .transient, .ignoresCycle
2931
]
3032
nonisolated static let defaultUnfocusedAlpha: CGFloat = 0.55
3133

@@ -356,6 +358,8 @@ public final class SpotlightWindowController {
356358
}
357359

358360
private func bringPanelToFront(_ panel: NSPanel) {
361+
Self.configurePanel(panel)
362+
panel.orderFrontRegardless()
359363
panel.makeKeyAndOrderFront(nil)
360364
panel.orderFrontRegardless()
361365
syncFuzzyPreviewPanel()
@@ -687,11 +691,20 @@ extension SpotlightWindowController {
687691
if fuzzyController.isVisible { fuzzyController.close() }
688692
commandController.toggle(shortcuts: shortcuts, preferences: preferences)
689693
case .insertTodayBadge:
690-
_ = panel?.firstResponder?.tryToPerform(#selector(PlaceholderTextView.insertTodayBadgeToken(_:)), with: nil)
694+
_ = panel?.firstResponder?.tryToPerform(
695+
#selector(PlaceholderTextView.insertTodayBadgeToken(_:)),
696+
with: nil
697+
)
691698
case .insertChecklist:
692-
_ = panel?.firstResponder?.tryToPerform(#selector(PlaceholderTextView.insertChecklistToken(_:)), with: nil)
699+
_ = panel?.firstResponder?.tryToPerform(
700+
#selector(PlaceholderTextView.insertChecklistToken(_:)),
701+
with: nil
702+
)
693703
case .toggleChecklist:
694-
_ = panel?.firstResponder?.tryToPerform(#selector(PlaceholderTextView.toggleChecklistShortcut(_:)), with: nil)
704+
_ = panel?.firstResponder?.tryToPerform(
705+
#selector(PlaceholderTextView.toggleChecklistShortcut(_:)),
706+
with: nil
707+
)
695708
case .pinNote:
696709
Task { await session.togglePin() }
697710
case .shareCurrentChat:

Tests/SpotlightTests/SpotlightWindowControllerTests.swift

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ struct SpotlightWindowControllerTests {
3535
/// **Regression guard** -- `.fullScreenAuxiliary` is what allows the
3636
/// HUD to render in a Space owned by a fullscreen app. Without it,
3737
/// the panel is hidden behind the fullscreen layer and never shown.
38-
@Test("panel collection behavior includes .fullScreenAuxiliary -- required for over-fullscreen HUD")
38+
@Test(
39+
"panel collection behavior includes .fullScreenAuxiliary -- required for over-fullscreen HUD"
40+
)
3941
func panelCollectionBehaviorAllowsFullscreen() {
4042
let behavior = SpotlightWindowController.panelCollectionBehavior
4143
#expect(behavior.contains(.fullScreenAuxiliary))
@@ -54,6 +56,17 @@ struct SpotlightWindowControllerTests {
5456
#expect(!behavior.contains(.auxiliary))
5557
}
5658

59+
/// **Regression guard** -- the HUD is a summonable floating overlay,
60+
/// not desktop chrome. `.stationary` can leave a reused panel behind
61+
/// a fullscreen window set after AppKit rebuilds Spaces membership.
62+
@Test("panel uses transient Spaces behavior -- required for reused over-fullscreen HUD")
63+
func panelUsesTransientSpacesBehavior() {
64+
let behavior = SpotlightWindowController.panelCollectionBehavior
65+
#expect(behavior.contains(.transient))
66+
#expect(!behavior.contains(.managed))
67+
#expect(!behavior.contains(.stationary))
68+
}
69+
5770
/// **Regression guard** -- recent macOS releases can keep
5871
/// fullscreen windows above `.statusBar` auxiliary panels. The HUD is
5972
/// transient, so it uses the overlay-grade screen saver level.
@@ -78,7 +91,8 @@ struct SpotlightWindowControllerTests {
7891
#expect(panel.collectionBehavior.contains(.canJoinAllSpaces))
7992
#expect(panel.collectionBehavior.contains(.canJoinAllApplications))
8093
#expect(panel.collectionBehavior.contains(.fullScreenAuxiliary))
81-
#expect(panel.collectionBehavior.contains(.stationary))
94+
#expect(panel.collectionBehavior.contains(.transient))
95+
#expect(!panel.collectionBehavior.contains(.stationary))
8296
#expect(panel.collectionBehavior.contains(.ignoresCycle))
8397
#expect(panel.hidesOnDeactivate == false)
8498
#expect(panel.isFloatingPanel)

0 commit comments

Comments
 (0)