Mercurial > minori
view dep/animia/src/win/quartz.cc @ 216:8a482049b968
dep/animia: win/wayland: add UNTESTED support for wlroots protocols
author | Paper <mrpapersonic@gmail.com> |
---|---|
date | Sun, 07 Jan 2024 12:42:10 -0500 |
parents | bc1ae1810855 |
children | a7d0d543b334 |
line wrap: on
line source
/* * win/quartz.cc: support for macOS (the Quartz Compositor) * * This file does not require an Objective-C++ compiler, * but it *does* require an Objective-C runtime and linking * with AppKit in order to receive proper window titles. */ #include "animia/win/quartz.h" #include "animia/util/osx.h" #include "animia.h" #include <objc/runtime.h> #include <objc/message.h> #include <CoreFoundation/CoreFoundation.h> #include <CoreGraphics/CoreGraphics.h> namespace animia::internal::quartz { 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 bool GetWindowTitle(unsigned int wid, std::string& result) { // NSApplication* app = [NSApplication sharedApplication]; const id app = cls_send(objc_getClass("NSApplication"), sel_getUid("sharedApplication")); // NSWindow* window = [app windowWithWindowNumber: wid]; const id window = obj_send(app, sel_getUid("windowWithWindowNumber:"), wid); if (!window) return false; // NSString* title = [window title]; const CFStringRef title = reinterpret_cast<CFStringRef>(obj_send(window, sel_getUid("title"))); if (!title) return false; // return [title UTF8String]; return osx::util::StringFromCFString(title, result); } static bool GetProcessBundleIdentifier(pid_t pid, std::string& result) { /* The Bundle ID is essentially OS X's solution to Windows' * "class name"; theoretically, it should be different for * each program, although it requires an app bundle. */ // NSRunningApplication* app = [NSRunningApplication runningApplicationWithProcessIdentifier: pid]; const id app = cls_send(objc_getClass("NSRunningApplication"), sel_getUid("runningApplicationWithProcessIdentifier:"), pid); if (!app) return false; // NSString* bundle_id = [app bundleIdentifier]; const CFStringRef bundle_id = reinterpret_cast<CFStringRef>(obj_send(app, sel_getUid("bundleIdentifier"))); if (!bundle_id) return false; // return [bundle_id UTF8String]; return osx::util::StringFromCFString(bundle_id, result); } 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); else if constexpr (std::is_same<T, std::string>::value) osx::util::StringFromCFString(reinterpret_cast<CFStringRef>(data), out); else return false; return true; } bool EnumerateWindows(window_proc_t window_proc) { if (!window_proc) return false; const CFArrayRef windows = CGWindowListCopyWindowInfo(kCGWindowListOptionAll, kCGNullWindowID); if (!windows) return false; const CFIndex count = CFArrayGetCount(windows); for (CFIndex i = 0; i < count; i++) { CFDictionaryRef window = reinterpret_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(windows, i)); if (!window) continue; Process proc; { CFDictionaryGetValue(window, CFSTR("kCGWindowOwnerPID"), proc.pid); if (!CFDictionaryGetValue(window, CFSTR("kCGWindowOwnerName"), proc.name)) osx::util::GetProcessName(proc.pid, proc.name); } Window win; { CFDictionaryGetValue(window, CFSTR("kCGWindowNumber"), win.id); if (!GetProcessBundleIdentifier(proc.pid, win.class_name)) { // Fallback to the Quartz window name, which is unlikely to be filled, but it // *could* be. CFDictionaryGetValue(window, CFSTR("kCGWindowName"), win.class_name); } GetWindowTitle(win.id, win.text); } if (!window_proc(proc, win)) { CFRelease(windows); return false; } } CFRelease(windows); return true; } } // namespace animia::win::detail