diff dep/animone/src/win/quartz.cc @ 268:382b50754fe4

dep/animone: make osx code a bit less hacky it would be nice if macos actually provided a real API for getting window titles (outside of the accessibility api). the accessibility API is a real mess to work with; the user has to give permission to access it under newer versions.
author Paper <paper@paper.us.eu.org>
date Fri, 12 Apr 2024 05:21:45 -0400
parents 862d0d8619f6
children f01b6e9c8fa2
line wrap: on
line diff
--- a/dep/animone/src/win/quartz.cc	Thu Apr 11 22:05:41 2024 -0400
+++ b/dep/animone/src/win/quartz.cc	Fri Apr 12 05:21:45 2024 -0400
@@ -17,6 +17,9 @@
 
 namespace animone::internal::quartz {
 
+template<typename T>
+using CFPtr = std::unique_ptr<T, CFDecontructor<T>>;
+
 #if __LP64__
 typedef long NSInteger;
 #else
@@ -58,21 +61,51 @@
 }
 
 template<typename T>
+static bool GetCFNumber(CFNumberRef num, T& result) {
+	if (!num)
+		return false;
+
+	int64_t res;
+	if (!CFNumberGetValue(num, static_cast<CFNumberType>(4), &res))
+		return false;
+
+	result = static_cast<T>(res);
+	return true;
+}
+
+static bool StringFromCFString(CFStringRef string, std::string& result) {
+	if (!string)
+		return false;
+
+	result.resize(CFStringGetMaximumSizeForEncoding(CFStringGetLength(string), kCFStringEncodingUTF8) + 1);
+	if (!CFStringGetCString(string, &result.front(), result.length(), kCFStringEncodingUTF8))
+		return false;
+
+	return true;
+}
+
+template<typename T>
 static bool CFDictionaryGetValue(CFDictionaryRef thedict, CFStringRef key, T& out) {
 	CFTypeRef data = nullptr;
 	if (!CFDictionaryGetValueIfPresent(thedict, key, reinterpret_cast<const void**>(&data)) || !data)
 		return false;
 
 	if constexpr (std::is_arithmetic<T>::value)
-		osx::util::GetCFNumber(reinterpret_cast<CFNumberRef>(data), out);
+		GetCFNumber(reinterpret_cast<CFNumberRef>(data), out);
 	else if constexpr (std::is_same<T, std::string>::value)
-		osx::util::StringFromCFString(reinterpret_cast<CFStringRef>(data), out);
+		StringFromCFString(reinterpret_cast<CFStringRef>(data), out);
 	else
 		return false;
 
 	return true;
 }
 
+template<typename T>
+struct CFDeconstructor {
+	using pointer = T;
+	void operator()(pointer t) const { ::CFRelease(t); };
+};
+
 static bool GetWindowTitleAccessibility(unsigned int wid, pid_t pid, std::string& result) {
 	CGRect bounds = {0};
 	{
@@ -119,24 +152,39 @@
 		    kAXErrorSuccess) {
 			CGPoint point;
 			if (!AXValueGetValue(val, kAXValueTypeCGPoint, reinterpret_cast<CFTypeRef>(&point)) ||
-			    (point.x != bounds.origin.x || point.y != bounds.origin.y))
+			    (point.x != bounds.origin.x || point.y != bounds.origin.y)) {
+				CFRelease(val);
 				continue;
-		} else
+			}
+		} else {
+			CFRelease(val);
 			continue;
+		}
+
+		CFRelease(val);
 
 		if (AXUIElementCopyAttributeValue(window, kAXSizeAttribute, reinterpret_cast<CFTypeRef*>(&val)) ==
 		    kAXErrorSuccess) {
 			CGSize size;
 			if (!AXValueGetValue(val, kAXValueTypeCGSize, reinterpret_cast<CFTypeRef>(&size)) ||
-			    (size.width != bounds.size.width || size.height != bounds.size.height))
+			    (size.width != bounds.size.width || size.height != bounds.size.height)) {
+				CFRelease(val);
 				continue;
-		} else
+			}
+		} else {
+			CFRelease(val);
 			continue;
+		}
+
+		CFRelease(val);
 
 		CFStringRef title;
 		if (AXUIElementCopyAttributeValue(window, kAXTitleAttribute, reinterpret_cast<CFTypeRef*>(&title)) ==
-		    kAXErrorSuccess)
-			return osx::util::StringFromCFString(title, result);
+		    kAXErrorSuccess) {
+			bool success = StringFromCFString(title, result);
+			CFRelease(title);
+			return success;
+		}
 	}
 
 	return false;
@@ -152,7 +200,7 @@
 			title.reset(t);
 		}
 
-		if (title && CFStringGetLength(title.get()) && osx::util::StringFromCFString(title.get(), result))
+		if (title && CFStringGetLength(title.get()) && StringFromCFString(title.get(), result))
 			return true;
 	}
 
@@ -171,8 +219,7 @@
 	if (!bundle_id)
 		return false;
 
-	result = osx::util::StringFromCFString(bundle_id, result);
-	return true;
+	return StringFromCFString(bundle_id, result);
 }
 
 static bool GetProcessBundleIdentifierOld(pid_t pid, std::string& result) {
@@ -189,8 +236,7 @@
 	if (!value)
 		return false;
 
-	result = osx::util::StringFromCFString(value, result);
-	return true;
+	return StringFromCFString(value, result);
 }
 
 static bool GetProcessBundleIdentifier(pid_t pid, std::string& result) {