diff src/sys/osx/dark_theme.cc @ 194:8548dc425697

sys/osx: remove all objective-c++ stuff mmmm :)
author Paper <mrpapersonic@gmail.com>
date Thu, 07 Dec 2023 03:17:05 -0500
parents
children 975a3f0965e2
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sys/osx/dark_theme.cc	Thu Dec 07 03:17:05 2023 -0500
@@ -0,0 +1,133 @@
+#include "sys/osx/dark_theme.h"
+
+#include <objc/runtime.h>
+#include <objc/message.h>
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <AvailabilityMacros.h>
+
+#include <QOperatingSystemVersion>
+
+namespace osx {
+
+typedef id (*object_message_send)(id, SEL, ...);
+typedef id (*class_message_send)(Class, SEL, ...);
+
+static const object_message_send obj_send = reinterpret_cast<object_message_send>(objc_msgSend);
+static const class_message_send cls_send = reinterpret_cast<class_message_send>(objc_msgSend);
+
+static CFStringRef NSAppearanceNameAqua = nullptr;
+static CFStringRef NSAppearanceNameDarkAqua = nullptr;
+
+static const CFStringRef kLaunchServicesBundleID = CFSTR("com.apple.AppKit");
+
+bool RetrieveAppearanceNames() {
+	CFBundleRef appkit_bundle = CFBundleGetBundleWithIdentifier(kLaunchServicesBundleID);
+	if (!appkit_bundle)
+		return false;
+
+	NSAppearanceNameAqua = *reinterpret_cast<CFStringRef*>(CFBundleGetDataPointerForName(appkit_bundle, CFSTR("NSAppearanceNameAqua")));
+	if (!NSAppearanceNameAqua)
+		return false;
+
+	NSAppearanceNameDarkAqua = *reinterpret_cast<CFStringRef*>(CFBundleGetDataPointerForName(appkit_bundle, CFSTR("NSAppearanceNameDarkAqua")));
+	if (!NSAppearanceNameDarkAqua)
+		return false;
+
+	return true;
+}
+
+bool DarkThemeAvailable() {
+	return (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave);
+}
+
+bool IsInDarkTheme() {
+	if (!DarkThemeAvailable())
+		return false;
+
+	if (!NSAppearanceNameAqua || !NSAppearanceNameDarkAqua)
+		if (!RetrieveAppearanceNames())
+			return false;
+
+	CFArrayRef array = []() -> CFArrayRef {
+		CFStringRef refs[] = {NSAppearanceNameAqua, NSAppearanceNameDarkAqua};
+		return CFArrayCreate(NULL, reinterpret_cast<const void**>(refs), 2, &kCFTypeArrayCallBacks);
+	}();
+
+	// NSApplication* app = [NSApplication sharedApplication];
+	const id app = cls_send(objc_getClass("NSApplication"), sel_getUid("sharedApplication"));
+
+	// NSAppearance* effectiveAppearance = [app effectiveAppearance];
+	const id effectiveAppearance = obj_send(app, sel_getUid("effectiveAppearance"));
+	if (!effectiveAppearance) {
+		CFRelease(array);
+		return false;
+	}
+
+	// NSAppearance* appearance = [effectiveAppearance bestMatchFromAppearancesWithNames: array];
+	const id appearance = obj_send(effectiveAppearance, sel_getUid("bestMatchFromAppearancesWithNames:"), array);
+
+	CFRelease(array);
+
+	if (!appearance)
+		return false;
+
+	return CFEqual(appearance, NSAppearanceNameDarkAqua);
+}
+
+bool SetToDarkTheme() {
+	// https://stackoverflow.com/questions/55925862/how-can-i-set-my-os-x-application-theme-in-code
+	if (!DarkThemeAvailable())
+		return false;
+
+	if (!NSAppearanceNameAqua || !NSAppearanceNameDarkAqua)
+		if (!RetrieveAppearanceNames())
+			return false;
+
+	// NSApplication* app = [NSApplication sharedApplication];
+	const id app = cls_send(objc_getClass("NSApplication"), sel_getUid("sharedApplication"));
+
+	// NSAppearance* appearance = [NSAppearance appearanceNamed: NSAppearanceNameDarkAqua];
+	const id appearance = cls_send(objc_getClass("NSAppearance"), sel_getUid("appearanceNamed:"), NSAppearanceNameDarkAqua);
+	if (!appearance)
+		return false;
+
+	// [app setAppearance: appearance];
+	obj_send(app, sel_getUid("setAppearance:"), appearance);
+	return true;
+}
+
+bool SetToLightTheme() {
+	// https://stackoverflow.com/questions/55925862/how-can-i-set-my-os-x-application-theme-in-code
+	if (!DarkThemeAvailable())
+		return false;
+
+	if (!NSAppearanceNameAqua || !NSAppearanceNameDarkAqua)
+		if (!RetrieveAppearanceNames())
+			return false;
+
+	// NSApplication* app = [NSApplication sharedApplication];
+	const id app = cls_send(objc_getClass("NSApplication"), sel_getUid("sharedApplication"));
+
+	// NSAppearance* appearance = [NSAppearance appearanceNamed: NSAppearanceNameDarkAqua];
+	const id appearance = cls_send(objc_getClass("NSAppearance"), sel_getUid("appearanceNamed:"), NSAppearanceNameAqua);
+	if (!appearance)
+		return false;
+
+	// [app setAppearance: appearance];
+	obj_send(app, sel_getUid("setAppearance:"), appearance);
+	return true;
+}
+
+void SetToAutoTheme() {
+	if (!DarkThemeAvailable())
+		return;
+
+	// NSApplication* app = [NSApplication sharedApplication];
+	const id app = cls_send(objc_getClass("NSApplication"), sel_getUid("sharedApplication"));
+
+	// [app setAppearance: null];
+	obj_send(app, sel_getUid("setAppearance:"), nullptr);
+}
+
+} // namespace osx