fix(macos): keep voice wake overlay on top

This commit is contained in:
Peter Steinberger
2025-12-12 22:09:14 +00:00
parent 6a7f955818
commit c50c3699d9
2 changed files with 13 additions and 3 deletions

View File

@@ -248,6 +248,7 @@ final class CanvasWindowController: NSWindowController, WKNavigationDelegate, NS
window.makeKeyAndOrderFront(nil)
NSApp.activate(ignoringOtherApps: true)
window.makeFirstResponder(self.webView)
VoiceWakeOverlayController.shared.bringToFrontIfVisible()
self.onVisibilityChanged?(true)
}

View File

@@ -10,6 +10,10 @@ final class VoiceWakeOverlayController: ObservableObject {
private let logger = Logger(subsystem: "com.steipete.clawdis", category: "voicewake.overlay")
/// Keep the voice wake overlay above any other Clawdis windows, but below the systems pop-up menus.
/// (Menu bar menus typically live at `.popUpMenu`.)
private static let preferredWindowLevel = NSWindow.Level(rawValue: NSWindow.Level.popUpMenu.rawValue - 4)
enum Source: String { case wakeWord, pushToTalk }
@Published private(set) var model = Model()
@@ -308,9 +312,7 @@ final class VoiceWakeOverlayController: ObservableObject {
panel.isOpaque = false
panel.backgroundColor = .clear
panel.hasShadow = false
// Voice wake must stay above any other Clawdis windows (Canvas, WebChat, notifications).
// `.statusBar` is shared with some other overlays, so bump it slightly to avoid ordering fights.
panel.level = NSWindow.Level(rawValue: NSWindow.Level.statusBar.rawValue + 2)
panel.level = Self.preferredWindowLevel
panel.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary, .transient]
panel.hidesOnDeactivate = false
panel.isMovable = false
@@ -326,6 +328,13 @@ final class VoiceWakeOverlayController: ObservableObject {
self.window = panel
}
/// Reassert window ordering when other panels are shown.
func bringToFrontIfVisible() {
guard self.model.isVisible, let window = self.window else { return }
window.level = Self.preferredWindowLevel
window.orderFrontRegardless()
}
private func targetFrame() -> NSRect {
guard let screen = NSScreen.main else { return .zero }
let height = self.measuredHeight()