Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions BoringNotchXPCHelper/BoringNotchXPCHelper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -171,14 +171,14 @@ class BoringNotchXPCHelper: NSObject, BoringNotchXPCHelperProtocol {
reply(displayServicesGetBrightness(displayID: displayID, out: &b) || ioServiceFor(displayID: displayID) != nil)
}

@objc func currentScreenBrightness(with reply: @escaping (NSNumber?) -> Void) {
let displayID = brightnessDisplayID()
@objc func currentScreenBrightness(forDisplayID displayID: NSNumber?, with reply: @escaping (NSNumber?) -> Void) {
let targetDisplayID = displayID.map { CGDirectDisplayID($0.uint32Value) } ?? brightnessDisplayID()
var b: Float = 0
if displayServicesGetBrightness(displayID: displayID, out: &b) {
if displayServicesGetBrightness(displayID: targetDisplayID, out: &b) {
reply(NSNumber(value: b))
return
}
if let io = ioServiceFor(displayID: displayID) {
if let io = ioServiceFor(displayID: targetDisplayID) {
var level: Float = 0
if IODisplayGetFloatParameter(io, 0, kIODisplayBrightnessKey as CFString, &level) == kIOReturnSuccess {
IOObjectRelease(io)
Expand All @@ -190,14 +190,14 @@ class BoringNotchXPCHelper: NSObject, BoringNotchXPCHelperProtocol {
reply(nil)
}

@objc func setScreenBrightness(_ value: Float, with reply: @escaping (Bool) -> Void) {
@objc func setScreenBrightness(_ value: Float, forDisplayID displayID: NSNumber?, with reply: @escaping (Bool) -> Void) {
let targetDisplayID = displayID.map { CGDirectDisplayID($0.uint32Value) } ?? brightnessDisplayID()
let clamped = max(0, min(1, value))
let displayID = brightnessDisplayID()
if displayServicesSetBrightness(displayID: displayID, value: clamped) {
if displayServicesSetBrightness(displayID: targetDisplayID, value: clamped) {
reply(true)
return
}
if let io = ioServiceFor(displayID: displayID) {
if let io = ioServiceFor(displayID: targetDisplayID) {
let ok = IODisplaySetFloatParameter(io, 0, kIODisplayBrightnessKey as CFString, clamped) == kIOReturnSuccess
IOObjectRelease(io)
reply(ok)
Expand Down
4 changes: 2 additions & 2 deletions BoringNotchXPCHelper/BoringNotchXPCHelperProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ final class BNLunarBrightnessEvent: NSObject, NSSecureCoding {
func isScreenBrightnessAvailable(with reply: @escaping (Bool) -> Void)
// returns the displayID that will be used for built-in brightness operations (main or internal fallback)
func displayIDForBrightness(with reply: @escaping (NSNumber?) -> Void)
func currentScreenBrightness(with reply: @escaping (NSNumber?) -> Void)
func setScreenBrightness(_ value: Float, with reply: @escaping (Bool) -> Void)
func currentScreenBrightness(forDisplayID displayID: NSNumber?, with reply: @escaping (NSNumber?) -> Void)
func setScreenBrightness(_ value: Float, forDisplayID displayID: NSNumber?, with reply: @escaping (Bool) -> Void)
func adjustScreenBrightness(by value: Float, with reply: @escaping (Bool) -> Void)
// Lunar brightness events (performed by the helper)
func isLunarAvailable(with reply: @escaping (Bool) -> Void)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ final class BNLunarBrightnessEvent: NSObject, NSSecureCoding {
func isScreenBrightnessAvailable(with reply: @escaping (Bool) -> Void)
// returns the displayID that will be used for built-in brightness operations (main or internal fallback)
func displayIDForBrightness(with reply: @escaping (NSNumber?) -> Void)
func currentScreenBrightness(with reply: @escaping (NSNumber?) -> Void)
func setScreenBrightness(_ value: Float, with reply: @escaping (Bool) -> Void)
func currentScreenBrightness(forDisplayID displayID: NSNumber?, with reply: @escaping (NSNumber?) -> Void)
func setScreenBrightness(_ value: Float, forDisplayID displayID: NSNumber?, with reply: @escaping (Bool) -> Void)
func adjustScreenBrightness(by value: Float, with reply: @escaping (Bool) -> Void)
// Lunar brightness events (performed by the helper)
func isLunarAvailable(with reply: @escaping (Bool) -> Void)
Expand Down
9 changes: 4 additions & 5 deletions boringNotch/XPCHelperClient/XPCHelperClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -241,13 +241,13 @@ final class XPCHelperClient: NSObject {
}
}

nonisolated func currentScreenBrightness() async -> Float? {
nonisolated func currentScreenBrightness(displayID: CGDirectDisplayID? = nil) async -> Float? {
do {
let service = await MainActor.run {
ensureRemoteService()
}
let result: NSNumber? = try await service.withContinuation { service, continuation in
service.currentScreenBrightness { value in
service.currentScreenBrightness(forDisplayID: displayID.map { NSNumber(value: $0) }) { value in
continuation.resume(returning: value)
}
}
Expand All @@ -274,13 +274,13 @@ final class XPCHelperClient: NSObject {
}
}

nonisolated func setScreenBrightness(_ value: Float) async -> Bool {
nonisolated func setScreenBrightness(_ value: Float, displayID: CGDirectDisplayID? = nil) async -> Bool {
do {
let service = await MainActor.run {
ensureRemoteService()
}
return try await service.withContinuation { service, continuation in
service.setScreenBrightness(value) { success in
service.setScreenBrightness(value, forDisplayID: displayID.map { NSNumber(value: $0) }) { success in
continuation.resume(returning: success)
}
}
Expand Down Expand Up @@ -366,4 +366,3 @@ final class XPCHelperClient: NSObject {
}
}
}

52 changes: 43 additions & 9 deletions boringNotch/components/OSD/Managers/XPC/BrightnessManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// Created by JeanLouis on 08/22/24.

import AppKit
import CoreGraphics

final class BrightnessManager: ObservableObject {
static let shared = BrightnessManager()
Expand All @@ -18,10 +19,16 @@ final class BrightnessManager: ObservableObject {
private init() { refresh() }

/// Determine which screen UUID should be used for brightness OSDs
/// when the builtin source is selected. This mirrors the logic in the
/// XPC helper, which chooses the menu-bar display if it supports brightness and
/// otherwise falls back to an internal panel.
/// when the built-in source is selected.
/// Prefer the display being acted on, and only fall back to the helper's
/// built-in brightness display resolution if needed.
func brightnessTargetUUID() async -> String? {
if let displayID = await MainActor.run(body: { targetDisplayID() }),
let screen = NSScreen.screens.first(where: { $0.cgDisplayID == displayID })
{
return screen.displayUUID
}

if let displayID = await client.displayIDForBrightness() {
if let screen = NSScreen.screens.first(where: { $0.cgDisplayID == displayID }) {
return screen.displayUUID
Expand All @@ -32,19 +39,44 @@ final class BrightnessManager: ObservableObject {

var shouldShowOverlay: Bool { Date().timeIntervalSince(lastChangeAt) < visibleDuration }

@MainActor
private func targetDisplayID() -> CGDirectDisplayID? {
if let mouseDisplayID = NSScreen.screenWithMouse?.displayID {
return mouseDisplayID
}

if let selectedScreen = NSScreen.screen(withUUID: BoringViewCoordinator.shared.selectedScreenUUID),
let selectedDisplayID = selectedScreen.displayID
{
return selectedDisplayID
}

if let preferredUUID = BoringViewCoordinator.shared.preferredScreenUUID,
let preferredScreen = NSScreen.screen(withUUID: preferredUUID),
let preferredDisplayID = preferredScreen.displayID
{
return preferredDisplayID
}

return NSScreen.main?.displayID ?? NSScreen.screens.first?.displayID
}

func refresh() {
Task { @MainActor in
if let current = await client.currentScreenBrightness() {
if let current = await client.currentScreenBrightness(displayID: targetDisplayID()) {
publish(brightness: current, touchDate: false)
}
}
}

@MainActor func setRelative(delta: Float) {
Task { @MainActor in
let ok = await client.adjustScreenBrightness(by: delta)
let displayID = targetDisplayID()
let starting = await client.currentScreenBrightness(displayID: displayID) ?? rawBrightness
let target = max(0, min(1, starting + delta))
let ok = await client.setScreenBrightness(target, displayID: displayID)
if ok {
let current = await client.currentScreenBrightness() ?? rawBrightness
let current = await client.currentScreenBrightness(displayID: displayID) ?? target
publish(brightness: current, touchDate: true)

let targetUUID = await brightnessTargetUUID()
Expand All @@ -58,12 +90,14 @@ final class BrightnessManager: ObservableObject {
func setAbsolute(value: Float) {
let clamped = max(0, min(1, value))
Task { @MainActor in
let ok = await client.setScreenBrightness(clamped)
let displayID = targetDisplayID()
let ok = await client.setScreenBrightness(clamped, displayID: displayID)
if ok {
publish(brightness: clamped, touchDate: true)
let current = await client.currentScreenBrightness(displayID: displayID) ?? clamped
publish(brightness: current, touchDate: true)
// optionally show peek when user uses slider/controls
let targetUUID = await brightnessTargetUUID()
BoringViewCoordinator.shared.toggleSneakPeek(status: true, type: .brightness, value: CGFloat(clamped), targetScreenUUID: targetUUID)
BoringViewCoordinator.shared.toggleSneakPeek(status: true, type: .brightness, value: CGFloat(current), targetScreenUUID: targetUUID)
} else {
refresh()
}
Expand Down
10 changes: 8 additions & 2 deletions boringNotch/extensions/NSScreen+UUID.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,18 @@ import AppKit
import CoreGraphics

extension NSScreen {
var displayID: CGDirectDisplayID? {
guard let number = deviceDescription[NSDeviceDescriptionKey("NSScreenNumber")] as? NSNumber else {
return nil
}
return CGDirectDisplayID(number.uint32Value)
}

/// Returns a persistent UUID for this display
var displayUUID: String? {
guard let number = deviceDescription[NSDeviceDescriptionKey("NSScreenNumber")] as? NSNumber else {
guard let displayID else {
return nil
}
let displayID = CGDirectDisplayID(number.uint32Value)
guard let uuid = CGDisplayCreateUUIDFromDisplayID(displayID) else {
return nil
}
Expand Down