mirror of
https://github.com/FBukovina/Atoll.git
synced 2026-10-27 15:14:33 +00:00
Update per display windows for betterdisplay
This commit is contained in:
parent
cead5f9ce8
commit
12f8bc28ba
4 changed files with 99 additions and 59 deletions
|
|
@ -8747,6 +8747,9 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Disabled while BetterDisplay integration is active — BetterDisplay uses Cmd+Brightness keys for its own controls." : {
|
||||
|
||||
},
|
||||
"Discrete transitions snap between Green (0–60%), Yellow (60–85%), and Red (85–100%)." : {
|
||||
"comment" : "A description of how the color-coded progress bars work when not using smooth transitions.",
|
||||
|
|
|
|||
|
|
@ -1384,8 +1384,7 @@ private struct HUDAndOSDSettingsView: View {
|
|||
@Default(.enableVolumeHUD) var enableVolumeHUD
|
||||
@Default(.enableBrightnessHUD) var enableBrightnessHUD
|
||||
@Default(.enableKeyboardBacklightHUD) var enableKeyboardBacklightHUD
|
||||
|
||||
// Vertical HUD Props
|
||||
@Default(.enableBetterDisplayIntegration) var enableBetterDisplayIntegration
|
||||
@Default(.verticalHUDShowValue) var verticalHUDShowValue
|
||||
@Default(.verticalHUDInteractive) var verticalHUDInteractive
|
||||
@Default(.verticalHUDHeight) var verticalHUDHeight
|
||||
|
|
@ -1621,7 +1620,7 @@ private struct HUDAndOSDSettingsView: View {
|
|||
}
|
||||
case .vertical:
|
||||
Form {
|
||||
if !accessibilityPermission.isAuthorized {
|
||||
if !accessibilityPermission.isAuthorized && !enableBetterDisplayIntegration {
|
||||
Section {
|
||||
SettingsPermissionCallout(
|
||||
message: "Accessibility permission is needed to intercept system controls for the Vertical HUD.",
|
||||
|
|
@ -1637,11 +1636,13 @@ private struct HUDAndOSDSettingsView: View {
|
|||
}
|
||||
}
|
||||
|
||||
if accessibilityPermission.isAuthorized {
|
||||
if accessibilityPermission.isAuthorized || enableBetterDisplayIntegration {
|
||||
Section {
|
||||
Toggle("Volume HUD", isOn: $enableVolumeHUD)
|
||||
Toggle("Brightness HUD", isOn: $enableBrightnessHUD)
|
||||
Toggle("Keyboard Backlight HUD", isOn: $enableKeyboardBacklightHUD)
|
||||
.disabled(enableBetterDisplayIntegration)
|
||||
.help(enableBetterDisplayIntegration ? "Disabled while BetterDisplay integration is active — BetterDisplay uses Cmd+Brightness keys for its own controls." : "")
|
||||
} header: {
|
||||
Text("Controls")
|
||||
} footer: {
|
||||
|
|
@ -1736,7 +1737,7 @@ private struct HUDAndOSDSettingsView: View {
|
|||
|
||||
case .circular:
|
||||
Form {
|
||||
if !accessibilityPermission.isAuthorized {
|
||||
if !accessibilityPermission.isAuthorized && !enableBetterDisplayIntegration {
|
||||
Section {
|
||||
SettingsPermissionCallout(
|
||||
message: "Accessibility permission is needed to intercept system controls for the Circular HUD.",
|
||||
|
|
@ -1752,11 +1753,13 @@ private struct HUDAndOSDSettingsView: View {
|
|||
}
|
||||
}
|
||||
|
||||
if accessibilityPermission.isAuthorized {
|
||||
if accessibilityPermission.isAuthorized || enableBetterDisplayIntegration {
|
||||
Section {
|
||||
Toggle("Volume HUD", isOn: $enableVolumeHUD)
|
||||
Toggle("Brightness HUD", isOn: $enableBrightnessHUD)
|
||||
Toggle("Keyboard Backlight HUD", isOn: $enableKeyboardBacklightHUD)
|
||||
.disabled(enableBetterDisplayIntegration)
|
||||
.help(enableBetterDisplayIntegration ? "Disabled while BetterDisplay integration is active — BetterDisplay uses Cmd+Brightness keys for its own controls." : "")
|
||||
} header: {
|
||||
Text("Controls")
|
||||
} footer: {
|
||||
|
|
@ -2020,6 +2023,7 @@ struct HUD: View {
|
|||
@Default(.enableVolumeHUD) var enableVolumeHUD
|
||||
@Default(.enableBrightnessHUD) var enableBrightnessHUD
|
||||
@Default(.enableKeyboardBacklightHUD) var enableKeyboardBacklightHUD
|
||||
@Default(.enableBetterDisplayIntegration) var enableBetterDisplayIntegration
|
||||
@Default(.systemHUDSensitivity) var systemHUDSensitivity
|
||||
@ObservedObject var coordinator = DynamicIslandViewCoordinator.shared
|
||||
@ObservedObject private var accessibilityPermission = AccessibilityPermissionStore.shared
|
||||
|
|
@ -2038,7 +2042,7 @@ struct HUD: View {
|
|||
|
||||
var body: some View {
|
||||
Form {
|
||||
if !hasAccessibilityPermission {
|
||||
if !hasAccessibilityPermission && !enableBetterDisplayIntegration {
|
||||
Section {
|
||||
SettingsPermissionCallout(
|
||||
message: "Accessibility permission lets Dynamic Island replace the native volume, brightness, and keyboard HUDs.",
|
||||
|
|
@ -2052,11 +2056,13 @@ struct HUD: View {
|
|||
|
||||
|
||||
|
||||
if enableSystemHUD && !Defaults[.enableCustomOSD] && hasAccessibilityPermission {
|
||||
if enableSystemHUD && !Defaults[.enableCustomOSD] && (hasAccessibilityPermission || enableBetterDisplayIntegration) {
|
||||
Section {
|
||||
Toggle("Volume HUD", isOn: $enableVolumeHUD)
|
||||
Toggle("Brightness HUD", isOn: $enableBrightnessHUD)
|
||||
Toggle("Keyboard Backlight HUD", isOn: $enableKeyboardBacklightHUD)
|
||||
.disabled(enableBetterDisplayIntegration)
|
||||
.help(enableBetterDisplayIntegration ? "Disabled while BetterDisplay integration is active \u{2014} BetterDisplay uses Cmd+Brightness keys for its own controls." : "")
|
||||
} header: {
|
||||
Text("Controls")
|
||||
} footer: {
|
||||
|
|
@ -6702,6 +6708,7 @@ struct CustomOSDSettings: View {
|
|||
@Default(.enableOSDVolume) var enableOSDVolume
|
||||
@Default(.enableOSDBrightness) var enableOSDBrightness
|
||||
@Default(.enableOSDKeyboardBacklight) var enableOSDKeyboardBacklight
|
||||
@Default(.enableBetterDisplayIntegration) var enableBetterDisplayIntegration
|
||||
@Default(.osdMaterial) var osdMaterial
|
||||
@Default(.osdLiquidGlassCustomizationMode) var osdLiquidGlassCustomizationMode
|
||||
@Default(.osdLiquidGlassVariant) var osdLiquidGlassVariant
|
||||
|
|
@ -6744,7 +6751,7 @@ struct CustomOSDSettings: View {
|
|||
|
||||
var body: some View {
|
||||
Form {
|
||||
if !hasAccessibilityPermission {
|
||||
if !hasAccessibilityPermission && !enableBetterDisplayIntegration {
|
||||
Section {
|
||||
SettingsPermissionCallout(
|
||||
message: "Accessibility permission is needed to intercept system controls for the Custom OSD.",
|
||||
|
|
@ -6756,7 +6763,7 @@ struct CustomOSDSettings: View {
|
|||
}
|
||||
}
|
||||
|
||||
if hasAccessibilityPermission {
|
||||
if hasAccessibilityPermission || enableBetterDisplayIntegration {
|
||||
Section {
|
||||
Toggle("Volume OSD", isOn: $enableOSDVolume)
|
||||
.settingsHighlight(id: highlightID("Volume OSD"))
|
||||
|
|
@ -6764,6 +6771,8 @@ struct CustomOSDSettings: View {
|
|||
.settingsHighlight(id: highlightID("Brightness OSD"))
|
||||
Toggle("Keyboard Backlight OSD", isOn: $enableOSDKeyboardBacklight)
|
||||
.settingsHighlight(id: highlightID("Keyboard Backlight OSD"))
|
||||
.disabled(enableBetterDisplayIntegration)
|
||||
.help(enableBetterDisplayIntegration ? "Disabled while BetterDisplay integration is active \u{2014} BetterDisplay uses Cmd+Brightness keys for its own controls." : "")
|
||||
} header: {
|
||||
Text("Controls")
|
||||
} footer: {
|
||||
|
|
|
|||
|
|
@ -190,6 +190,8 @@ final class BetterDisplayManager: ObservableObject {
|
|||
return
|
||||
}
|
||||
|
||||
NSLog("📺 BetterDisplay OSD raw payload: \(notificationString)")
|
||||
|
||||
do {
|
||||
let osd = try JSONDecoder().decode(
|
||||
BetterDisplayOSDNotification.self,
|
||||
|
|
@ -208,21 +210,20 @@ final class BetterDisplayManager: ObservableObject {
|
|||
let targetScreen = resolveScreen(for: osd.displayID)
|
||||
let isExternalDisplay = isExternal(displayID: osd.displayID)
|
||||
|
||||
NSLog("📺 BetterDisplay OSD: target=\(osd.controlTarget ?? "nil") displayID=\(osd.displayID.map(String.init) ?? "nil") resolvedScreen=\(targetScreen?.localizedName ?? "nil") isExternal=\(isExternalDisplay) value=\(osd.value ?? -1)")
|
||||
|
||||
switch category {
|
||||
case .brightness:
|
||||
guard Defaults[.enableBrightnessHUD] else { return }
|
||||
let icon = isExternalDisplay ? "display" : nil
|
||||
dispatchBrightnessHUD(value: normalizedValue, customSymbol: icon, onScreen: targetScreen)
|
||||
|
||||
case .volume:
|
||||
guard Defaults[.enableVolumeHUD] else { return }
|
||||
let isMuted = osd.controlTarget == "mute" || osd.systemIconID == 4
|
||||
dispatchVolumeHUD(value: normalizedValue, isMuted: isMuted, onScreen: targetScreen)
|
||||
|
||||
case .other:
|
||||
// For unsupported control targets (contrast, gamma, temperature, etc.),
|
||||
// show a generic brightness-style HUD if the user has brightness HUD enabled
|
||||
guard Defaults[.enableBrightnessHUD] else { return }
|
||||
let icon = isExternalDisplay ? "display" : osd.customSymbol
|
||||
dispatchBrightnessHUD(value: normalizedValue, customSymbol: icon, onScreen: targetScreen)
|
||||
}
|
||||
|
|
@ -281,14 +282,26 @@ final class BetterDisplayManager: ObservableObject {
|
|||
|
||||
/// Resolve a BetterDisplay `displayID` (CGDirectDisplayID) to the matching NSScreen, if any.
|
||||
private func resolveScreen(for displayID: Int?) -> NSScreen? {
|
||||
guard let displayID else { return nil }
|
||||
guard let displayID else {
|
||||
NSLog("📺 BetterDisplay resolveScreen: displayID is nil, falling back to all screens")
|
||||
return nil
|
||||
}
|
||||
let target = UInt32(displayID)
|
||||
return NSScreen.screens.first { screen in
|
||||
let availableScreens = NSScreen.screens.map { screen -> (String, UInt32) in
|
||||
let num = (screen.deviceDescription[NSDeviceDescriptionKey("NSScreenNumber")] as? NSNumber)?.uint32Value ?? 0
|
||||
return (screen.localizedName, num)
|
||||
}
|
||||
NSLog("📺 BetterDisplay resolveScreen: looking for displayID=\(displayID) (UInt32=\(target)) among screens: \(availableScreens)")
|
||||
let matched = NSScreen.screens.first { screen in
|
||||
guard let screenNumber = screen.deviceDescription[NSDeviceDescriptionKey("NSScreenNumber")] as? NSNumber else {
|
||||
return false
|
||||
}
|
||||
return screenNumber.uint32Value == target
|
||||
}
|
||||
if matched == nil {
|
||||
NSLog("📺 BetterDisplay resolveScreen: no match found for displayID=\(displayID), HUD will show on all screens")
|
||||
}
|
||||
return matched
|
||||
}
|
||||
|
||||
/// Whether the given displayID refers to an external (non-built-in) display.
|
||||
|
|
|
|||
|
|
@ -108,70 +108,76 @@ class SystemHUDManager {
|
|||
}.store(in: &cancellables)
|
||||
|
||||
// Observe individual HUD toggles
|
||||
Defaults.publisher(.enableVolumeHUD, options: []).sink { [weak self] change in
|
||||
Defaults.publisher(.enableVolumeHUD, options: []).sink { [weak self] _ in
|
||||
guard let self = self, self.isSetupComplete, self.requiresSystemToggleHandling else {
|
||||
return
|
||||
}
|
||||
let flags = self.resolvedControlFlags()
|
||||
self.changesObserver?.update(
|
||||
volumeEnabled: change.newValue,
|
||||
brightnessEnabled: Defaults[.enableBrightnessHUD],
|
||||
keyboardBacklightEnabled: Defaults[.enableKeyboardBacklightHUD]
|
||||
volumeEnabled: flags.volume,
|
||||
brightnessEnabled: flags.brightness,
|
||||
keyboardBacklightEnabled: flags.backlight
|
||||
)
|
||||
}.store(in: &cancellables)
|
||||
|
||||
Defaults.publisher(.enableBrightnessHUD, options: []).sink { [weak self] change in
|
||||
Defaults.publisher(.enableBrightnessHUD, options: []).sink { [weak self] _ in
|
||||
guard let self = self, self.isSetupComplete, self.requiresSystemToggleHandling else {
|
||||
return
|
||||
}
|
||||
let flags = self.resolvedControlFlags()
|
||||
self.changesObserver?.update(
|
||||
volumeEnabled: Defaults[.enableVolumeHUD],
|
||||
brightnessEnabled: change.newValue,
|
||||
keyboardBacklightEnabled: Defaults[.enableKeyboardBacklightHUD]
|
||||
volumeEnabled: flags.volume,
|
||||
brightnessEnabled: flags.brightness,
|
||||
keyboardBacklightEnabled: flags.backlight
|
||||
)
|
||||
}.store(in: &cancellables)
|
||||
|
||||
Defaults.publisher(.enableKeyboardBacklightHUD, options: []).sink { [weak self] change in
|
||||
Defaults.publisher(.enableKeyboardBacklightHUD, options: []).sink { [weak self] _ in
|
||||
guard let self = self, self.isSetupComplete, self.requiresSystemToggleHandling else {
|
||||
return
|
||||
}
|
||||
let flags = self.resolvedControlFlags()
|
||||
self.changesObserver?.update(
|
||||
volumeEnabled: Defaults[.enableVolumeHUD],
|
||||
brightnessEnabled: Defaults[.enableBrightnessHUD],
|
||||
keyboardBacklightEnabled: change.newValue
|
||||
volumeEnabled: flags.volume,
|
||||
brightnessEnabled: flags.brightness,
|
||||
keyboardBacklightEnabled: flags.backlight
|
||||
)
|
||||
}.store(in: &cancellables)
|
||||
|
||||
// Observe individual OSD toggles
|
||||
Defaults.publisher(.enableOSDVolume, options: []).sink { [weak self] change in
|
||||
Defaults.publisher(.enableOSDVolume, options: []).sink { [weak self] _ in
|
||||
guard let self = self, self.isSetupComplete, Defaults[.enableCustomOSD] else {
|
||||
return
|
||||
}
|
||||
let flags = self.resolvedControlFlags()
|
||||
self.changesObserver?.update(
|
||||
volumeEnabled: change.newValue,
|
||||
brightnessEnabled: Defaults[.enableOSDBrightness],
|
||||
keyboardBacklightEnabled: Defaults[.enableOSDKeyboardBacklight]
|
||||
volumeEnabled: flags.volume,
|
||||
brightnessEnabled: flags.brightness,
|
||||
keyboardBacklightEnabled: flags.backlight
|
||||
)
|
||||
}.store(in: &cancellables)
|
||||
|
||||
Defaults.publisher(.enableOSDBrightness, options: []).sink { [weak self] change in
|
||||
Defaults.publisher(.enableOSDBrightness, options: []).sink { [weak self] _ in
|
||||
guard let self = self, self.isSetupComplete, Defaults[.enableCustomOSD] else {
|
||||
return
|
||||
}
|
||||
let flags = self.resolvedControlFlags()
|
||||
self.changesObserver?.update(
|
||||
volumeEnabled: Defaults[.enableOSDVolume],
|
||||
brightnessEnabled: change.newValue,
|
||||
keyboardBacklightEnabled: Defaults[.enableOSDKeyboardBacklight]
|
||||
volumeEnabled: flags.volume,
|
||||
brightnessEnabled: flags.brightness,
|
||||
keyboardBacklightEnabled: flags.backlight
|
||||
)
|
||||
}.store(in: &cancellables)
|
||||
|
||||
Defaults.publisher(.enableOSDKeyboardBacklight, options: []).sink { [weak self] change in
|
||||
Defaults.publisher(.enableOSDKeyboardBacklight, options: []).sink { [weak self] _ in
|
||||
guard let self = self, self.isSetupComplete, Defaults[.enableCustomOSD] else {
|
||||
return
|
||||
}
|
||||
let flags = self.resolvedControlFlags()
|
||||
self.changesObserver?.update(
|
||||
volumeEnabled: Defaults[.enableOSDVolume],
|
||||
brightnessEnabled: Defaults[.enableOSDBrightness],
|
||||
keyboardBacklightEnabled: change.newValue
|
||||
volumeEnabled: flags.volume,
|
||||
brightnessEnabled: flags.brightness,
|
||||
keyboardBacklightEnabled: flags.backlight
|
||||
)
|
||||
}.store(in: &cancellables)
|
||||
|
||||
|
|
@ -214,22 +220,13 @@ class SystemHUDManager {
|
|||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func startSystemObserver() async {
|
||||
guard let coordinator = coordinator, !isSystemOperationInProgress else { return }
|
||||
|
||||
isSystemOperationInProgress = true
|
||||
await stopSystemObserver() // Stop any existing observer
|
||||
|
||||
changesObserver = SystemChangesObserver(coordinator: coordinator)
|
||||
|
||||
// Determine which controls to enable based on HUD or OSD mode
|
||||
let volumeEnabled: Bool
|
||||
let brightnessEnabled: Bool
|
||||
/// Resolves the effective control flags, applying BetterDisplay overrides.
|
||||
private func resolvedControlFlags() -> (volume: Bool, brightness: Bool, backlight: Bool) {
|
||||
var volumeEnabled: Bool
|
||||
var brightnessEnabled: Bool
|
||||
var keyboardBacklightEnabled: Bool
|
||||
|
||||
|
||||
if Defaults[.enableCircularHUD] || Defaults[.enableVerticalHUD] {
|
||||
// Respect per-control toggles so the system HUD can handle disabled events
|
||||
volumeEnabled = Defaults[.enableVolumeHUD]
|
||||
brightnessEnabled = Defaults[.enableBrightnessHUD]
|
||||
keyboardBacklightEnabled = Defaults[.enableKeyboardBacklightHUD]
|
||||
|
|
@ -243,22 +240,40 @@ class SystemHUDManager {
|
|||
keyboardBacklightEnabled = Defaults[.enableKeyboardBacklightHUD]
|
||||
}
|
||||
|
||||
// When BetterDisplay integration is on, disable Cmd+Brightness key interception
|
||||
// because BetterDisplay uses Cmd+F1/F2 for its own display controls.
|
||||
// When BetterDisplay integration is on, stop intercepting brightness and
|
||||
// Cmd+Brightness keys so BetterDisplay receives them and sends OSD notifications.
|
||||
if Defaults[.enableBetterDisplayIntegration] {
|
||||
brightnessEnabled = false
|
||||
keyboardBacklightEnabled = false
|
||||
}
|
||||
|
||||
return (volumeEnabled, brightnessEnabled, keyboardBacklightEnabled)
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func startSystemObserver() async {
|
||||
guard let coordinator = coordinator, !isSystemOperationInProgress else { return }
|
||||
|
||||
isSystemOperationInProgress = true
|
||||
|
||||
// Stop any existing observer directly (cannot call stopSystemObserver()
|
||||
// because isSystemOperationInProgress is already true).
|
||||
changesObserver?.stopObserving()
|
||||
changesObserver = nil
|
||||
|
||||
changesObserver = SystemChangesObserver(coordinator: coordinator)
|
||||
|
||||
let flags = resolvedControlFlags()
|
||||
changesObserver?.startObserving(
|
||||
volumeEnabled: volumeEnabled,
|
||||
brightnessEnabled: brightnessEnabled,
|
||||
keyboardBacklightEnabled: keyboardBacklightEnabled
|
||||
volumeEnabled: flags.volume,
|
||||
brightnessEnabled: flags.brightness,
|
||||
keyboardBacklightEnabled: flags.backlight
|
||||
)
|
||||
|
||||
// Force disable system HUD to ensure no duplicates
|
||||
SystemOSDManager.disableSystemHUD()
|
||||
|
||||
print("System observer started (HUD: \(Defaults[.enableSystemHUD]), OSD: \(Defaults[.enableCustomOSD]), Vertical: \(Defaults[.enableVerticalHUD]))")
|
||||
print("System observer started (HUD: \(Defaults[.enableSystemHUD]), OSD: \(Defaults[.enableCustomOSD]), Vertical: \(Defaults[.enableVerticalHUD]), BD: \(Defaults[.enableBetterDisplayIntegration]))")
|
||||
isSystemOperationInProgress = false
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue