Mercurial > minori
comparison dep/animia/src/win/quartz.cc @ 191:0fc126d52de4
animia: multiple stylistic choices
win.class_name is now used to store bundle IDs on OS X,
add some little explanations here and there for dumb stuff
| author | Paper <mrpapersonic@gmail.com> |
|---|---|
| date | Thu, 07 Dec 2023 01:48:04 -0500 |
| parents | 2d5823df870f |
| children | 50108040d792 |
comparison
equal
deleted
inserted
replaced
| 190:2d5823df870f | 191:0fc126d52de4 |
|---|---|
| 1 /* | |
| 2 * win/quartz.cc: support for macOS (the Quartz Compositor) | |
| 3 * | |
| 4 * This file does not require an Objective-C++ compiler, | |
| 5 * but it *does* require an Objective-C runtime and linking | |
| 6 * with AppKit in order to receive proper window titles. | |
| 7 */ | |
| 1 #include "animia/win/quartz.h" | 8 #include "animia/win/quartz.h" |
| 2 #include "animia/util/osx.h" | 9 #include "animia/util/osx.h" |
| 3 #include "animia.h" | 10 #include "animia.h" |
| 4 | 11 |
| 5 #include <objc/runtime.h> | 12 #include <objc/runtime.h> |
| 6 #include <objc/message.h> | 13 #include <objc/message.h> |
| 7 | 14 |
| 8 #include <CoreFoundation/CoreFoundation.h> | 15 #include <CoreFoundation/CoreFoundation.h> |
| 9 #include <CoreGraphics/CoreGraphics.h> | 16 #include <CoreGraphics/CoreGraphics.h> |
| 10 | |
| 11 #include <iostream> | |
| 12 | 17 |
| 13 namespace animia::internal::quartz { | 18 namespace animia::internal::quartz { |
| 14 | 19 |
| 15 typedef id (*object_message_send)(id, SEL, ...); | 20 typedef id (*object_message_send)(id, SEL, ...); |
| 16 typedef id (*class_message_send)(Class, SEL, ...); | 21 typedef id (*class_message_send)(Class, SEL, ...); |
| 18 static const object_message_send obj_send = reinterpret_cast<object_message_send>(objc_msgSend); | 23 static const object_message_send obj_send = reinterpret_cast<object_message_send>(objc_msgSend); |
| 19 static const class_message_send cls_send = reinterpret_cast<class_message_send>(objc_msgSend); | 24 static const class_message_send cls_send = reinterpret_cast<class_message_send>(objc_msgSend); |
| 20 | 25 |
| 21 static bool GetWindowTitle(unsigned int wid, std::string& result) { | 26 static bool GetWindowTitle(unsigned int wid, std::string& result) { |
| 22 // NSApplication* app = [NSApplication sharedApplication]; | 27 // NSApplication* app = [NSApplication sharedApplication]; |
| 23 id app = cls_send(objc_getClass("NSApplication"), sel_getUid("sharedApplication")); | 28 const id app = cls_send(objc_getClass("NSApplication"), sel_getUid("sharedApplication")); |
| 24 | 29 |
| 25 // NSWindow* window = [app windowWithWindowNumber: wid]; | 30 // NSWindow* window = [app windowWithWindowNumber: wid]; |
| 26 id window = obj_send(app, sel_getUid("windowWithWindowNumber:"), wid); | 31 const id window = obj_send(app, sel_getUid("windowWithWindowNumber:"), wid); |
| 27 if (!window) | 32 if (!window) |
| 28 return false; | 33 return false; |
| 29 | 34 |
| 30 // NSString* title = [window title]; | 35 // NSString* title = [window title]; |
| 31 // does this have to be freed? | 36 const CFStringRef title = reinterpret_cast<CFStringRef>(obj_send(window, sel_getUid("title"))); |
| 32 CFStringRef title = reinterpret_cast<CFStringRef>(obj_send(window, sel_getUid("title"))); | |
| 33 if (!title) | 37 if (!title) |
| 34 return false; | 38 return false; |
| 35 | 39 |
| 36 // return [title UTF8String]; | 40 // return [title UTF8String]; |
| 37 return osx::util::StringFromCFString(title, result); | 41 return osx::util::StringFromCFString(title, result); |
| 42 } | |
| 43 | |
| 44 static bool GetWindowBundleIdentifier(pid_t pid, std::string& result) { | |
| 45 /* The Bundle ID is essentially OS X's solution to Windows' | |
| 46 * "class name"; theoretically, it should be different for | |
| 47 * each program, although it requires an app bundle. | |
| 48 */ | |
| 49 | |
| 50 // NSRunningApplication* app = [NSRunningApplication runningApplicationWithProcessIdentifier: pid]; | |
| 51 const id app = cls_send(objc_getClass("NSRunningApplication"), sel_getUid("runningApplicationWithProcessIdentifier:"), pid); | |
| 52 if (!app) | |
| 53 return false; | |
| 54 | |
| 55 // NSString* bundle_id = [app bundleIdentifier]; | |
| 56 const CFStringRef bundle_id = reinterpret_cast<CFStringRef>(obj_send(app, sel_getUid("bundleIdentifier"))); | |
| 57 if (!bundle_id) | |
| 58 return false; | |
| 59 | |
| 60 // return [bundle_id UTF8String]; | |
| 61 return osx::util::StringFromCFString(bundle_id, result); | |
| 38 } | 62 } |
| 39 | 63 |
| 40 bool QuartzWinTools::EnumerateWindows(window_proc_t window_proc) { | 64 bool QuartzWinTools::EnumerateWindows(window_proc_t window_proc) { |
| 41 if (!window_proc) | 65 if (!window_proc) |
| 42 return false; | 66 return false; |
| 72 { | 96 { |
| 73 CFNumberRef num = nullptr; | 97 CFNumberRef num = nullptr; |
| 74 if (CFDictionaryGetValueIfPresent(window, CFSTR("kCGWindowNumber"), reinterpret_cast<const void**>(&num)) && num) | 98 if (CFDictionaryGetValueIfPresent(window, CFSTR("kCGWindowNumber"), reinterpret_cast<const void**>(&num)) && num) |
| 75 osx::util::GetCFNumber(num, win.id); | 99 osx::util::GetCFNumber(num, win.id); |
| 76 } | 100 } |
| 77 { | 101 if (!GetWindowBundleIdentifier(proc.pid, win.class_name)) { |
| 102 // Fallback to the Quartz window name, which is unlikely to be filled, but it | |
| 103 // *could* be. | |
| 78 CFStringRef str = nullptr; | 104 CFStringRef str = nullptr; |
| 79 if (CFDictionaryGetValueIfPresent(window, CFSTR("kCGWindowName"), reinterpret_cast<const void**>(&str)) && str) | 105 if (CFDictionaryGetValueIfPresent(window, CFSTR("kCGWindowName"), reinterpret_cast<const void**>(&str)) && str) |
| 80 osx::util::StringFromCFString(str, win.class_name); | 106 osx::util::StringFromCFString(str, win.class_name); |
| 81 } | 107 } |
| 82 GetWindowTitle(win.id, win.text); | 108 GetWindowTitle(win.id, win.text); |
