From f79898d65e89e12b9c8e17106db81764ba1e8563 Mon Sep 17 00:00:00 2001 From: Hariharan Mudaliar Date: Thu, 25 Dec 2025 22:49:39 +0530 Subject: [PATCH] Half baked changes --- DynamicIsland.xcodeproj/project.pbxproj | 24 -------- .../helpers/DisplayServicesDynamic.swift | 57 +++++++++++++++++++ DynamicIsland/helpers/MediaChecker.swift | 3 +- .../managers/SystemMediaControllers.swift | 35 ++++++------ 4 files changed, 78 insertions(+), 41 deletions(-) create mode 100644 DynamicIsland/helpers/DisplayServicesDynamic.swift diff --git a/DynamicIsland.xcodeproj/project.pbxproj b/DynamicIsland.xcodeproj/project.pbxproj index b8ca35b..d99b143 100644 --- a/DynamicIsland.xcodeproj/project.pbxproj +++ b/DynamicIsland.xcodeproj/project.pbxproj @@ -8,9 +8,6 @@ /* Begin PBXBuildFile section */ 7E1ADF1D2EA209B1001DA867 /* SkyLightWindow in Frameworks */ = {isa = PBXBuildFile; productRef = 7E61181E2E24071E0050006C /* SkyLightWindow */; }; - 7E25ECA12E6C6C3800700E72 /* CoreBrightness.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7E25ECA02E6C6C3800700E72 /* CoreBrightness.framework */; }; - 7E25ECA32E6C6E2600700E72 /* OSD.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7E25ECA22E6C6E2600700E72 /* OSD.framework */; }; - 7E25ECA52E6C6E7800700E72 /* DisplayServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7E25ECA42E6C6E7800700E72 /* DisplayServices.framework */; }; 7E6118142E24071E0050006C /* LaunchAtLogin in Frameworks */ = {isa = PBXBuildFile; productRef = 14D032192C68F32E0096E6A1 /* LaunchAtLogin */; }; 7E6118152E24071E0050006C /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = 14D0321C2C68F3350096E6A1 /* Sparkle */; }; 7E6118162E24071E0050006C /* KeyboardShortcuts in Frameworks */ = {isa = PBXBuildFile; productRef = B18654382C6F4990000B926A /* KeyboardShortcuts */; }; @@ -28,24 +25,8 @@ 7E9911B02EFD7D1B002EDFD5 /* Reindeer.json in Resources */ = {isa = PBXBuildFile; fileRef = 7E9911AF2EFD7D1B002EDFD5 /* Reindeer.json */; }; 7EE1D73D2E6B1E0B00997219 /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7EE1D73C2E6B1E0B00997219 /* ApplicationServices.framework */; }; 7EE1D73F2E6B1E1200997219 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7EE1D73E2E6B1E1200997219 /* IOKit.framework */; }; - BA90505C953246D0AB206451 /* MediaRemoteAdapter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F4C1DD09EC134302938E84F6 /* MediaRemoteAdapter.framework */; }; - C61F69420FB64DA98516CFBC /* MediaRemoteAdapter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = F4C1DD09EC134302938E84F6 /* MediaRemoteAdapter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; /* End PBXBuildFile section */ -/* Begin PBXCopyFilesBuildPhase section */ - B933CDB48C2F42C2887A9836 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 12; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - C61F69420FB64DA98516CFBC /* MediaRemoteAdapter.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - /* Begin PBXFileReference section */ 7E25ECA02E6C6C3800700E72 /* CoreBrightness.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreBrightness.framework; path = /System/Library/PrivateFrameworks/CoreBrightness.framework; sourceTree = ""; }; 7E25ECA22E6C6E2600700E72 /* OSD.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OSD.framework; path = /System/Library/PrivateFrameworks/OSD.framework; sourceTree = ""; }; @@ -77,15 +58,11 @@ buildActionMask = 2147483647; files = ( 7E1ADF1D2EA209B1001DA867 /* SkyLightWindow in Frameworks */, - 7E25ECA12E6C6C3800700E72 /* CoreBrightness.framework in Frameworks */, 7EE1D73F2E6B1E1200997219 /* IOKit.framework in Frameworks */, 7EE1D73D2E6B1E0B00997219 /* ApplicationServices.framework in Frameworks */, - BA90505C953246D0AB206451 /* MediaRemoteAdapter.framework in Frameworks */, 7E61181C2E24071E0050006C /* MacroVisionKit in Frameworks */, 7E61181B2E24071E0050006C /* LottieUI in Frameworks */, 7E61181A2E24071E0050006C /* SwiftUIIntrospect in Frameworks */, - 7E25ECA32E6C6E2600700E72 /* OSD.framework in Frameworks */, - 7E25ECA52E6C6E7800700E72 /* DisplayServices.framework in Frameworks */, 7E6118192E24071E0050006C /* Defaults in Frameworks */, 7E6118172E24071E0050006C /* Collections in Frameworks */, 7E6118162E24071E0050006C /* KeyboardShortcuts in Frameworks */, @@ -160,7 +137,6 @@ F54406E32CD4987A00C7AFD9 /* Sources */, F54406E42CD4987A00C7AFD9 /* Frameworks */, F54406E52CD4987A00C7AFD9 /* Resources */, - B933CDB48C2F42C2887A9836 /* Embed Frameworks */, ); buildRules = ( ); diff --git a/DynamicIsland/helpers/DisplayServicesDynamic.swift b/DynamicIsland/helpers/DisplayServicesDynamic.swift new file mode 100644 index 0000000..ce42ccb --- /dev/null +++ b/DynamicIsland/helpers/DisplayServicesDynamic.swift @@ -0,0 +1,57 @@ +// +// DisplayServicesDynamic.swift +// DynamicIsland +// +// Created by AI Assistant on 25/12/2025. +// +// Lightweight wrapper that resolves DisplayServices symbols at runtime so we +// can call the private brightness APIs without linking against the framework. +// + +import Foundation +import Darwin + +final class DisplayServicesDynamic { + static let shared = DisplayServicesDynamic() + + private let handle: UnsafeMutableRawPointer? + + private typealias GetBrightnessFn = @convention(c) (UInt32, UnsafeMutablePointer) -> Int32 + private typealias SetBrightnessFn = @convention(c) (UInt32, Float) -> Int32 + + private let getBrightnessFn: GetBrightnessFn? + private let setBrightnessFn: SetBrightnessFn? + + private init() { + handle = dlopen("/System/Library/PrivateFrameworks/DisplayServices.framework/DisplayServices", RTLD_NOW) + + if handle == nil, let errorPointer = dlerror() { + let message = String(cString: errorPointer) + NSLog("⚠️ DisplayServicesDynamic: dlopen failed - %@", message) + } + + getBrightnessFn = handle.flatMap { dlsym($0, "DisplayServicesGetBrightness") } + .map { unsafeBitCast($0, to: GetBrightnessFn.self) } + + setBrightnessFn = handle.flatMap { dlsym($0, "DisplayServicesSetBrightness") } + .map { unsafeBitCast($0, to: SetBrightnessFn.self) } + } + + func setBrightness(displayID: UInt32, value: Float) -> Int32? { + guard let fn = setBrightnessFn else { return nil } + return fn(displayID, value) + } + + func getBrightness(displayID: UInt32) -> (status: Int32, value: Float)? { + guard let fn = getBrightnessFn else { return nil } + var brightness: Float = 0 + let status = fn(displayID, &brightness) + return (status, brightness) + } + + deinit { + if let handle { + dlclose(handle) + } + } +} diff --git a/DynamicIsland/helpers/MediaChecker.swift b/DynamicIsland/helpers/MediaChecker.swift index b6c5e99..b448198 100644 --- a/DynamicIsland/helpers/MediaChecker.swift +++ b/DynamicIsland/helpers/MediaChecker.swift @@ -18,7 +18,8 @@ final class MediaChecker: Sendable { func checkDeprecationStatus() async throws -> Bool { guard let scriptURL = Bundle.main.url(forResource: "mediaremote-adapter", withExtension: "pl"), let nowPlayingTestClientPath = Bundle.main.url(forResource: "MediaRemoteAdapterTestClient", withExtension: nil)?.path, - let frameworkPath = Bundle.main.privateFrameworksPath?.appending("/MediaRemoteAdapter.framework") + //let frameworkPath = Bundle.main.privateFrameworksPath?.appending("/MediaRemoteAdapter.framework") + let frameworkPath = Optional("/System/Library/PrivateFrameworks/MediaRemoteAdapter.framework") else { throw MediaCheckerError.missingResources } diff --git a/DynamicIsland/managers/SystemMediaControllers.swift b/DynamicIsland/managers/SystemMediaControllers.swift index a7de299..dd605d0 100644 --- a/DynamicIsland/managers/SystemMediaControllers.swift +++ b/DynamicIsland/managers/SystemMediaControllers.swift @@ -606,13 +606,18 @@ final class SystemBrightnessController { } private func setBrightnessViaDisplayServices(_ value: Float) -> Bool { - let status = DisplayServicesSetBrightness(displayID, value) + guard let status = DisplayServicesDynamic.shared.setBrightness(displayID: displayID, value: value) else { + return false + } if status == kIOReturnSuccess { return true } // Attempt to refresh display ID in case the main display changed displayID = CGMainDisplayID() - let retry = DisplayServicesSetBrightness(displayID, value) + guard let retry = DisplayServicesDynamic.shared.setBrightness(displayID: displayID, value: value) else { + NSLog("⚠️ DisplayServicesSetBrightness unavailable after display refresh") + return false + } if retry != kIOReturnSuccess { NSLog("⚠️ DisplayServicesSetBrightness failed: \(retry)") return false @@ -621,17 +626,21 @@ final class SystemBrightnessController { } private func getBrightnessViaDisplayServices() -> Float? { - var brightness: Float = 0 - let status = DisplayServicesGetBrightness(displayID, &brightness) - if status == kIOReturnSuccess { - return brightness + guard let result = DisplayServicesDynamic.shared.getBrightness(displayID: displayID) else { + return nil + } + if result.status == kIOReturnSuccess { + return result.value } displayID = CGMainDisplayID() - let retry = DisplayServicesGetBrightness(displayID, &brightness) - if retry == kIOReturnSuccess { - return brightness + guard let retry = DisplayServicesDynamic.shared.getBrightness(displayID: displayID) else { + NSLog("⚠️ DisplayServicesGetBrightness unavailable after display refresh") + return nil } - NSLog("⚠️ DisplayServicesGetBrightness failed: \(retry)") + if retry.status == kIOReturnSuccess { + return retry.value + } + NSLog("⚠️ DisplayServicesGetBrightness failed: \(retry.status)") return nil } @@ -655,9 +664,3 @@ final class SystemBrightnessController { observers.forEach { DistributedNotificationCenter.default().removeObserver($0) } } } - -@_silgen_name("DisplayServicesGetBrightness") -private func DisplayServicesGetBrightness(_ display: UInt32, _ brightness: UnsafeMutablePointer) -> Int32 - -@_silgen_name("DisplayServicesSetBrightness") -private func DisplayServicesSetBrightness(_ display: UInt32, _ brightness: Float) -> Int32