Working a bit

This commit is contained in:
Hariharan Mudaliar 2025-12-01 13:01:44 +05:30
commit 1f0eea3cc6
8 changed files with 881 additions and 91 deletions

View file

@ -0,0 +1,252 @@
#if os(macOS)
import AppKit
import SwiftUI
import SkyLightWindow
import QuartzCore
import Defaults
/// Manages custom OSD windows for volume, brightness, and keyboard backlight controls
/// Mimics macOS native OSD behavior with custom styling
@MainActor
final class CustomOSDWindowManager {
static let shared = CustomOSDWindowManager()
private var volumeWindow: OSDWindow?
private var brightnessWindow: OSDWindow?
private var backlightWindow: OSDWindow?
private var hideWorkItem: DispatchWorkItem?
private let displayDuration: TimeInterval = 2.0
private let animationDuration: TimeInterval = 0.3
private var isInitialized = false
// Standard macOS OSD dimensions (approximate)
private let osdWidth: CGFloat = 200
private let osdHeight: CGFloat = 200
private init() {}
// MARK: - Public API
func showVolume(value: CGFloat, isMuted: Bool = false, icon: String = "") {
guard Defaults[.enableCustomOSD], isInitialized else { return }
show(type: .volume, value: value, icon: icon)
}
func showBrightness(value: CGFloat) {
guard Defaults[.enableCustomOSD], isInitialized else { return }
show(type: .brightness, value: value, icon: "")
}
func showBacklight(value: CGFloat) {
guard Defaults[.enableCustomOSD], isInitialized else { return }
show(type: .backlight, value: value, icon: "")
}
func initialize() {
isInitialized = true
}
// MARK: - Private Implementation
private func show(type: SneakContentType, value: CGFloat, icon: String) {
guard let screen = NSScreen.main else { return }
// Close other windows first
hideAllWindowsExcept(type: type)
let window = ensureWindow(for: type)
updateContent(window: window, type: type, value: value, icon: icon)
let targetFrame = calculateFrame(for: screen)
if window.nsWindow.alphaValue <= 0.01 {
// Initial presentation
presentWindow(window, targetFrame: targetFrame)
} else {
// Update existing window
window.nsWindow.setFrame(targetFrame, display: true)
window.nsWindow.orderFrontRegardless()
}
scheduleHide(for: type)
}
private func ensureWindow(for type: SneakContentType) -> OSDWindow {
let window: OSDWindow
switch type {
case .volume:
if let existing = volumeWindow {
return existing
}
window = createWindow(for: type)
volumeWindow = window
case .brightness:
if let existing = brightnessWindow {
return existing
}
window = createWindow(for: type)
brightnessWindow = window
case .backlight:
if let existing = backlightWindow {
return existing
}
window = createWindow(for: type)
backlightWindow = window
default:
fatalError("Unsupported OSD type: \(type)")
}
return window
}
private func createWindow(for type: SneakContentType) -> OSDWindow {
guard let screen = NSScreen.main else {
fatalError("No main screen available")
}
let osdView = CustomOSDView(type: .constant(type), value: .constant(0), icon: .constant(""))
let hostingView = NSHostingView(rootView: osdView)
let frame = calculateFrame(for: screen)
let window = NSWindow(
contentRect: frame,
styleMask: [.borderless, .nonactivatingPanel],
backing: .buffered,
defer: false
)
window.isOpaque = false
window.backgroundColor = .clear
window.level = .statusBar + 1
window.collectionBehavior = [.canJoinAllSpaces, .stationary, .ignoresCycle, .fullScreenAuxiliary]
window.hasShadow = false
window.contentView = hostingView
window.alphaValue = 0
// Delegate to SkyLight for proper rendering
SkyLightOperator.shared.delegateWindow(window)
return OSDWindow(nsWindow: window, hostingView: hostingView, type: type)
}
private func updateContent(window: OSDWindow, type: SneakContentType, value: CGFloat, icon: String) {
let osdView = CustomOSDView(type: .constant(type), value: .constant(value), icon: .constant(icon))
window.hostingView.rootView = osdView
}
private func calculateFrame(for screen: NSScreen) -> NSRect {
let screenFrame = screen.frame
let centerX = screenFrame.midX - (osdWidth / 2)
// Position at bottom center, similar to native macOS OSD
let bottomOffset: CGFloat = 120 // Distance from bottom of screen
let centerY = screenFrame.minY + bottomOffset
return NSRect(x: centerX, y: centerY, width: osdWidth, height: osdHeight)
}
private func presentWindow(_ window: OSDWindow, targetFrame: NSRect) {
let startFrame = targetFrame.offsetBy(dx: 0, dy: -20)
window.nsWindow.setFrame(startFrame, display: true)
window.nsWindow.alphaValue = 0
window.nsWindow.orderFrontRegardless()
NSAnimationContext.runAnimationGroup { context in
context.duration = animationDuration
context.timingFunction = CAMediaTimingFunction(name: .easeOut)
window.nsWindow.animator().setFrame(targetFrame, display: true)
window.nsWindow.animator().alphaValue = 1
}
}
private func hideAllWindowsExcept(type: SneakContentType) {
if type != .volume, let volumeWindow = volumeWindow, volumeWindow.nsWindow.alphaValue > 0.01 {
hideWindowImmediately(volumeWindow)
}
if type != .brightness, let brightnessWindow = brightnessWindow, brightnessWindow.nsWindow.alphaValue > 0.01 {
hideWindowImmediately(brightnessWindow)
}
if type != .backlight, let backlightWindow = backlightWindow, backlightWindow.nsWindow.alphaValue > 0.01 {
hideWindowImmediately(backlightWindow)
}
}
private func hideWindowImmediately(_ window: OSDWindow) {
NSAnimationContext.runAnimationGroup { context in
context.duration = 0.15
context.timingFunction = CAMediaTimingFunction(name: .easeIn)
window.nsWindow.animator().alphaValue = 0
} completionHandler: {
window.nsWindow.orderOut(nil)
}
}
private func scheduleHide(for type: SneakContentType) {
hideWorkItem?.cancel()
let workItem = DispatchWorkItem { [weak self] in
guard let self else { return }
Task { @MainActor in
self.hideWindow(for: type)
}
}
hideWorkItem = workItem
DispatchQueue.main.asyncAfter(deadline: .now() + displayDuration, execute: workItem)
}
private func hideWindow(for type: SneakContentType) {
let window: OSDWindow?
switch type {
case .volume:
window = volumeWindow
case .brightness:
window = brightnessWindow
case .backlight:
window = backlightWindow
default:
return
}
guard let window else { return }
let currentFrame = window.nsWindow.frame
let hideFrame = currentFrame.offsetBy(dx: 0, dy: -20)
NSAnimationContext.runAnimationGroup { context in
context.duration = animationDuration
context.timingFunction = CAMediaTimingFunction(name: .easeIn)
window.nsWindow.animator().setFrame(hideFrame, display: true)
window.nsWindow.animator().alphaValue = 0
} completionHandler: {
window.nsWindow.orderOut(nil)
}
}
// MARK: - Cleanup
func tearDown() {
hideWorkItem?.cancel()
hideWorkItem = nil
volumeWindow?.nsWindow.orderOut(nil)
brightnessWindow?.nsWindow.orderOut(nil)
backlightWindow?.nsWindow.orderOut(nil)
volumeWindow = nil
brightnessWindow = nil
backlightWindow = nil
}
}
// MARK: - OSD Window Container
private struct OSDWindow {
let nsWindow: NSWindow
let hostingView: NSHostingView<CustomOSDView>
let type: SneakContentType
}
#endif

