Core optimization: - Use CGDisplayStream instead of per-frame CGDisplayCreateImage - Push model: CPU sleeps when screen is static (condition_variable wait) - IOSurface capture avoids expensive image creation per frame - ~47% CPU reduction during active remote desktop (45% → 24%) Additional optimizations: - vImageVerticalReflect (SIMD) replaces manual row-by-row flip - Cache CGColorSpaceRef to avoid per-frame creation/release - Cache tempBuffer to avoid per-frame memory allocation - Throttle getCursorTypeIndex to 250ms (Accessibility API is expensive) Bug fixes: - Fix unreliable screen capture permission check (use actual capture test) - Improve permission logging Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
127 lines
4.4 KiB
Plaintext
127 lines
4.4 KiB
Plaintext
#import "Permissions.h"
|
|
#import <Cocoa/Cocoa.h>
|
|
#import <CoreGraphics/CoreGraphics.h>
|
|
#import <ApplicationServices/ApplicationServices.h>
|
|
|
|
bool Permissions::checkScreenCapture() {
|
|
// macOS 10.15+ requires screen recording permission
|
|
if (@available(macOS 10.15, *)) {
|
|
// CGPreflightScreenCaptureAccess() is unreliable - it can return false
|
|
// even when permission is granted (especially after code re-signing).
|
|
// Instead, actually try to capture the screen to verify permission.
|
|
|
|
CGDirectDisplayID displayID = CGMainDisplayID();
|
|
CGImageRef image = CGDisplayCreateImage(displayID);
|
|
|
|
if (image != NULL) {
|
|
// Got an image - permission is granted
|
|
// Additional check: verify image has actual content (not blank)
|
|
size_t width = CGImageGetWidth(image);
|
|
size_t height = CGImageGetHeight(image);
|
|
CGImageRelease(image);
|
|
|
|
if (width > 0 && height > 0) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Failed to capture - permission not granted or display issue
|
|
// Fall back to preflight check for triggering dialog
|
|
return CGPreflightScreenCaptureAccess();
|
|
}
|
|
|
|
// Before 10.15, no permission needed
|
|
return true;
|
|
}
|
|
|
|
void Permissions::requestScreenCapture() {
|
|
if (@available(macOS 10.15, *)) {
|
|
// Trigger system permission dialog
|
|
CGRequestScreenCaptureAccess();
|
|
}
|
|
}
|
|
|
|
bool Permissions::checkAccessibility() {
|
|
return AXIsProcessTrusted();
|
|
}
|
|
|
|
void Permissions::requestAccessibility() {
|
|
NSDictionary *options = @{
|
|
(__bridge id)kAXTrustedCheckOptionPrompt: @YES
|
|
};
|
|
AXIsProcessTrustedWithOptions((__bridge CFDictionaryRef)options);
|
|
}
|
|
|
|
void Permissions::openScreenCaptureSettings() {
|
|
if (@available(macOS 10.15, *)) {
|
|
// Open System Preferences -> Security & Privacy -> Privacy -> Screen Recording
|
|
NSURL *url = [NSURL URLWithString:@"x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture"];
|
|
[[NSWorkspace sharedWorkspace] openURL:url];
|
|
}
|
|
}
|
|
|
|
void Permissions::openAccessibilitySettings() {
|
|
// Open System Preferences -> Security & Privacy -> Privacy -> Accessibility
|
|
NSURL *url = [NSURL URLWithString:@"x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility"];
|
|
[[NSWorkspace sharedWorkspace] openURL:url];
|
|
}
|
|
|
|
bool Permissions::checkFullDiskAccess() {
|
|
// There's no official API to check Full Disk Access.
|
|
// Try to actually read a protected file that requires FDA.
|
|
|
|
NSString* testPath = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Safari/Bookmarks.plist"];
|
|
|
|
NSFileManager* fm = [NSFileManager defaultManager];
|
|
if ([fm fileExistsAtPath:testPath]) {
|
|
// Try to actually read the file (more reliable than isReadableFileAtPath)
|
|
NSData* data = [NSData dataWithContentsOfFile:testPath];
|
|
if (data != nil) {
|
|
NSLog(@"FDA check: OK (can read Safari bookmarks)");
|
|
return true;
|
|
} else {
|
|
NSLog(@"FDA check: FAILED (Safari bookmarks exists but unreadable)");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Safari bookmarks doesn't exist, try TCC database
|
|
testPath = @"/Library/Application Support/com.apple.TCC/TCC.db";
|
|
if ([fm fileExistsAtPath:testPath]) {
|
|
NSData* data = [NSData dataWithContentsOfFile:testPath];
|
|
if (data != nil) {
|
|
NSLog(@"FDA check: OK (can read TCC.db)");
|
|
return true;
|
|
} else {
|
|
NSLog(@"FDA check: FAILED (TCC.db exists but unreadable)");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// No test files exist, assume OK
|
|
NSLog(@"FDA check: SKIPPED (no test files found)");
|
|
return true;
|
|
}
|
|
|
|
void Permissions::openFullDiskAccessSettings() {
|
|
// Open System Preferences -> Security & Privacy -> Privacy -> Full Disk Access
|
|
NSURL *url = [NSURL URLWithString:@"x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles"];
|
|
[[NSWorkspace sharedWorkspace] openURL:url];
|
|
}
|
|
|
|
bool Permissions::checkAllPermissions() {
|
|
return checkScreenCapture() && checkAccessibility() && checkFullDiskAccess();
|
|
}
|
|
|
|
bool Permissions::waitForPermissions(int timeoutSeconds) {
|
|
int elapsed = 0;
|
|
while (elapsed < timeoutSeconds) {
|
|
if (checkAllPermissions()) {
|
|
return true;
|
|
}
|
|
[NSThread sleepForTimeInterval:1.0];
|
|
elapsed++;
|
|
}
|
|
return false;
|
|
}
|