import AppKit /// Das Fenster, in dem das Notch-Panel lebt. /// /// Zwei Anforderungen kollidieren hier: es muss über allem liegen, auch über der /// Menüleiste — und es darf der aktiven App niemals den Fokus wegnehmen. Wer beim /// Blick auf den Kalender den Cursor aus seinem Editor verliert, benutzt das /// Panel kein zweites Mal. public final class NotchPanel: NSPanel { public init(contentRect: NSRect) { super.init(contentRect: contentRect, styleMask: [.borderless, .nonactivatingPanel], backing: .buffered, defer: false) isFloatingPanel = true // Ohne das wird das Panel beim ersten Klick zum Schlüsselfenster und // entzieht der aktiven App den Fokus. becomesKeyOnlyIfNeeded = true hidesOnDeactivate = false // Über der Menüleiste, aber unter Bildschirmschoner und Anmeldefenster. level = NSWindow.Level(rawValue: Int(CGWindowLevelForKey(.statusWindow)) + 1) // Auf allen Schreibtischen sichtbar und auch neben Vollbildfenstern, // ohne beim Umschalten mitzuwandern. collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary, .stationary, .ignoresCycle] backgroundColor = .clear isOpaque = false // Der Fensterschatten folgt dem Fensterrahmen, nicht der gezeichneten // Form. Da das Fenster immer die volle Panelgröße hat, läge der Schatten // während der ganzen Animation um eine unsichtbare Fläche. Den Schatten // zeichnet deshalb SwiftUI, wo er der wachsenden Form folgt. hasShadow = false isMovable = false isMovableByWindowBackground = false // Kein Systemeinblenden: das Panel bringt seine eigene Animation mit, // und beide übereinander sehen aus wie ein Ruckler. animationBehavior = .none acceptsMouseMovedEvents = true // Nicht in Bildschirmaufnahmen und Fensterlisten auftauchen. isExcludedFromWindowsMenu = true } /// Randlose Fenster gelten sonst als nicht fokussierbar — das bräuchten wir /// aber, damit `esc` im fixierten Zustand ankommt. public override var canBecomeKey: Bool { true } public override var canBecomeMain: Bool { false } } /// Der unsichtbare Fühler über der Notch. /// /// Er zeichnet nichts und nimmt keine Klicks an — `ignoresMouseEvents` bleibt an, /// sonst würden die Menüleiste und die Fensterknöpfe darunter unerreichbar. /// Die Zeigerposition kommt aus einem globalen Monitor, nicht aus diesem Fenster; /// das Fenster dient nur der Sichtprüfung beim Entwickeln. public final class NotchDebugOverlay: NSPanel { public init(frame: NSRect) { super.init(contentRect: frame, styleMask: [.borderless, .nonactivatingPanel], backing: .buffered, defer: false) level = NSWindow.Level(rawValue: Int(CGWindowLevelForKey(.statusWindow)) + 2) collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary, .stationary] backgroundColor = NSColor.systemPink.withAlphaComponent(0.25) isOpaque = false hasShadow = false ignoresMouseEvents = true } }