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); |