View file

@ -145,30 +145,61 @@ final class SystemChangesObserver: MediaKeyInterceptorDelegate {
if HUDSuppressionCoordinator.shared.shouldSuppressVolumeHUD {
return
}
coordinator?.toggleSneakPeek(
status: true,
type: .volume,
value: CGFloat(value),
icon: ""
)
// Send to custom OSD if enabled
if Defaults[.enableCustomOSD] && Defaults[.enableOSDVolume] {
Task { @MainActor in
CustomOSDWindowManager.shared.showVolume(value: CGFloat(value))
}
}
// Send to notch HUD if enabled and OSD is not enabled
if Defaults[.enableSystemHUD] && !Defaults[.enableCustomOSD] && Defaults[.enableVolumeHUD] {
coordinator?.toggleSneakPeek(
status: true,
type: .volume,
value: CGFloat(value),
icon: ""
)
}
}
private func sendBrightnessNotification(value: Float) {
coordinator?.toggleSneakPeek(
status: true,
type: .brightness,
value: CGFloat(value),
icon: ""
)
// Send to custom OSD if enabled
if Defaults[.enableCustomOSD] && Defaults[.enableOSDBrightness] {
Task { @MainActor in
CustomOSDWindowManager.shared.showBrightness(value: CGFloat(value))
}
}
// Send to notch HUD if enabled and OSD is not enabled
if Defaults[.enableSystemHUD] && !Defaults[.enableCustomOSD] && Defaults[.enableBrightnessHUD] {
coordinator?.toggleSneakPeek(
status: true,
type: .brightness,
value: CGFloat(value),
icon: ""
)
}
}
private func sendKeyboardBacklightNotification(value: Float) {
coordinator?.toggleSneakPeek(
status: true,
type: .backlight,
value: CGFloat(value),
icon: ""
)
// Send to custom OSD if enabled
if Defaults[.enableCustomOSD] && Defaults[.enableOSDKeyboardBacklight] {
Task { @MainActor in
CustomOSDWindowManager.shared.showBacklight(value: CGFloat(value))
}
}
// Send to notch HUD if enabled and OSD is not enabled
if Defaults[.enableSystemHUD] && !Defaults[.enableCustomOSD] && Defaults[.enableKeyboardBacklightHUD] {
coordinator?.toggleSneakPeek(
status: true,
type: .backlight,
value: CGFloat(value),
icon: ""
)
}
}
private func configureKeyboardBacklightCallback() {

View file

@ -23,16 +23,40 @@ class SystemHUDManager {
}
private func setupSettingsObserver() {
// Observe master toggle
// Observe master HUD toggle
Defaults.publisher(.enableSystemHUD, options: []).sink { [weak self] change in
guard let self = self, self.isSetupComplete else {
return
}
Task { @MainActor in
if change.newValue && !Defaults[.enableCustomOSD] {
await self.startSystemObserver()
} else if !Defaults[.enableCustomOSD] {
// Only stop if OSD is also disabled
await self.stopSystemObserver()
}
}
}.store(in: &cancellables)
// Observe OSD toggle
Defaults.publisher(.enableCustomOSD, options: []).sink { [weak self] change in
guard let self = self, self.isSetupComplete else {
return
}
Task { @MainActor in
if change.newValue {
await self.startSystemHUD()
// Start observer for OSD if not already running
if self.changesObserver == nil {
await self.startSystemObserver()
}
} else if Defaults[.enableSystemHUD] {
// Keep observer running for HUD
if self.changesObserver == nil {
await self.startSystemObserver()
}
} else {
await self.stopSystemHUD()
// Stop observer if both HUD and OSD are disabled
await self.stopSystemObserver()
}
}
}.store(in: &cancellables)
@ -70,6 +94,40 @@ class SystemHUDManager {
keyboardBacklightEnabled: change.newValue
)
}.store(in: &cancellables)
// Observe individual OSD toggles
Defaults.publisher(.enableOSDVolume, options: []).sink { [weak self] change in
guard let self = self, self.isSetupComplete, Defaults[.enableCustomOSD] else {
return
}
self.changesObserver?.update(
volumeEnabled: change.newValue,
brightnessEnabled: Defaults[.enableOSDBrightness],
keyboardBacklightEnabled: Defaults[.enableOSDKeyboardBacklight]
)
}.store(in: &cancellables)
Defaults.publisher(.enableOSDBrightness, options: []).sink { [weak self] change in
guard let self = self, self.isSetupComplete, Defaults[.enableCustomOSD] else {
return
}
self.changesObserver?.update(
volumeEnabled: Defaults[.enableOSDVolume],
brightnessEnabled: change.newValue,
keyboardBacklightEnabled: Defaults[.enableOSDKeyboardBacklight]
)
}.store(in: &cancellables)
Defaults.publisher(.enableOSDKeyboardBacklight, options: []).sink { [weak self] change in
guard let self = self, self.isSetupComplete, Defaults[.enableCustomOSD] else {
return
}
self.changesObserver?.update(
volumeEnabled: Defaults[.enableOSDVolume],
brightnessEnabled: Defaults[.enableOSDBrightness],
keyboardBacklightEnabled: change.newValue
)
}.store(in: &cancellables)
}
private var cancellables = Set<AnyCancellable>()
@ -82,9 +140,15 @@ class SystemHUDManager {
func setup(coordinator: DynamicIslandViewCoordinator) {
self.coordinator = coordinator
if Defaults[.enableSystemHUD] {
// Initialize OSD manager
Task { @MainActor in
CustomOSDWindowManager.shared.initialize()
}
// Start observer if either HUD or OSD is enabled
if Defaults[.enableSystemHUD] || Defaults[.enableCustomOSD] {
Task { @MainActor in
await startSystemHUD()
await startSystemObserver()
self.isSetupComplete = true
}
} else {
@ -93,42 +157,55 @@ class SystemHUDManager {
}
@MainActor
private func startSystemHUD() async {
private func startSystemObserver() async {
guard let coordinator = coordinator, !isSystemOperationInProgress else { return }
isSystemOperationInProgress = true
await stopSystemHUD() // Stop any existing observer
await stopSystemObserver() // Stop any existing observer
changesObserver = SystemChangesObserver(coordinator: coordinator)
let volumeEnabled = Defaults[.enableVolumeHUD]
let brightnessEnabled = Defaults[.enableBrightnessHUD]
let keyboardBacklightEnabled = Defaults[.enableKeyboardBacklightHUD]
// Determine which controls to enable based on HUD or OSD mode
let volumeEnabled: Bool
let brightnessEnabled: Bool
let keyboardBacklightEnabled: Bool
if Defaults[.enableCustomOSD] {
volumeEnabled = Defaults[.enableOSDVolume]
brightnessEnabled = Defaults[.enableOSDBrightness]
keyboardBacklightEnabled = Defaults[.enableOSDKeyboardBacklight]
} else {
volumeEnabled = Defaults[.enableVolumeHUD]
brightnessEnabled = Defaults[.enableBrightnessHUD]
keyboardBacklightEnabled = Defaults[.enableKeyboardBacklightHUD]
}
changesObserver?.startObserving(
volumeEnabled: volumeEnabled,
brightnessEnabled: brightnessEnabled,
keyboardBacklightEnabled: keyboardBacklightEnabled
)
print("System HUD replacement started")
print("System observer started (HUD: \(Defaults[.enableSystemHUD]), OSD: \(Defaults[.enableCustomOSD]))")
isSystemOperationInProgress = false
}
@MainActor
private func stopSystemHUD() async {
private func stopSystemObserver() async {
guard !isSystemOperationInProgress else { return }
isSystemOperationInProgress = true
changesObserver?.stopObserving()
changesObserver = nil
print("System HUD replacement stopped")
print("System observer stopped")
isSystemOperationInProgress = false
}
deinit {
cancellables.removeAll()
Task { @MainActor in
await stopSystemHUD()
await stopSystemObserver()
}
}
}