MacMonitor CI/CD Pipeline / Build & Test (Intel x86_64) (push) Successful in 2m37s
169 lines
5.7 KiB
Objective-C
169 lines
5.7 KiB
Objective-C
#import "MMDisplayManager.h"
|
|
#import <IOKit/graphics/IOGraphicsLib.h>
|
|
#import <dlfcn.h>
|
|
|
|
// Private DisplayServices API signatures
|
|
typedef int (*DisplayServicesGetBrightnessFunc)(CGDirectDisplayID display, float *brightness);
|
|
typedef int (*DisplayServicesSetBrightnessFunc)(CGDirectDisplayID display, float brightness);
|
|
|
|
@implementation MMDisplayInfo
|
|
|
|
- (instancetype)initWithDisplayID:(CGDirectDisplayID)displayID
|
|
name:(NSString *)name
|
|
isBuiltin:(BOOL)isBuiltin
|
|
isMain:(BOOL)isMain
|
|
isOnline:(BOOL)isOnline
|
|
width:(uint32_t)width
|
|
height:(uint32_t)height
|
|
refreshRate:(double)refreshRate
|
|
brightness:(float)brightness {
|
|
self = [super init];
|
|
if (self) {
|
|
_displayID = displayID;
|
|
_name = [name copy] ?: @"Unknown Display";
|
|
_isBuiltin = isBuiltin;
|
|
_isMain = isMain;
|
|
_isOnline = isOnline;
|
|
_width = width;
|
|
_height = height;
|
|
_refreshRate = refreshRate;
|
|
_brightness = brightness;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation MMDisplayManager {
|
|
void *_displayServicesHandle;
|
|
DisplayServicesGetBrightnessFunc _getBrightnessFunc;
|
|
DisplayServicesSetBrightnessFunc _setBrightnessFunc;
|
|
}
|
|
|
|
+ (instancetype)sharedManager {
|
|
static MMDisplayManager *sharedInstance = nil;
|
|
static dispatch_once_t onceToken;
|
|
dispatch_once(&onceToken, ^{
|
|
sharedInstance = [[self alloc] init];
|
|
});
|
|
return sharedInstance;
|
|
}
|
|
|
|
- (instancetype)init {
|
|
self = [super init];
|
|
if (self) {
|
|
[self loadDisplayServices];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)dealloc {
|
|
if (_displayServicesHandle) {
|
|
dlclose(_displayServicesHandle);
|
|
_displayServicesHandle = NULL;
|
|
}
|
|
}
|
|
|
|
- (void)loadDisplayServices {
|
|
_displayServicesHandle = dlopen("/System/Library/PrivateFrameworks/DisplayServices.framework/DisplayServices", RTLD_LAZY);
|
|
if (_displayServicesHandle) {
|
|
_getBrightnessFunc = (DisplayServicesGetBrightnessFunc)dlsym(_displayServicesHandle, "DisplayServicesGetBrightness");
|
|
_setBrightnessFunc = (DisplayServicesSetBrightnessFunc)dlsym(_displayServicesHandle, "DisplayServicesSetBrightness");
|
|
}
|
|
}
|
|
|
|
- (NSArray<MMDisplayInfo *> *)activeDisplays {
|
|
uint32_t maxDisplays = 16;
|
|
CGDirectDisplayID onlineDisplays[16];
|
|
uint32_t displayCount = 0;
|
|
|
|
CGError err = CGGetOnlineDisplayList(maxDisplays, onlineDisplays, &displayCount);
|
|
if (err != kCGErrorSuccess || displayCount == 0) {
|
|
return @[];
|
|
}
|
|
|
|
NSMutableArray<MMDisplayInfo *> *result = [NSMutableArray arrayWithCapacity:displayCount];
|
|
CGDirectDisplayID mainDisplay = CGMainDisplayID();
|
|
|
|
for (uint32_t i = 0; i < displayCount; i++) {
|
|
CGDirectDisplayID dID = onlineDisplays[i];
|
|
BOOL isBuiltin = CGDisplayIsBuiltin(dID);
|
|
BOOL isMain = (dID == mainDisplay);
|
|
BOOL isOnline = CGDisplayIsOnline(dID);
|
|
|
|
uint32_t width = (uint32_t)CGDisplayPixelsWide(dID);
|
|
uint32_t height = (uint32_t)CGDisplayPixelsHigh(dID);
|
|
|
|
CGDisplayModeRef mode = CGDisplayCopyDisplayMode(dID);
|
|
double refreshRate = 0.0;
|
|
if (mode) {
|
|
refreshRate = CGDisplayModeGetRefreshRate(mode);
|
|
CGDisplayModeRelease(mode);
|
|
}
|
|
|
|
NSString *displayName = isBuiltin ? @"Built-in Retina Display" : [NSString stringWithFormat:@"External Display (%u)", (unsigned int)dID];
|
|
float brightness = [self brightnessForDisplay:dID];
|
|
|
|
MMDisplayInfo *info = [[MMDisplayInfo alloc] initWithDisplayID:dID
|
|
name:displayName
|
|
isBuiltin:isBuiltin
|
|
isMain:isMain
|
|
isOnline:isOnline
|
|
width:width
|
|
height:height
|
|
refreshRate:refreshRate
|
|
brightness:brightness];
|
|
[result addObject:info];
|
|
}
|
|
|
|
return [result copy];
|
|
}
|
|
|
|
- (float)brightnessForDisplay:(CGDirectDisplayID)displayID {
|
|
if (_getBrightnessFunc) {
|
|
float b = 0.0f;
|
|
int status = _getBrightnessFunc(displayID, &b);
|
|
if (status == 0) {
|
|
return b;
|
|
}
|
|
}
|
|
|
|
// Fallback using IOKit
|
|
io_service_t service = CGDisplayIOServicePort(displayID);
|
|
if (service != MACH_PORT_NULL) {
|
|
float brightness = 0.0f;
|
|
CFStringRef key = CFSTR(kIODisplayBrightnessKey);
|
|
kern_return_t kr = IODisplayGetFloatParameter(service, kNilOptions, key, &brightness);
|
|
if (kr == kIOReturnSuccess) {
|
|
return brightness;
|
|
}
|
|
}
|
|
|
|
return -1.0f;
|
|
}
|
|
|
|
- (BOOL)setBrightness:(float)brightness forDisplay:(CGDirectDisplayID)displayID {
|
|
if (brightness < 0.0f) brightness = 0.0f;
|
|
if (brightness > 1.0f) brightness = 1.0f;
|
|
|
|
if (_setBrightnessFunc) {
|
|
int status = _setBrightnessFunc(displayID, brightness);
|
|
if (status == 0) {
|
|
return YES;
|
|
}
|
|
}
|
|
|
|
io_service_t service = CGDisplayIOServicePort(displayID);
|
|
if (service != MACH_PORT_NULL) {
|
|
CFStringRef key = CFSTR(kIODisplayBrightnessKey);
|
|
kern_return_t kr = IODisplaySetFloatParameter(service, kNilOptions, key, brightness);
|
|
if (kr == kIOReturnSuccess) {
|
|
return YES;
|
|
}
|
|
}
|
|
|
|
return NO;
|
|
}
|
|
|
|
@end
|