Mercurial > minori
annotate dep/animia/src/win/quartz.cc @ 197:c4ca035c565d
*: misc. patches
author | Paper <mrpapersonic@gmail.com> |
---|---|
date | Fri, 08 Dec 2023 11:19:54 -0500 |
parents | 50108040d792 |
children | bc1ae1810855 |
rev | line source |
---|---|
191
0fc126d52de4
animia: multiple stylistic choices
Paper <mrpapersonic@gmail.com>
parents:
190
diff
changeset
|
1 /* |
0fc126d52de4
animia: multiple stylistic choices
Paper <mrpapersonic@gmail.com>
parents:
190
diff
changeset
|
2 * win/quartz.cc: support for macOS (the Quartz Compositor) |
0fc126d52de4
animia: multiple stylistic choices
Paper <mrpapersonic@gmail.com>
parents:
190
diff
changeset
|
3 * |
0fc126d52de4
animia: multiple stylistic choices
Paper <mrpapersonic@gmail.com>
parents:
190
diff
changeset
|
4 * This file does not require an Objective-C++ compiler, |
0fc126d52de4
animia: multiple stylistic choices
Paper <mrpapersonic@gmail.com>
parents:
190
diff
changeset
|
5 * but it *does* require an Objective-C runtime and linking |
0fc126d52de4
animia: multiple stylistic choices
Paper <mrpapersonic@gmail.com>
parents:
190
diff
changeset
|
6 * with AppKit in order to receive proper window titles. |
0fc126d52de4
animia: multiple stylistic choices
Paper <mrpapersonic@gmail.com>
parents:
190
diff
changeset
|
7 */ |
189 | 8 #include "animia/win/quartz.h" |
190
2d5823df870f
dep/animia: finalize de-objc-ifying quartz
Paper <mrpapersonic@gmail.com>
parents:
189
diff
changeset
|
9 #include "animia/util/osx.h" |
189 | 10 #include "animia.h" |
11 | |
12 #include <objc/runtime.h> | |
13 #include <objc/message.h> | |
14 | |
15 #include <CoreFoundation/CoreFoundation.h> | |
16 #include <CoreGraphics/CoreGraphics.h> | |
190
2d5823df870f
dep/animia: finalize de-objc-ifying quartz
Paper <mrpapersonic@gmail.com>
parents:
189
diff
changeset
|
17 |
189 | 18 namespace animia::internal::quartz { |
19 | |
190
2d5823df870f
dep/animia: finalize de-objc-ifying quartz
Paper <mrpapersonic@gmail.com>
parents:
189
diff
changeset
|
20 typedef id (*object_message_send)(id, SEL, ...); |
2d5823df870f
dep/animia: finalize de-objc-ifying quartz
Paper <mrpapersonic@gmail.com>
parents:
189
diff
changeset
|
21 typedef id (*class_message_send)(Class, SEL, ...); |
2d5823df870f
dep/animia: finalize de-objc-ifying quartz
Paper <mrpapersonic@gmail.com>
parents:
189
diff
changeset
|
22 |
2d5823df870f
dep/animia: finalize de-objc-ifying quartz
Paper <mrpapersonic@gmail.com>
parents:
189
diff
changeset
|
23 static const object_message_send obj_send = reinterpret_cast<object_message_send>(objc_msgSend); |
2d5823df870f
dep/animia: finalize de-objc-ifying quartz
Paper <mrpapersonic@gmail.com>
parents:
189
diff
changeset
|
24 static const class_message_send cls_send = reinterpret_cast<class_message_send>(objc_msgSend); |
2d5823df870f
dep/animia: finalize de-objc-ifying quartz
Paper <mrpapersonic@gmail.com>
parents:
189
diff
changeset
|
25 |
189 | 26 static bool GetWindowTitle(unsigned int wid, std::string& result) { |
190
2d5823df870f
dep/animia: finalize de-objc-ifying quartz
Paper <mrpapersonic@gmail.com>
parents:
189
diff
changeset
|
27 // NSApplication* app = [NSApplication sharedApplication]; |
191
0fc126d52de4
animia: multiple stylistic choices
Paper <mrpapersonic@gmail.com>
parents:
190
diff
changeset
|
28 const id app = cls_send(objc_getClass("NSApplication"), sel_getUid("sharedApplication")); |
189 | 29 |
190
2d5823df870f
dep/animia: finalize de-objc-ifying quartz
Paper <mrpapersonic@gmail.com>
parents:
189
diff
changeset
|
30 // NSWindow* window = [app windowWithWindowNumber: wid]; |
191
0fc126d52de4
animia: multiple stylistic choices
Paper <mrpapersonic@gmail.com>
parents:
190
diff
changeset
|
31 const id window = obj_send(app, sel_getUid("windowWithWindowNumber:"), wid); |
190
2d5823df870f
dep/animia: finalize de-objc-ifying quartz
Paper <mrpapersonic@gmail.com>
parents:
189
diff
changeset
|
32 if (!window) |
2d5823df870f
dep/animia: finalize de-objc-ifying quartz
Paper <mrpapersonic@gmail.com>
parents:
189
diff
changeset
|
33 return false; |
189 | 34 |
190
2d5823df870f
dep/animia: finalize de-objc-ifying quartz
Paper <mrpapersonic@gmail.com>
parents:
189
diff
changeset
|
35 // NSString* title = [window title]; |
191
0fc126d52de4
animia: multiple stylistic choices
Paper <mrpapersonic@gmail.com>
parents:
190
diff
changeset
|
36 const CFStringRef title = reinterpret_cast<CFStringRef>(obj_send(window, sel_getUid("title"))); |
190
2d5823df870f
dep/animia: finalize de-objc-ifying quartz
Paper <mrpapersonic@gmail.com>
parents:
189
diff
changeset
|
37 if (!title) |
2d5823df870f
dep/animia: finalize de-objc-ifying quartz
Paper <mrpapersonic@gmail.com>
parents:
189
diff
changeset
|
38 return false; |
2d5823df870f
dep/animia: finalize de-objc-ifying quartz
Paper <mrpapersonic@gmail.com>
parents:
189
diff
changeset
|
39 |
2d5823df870f
dep/animia: finalize de-objc-ifying quartz
Paper <mrpapersonic@gmail.com>
parents:
189
diff
changeset
|
40 // return [title UTF8String]; |
2d5823df870f
dep/animia: finalize de-objc-ifying quartz
Paper <mrpapersonic@gmail.com>
parents:
189
diff
changeset
|
41 return osx::util::StringFromCFString(title, result); |
189 | 42 } |
43 | |
192
50108040d792
dep/animia/quartz: GetWindowBundleIdentifier -> GetProcessBundleIdentifier
Paper <mrpapersonic@gmail.com>
parents:
191
diff
changeset
|
44 static bool GetProcessBundleIdentifier(pid_t pid, std::string& result) { |
191
0fc126d52de4
animia: multiple stylistic choices
Paper <mrpapersonic@gmail.com>
parents:
190
diff
changeset
|
45 /* The Bundle ID is essentially OS X's solution to Windows' |
0fc126d52de4
animia: multiple stylistic choices
Paper <mrpapersonic@gmail.com>
parents:
190
diff
changeset
|
46 * "class name"; theoretically, it should be different for |
0fc126d52de4
animia: multiple stylistic choices
Paper <mrpapersonic@gmail.com>
parents:
190
diff
changeset
|
47 * each program, although it requires an app bundle. |
0fc126d52de4
animia: multiple stylistic choices
Paper <mrpapersonic@gmail.com>
parents:
190
diff
changeset
|
48 */ |
0fc126d52de4
animia: multiple stylistic choices
Paper <mrpapersonic@gmail.com>
parents:
190
diff
changeset
|
49 |
0fc126d52de4
animia: multiple stylistic choices
Paper <mrpapersonic@gmail.com>
parents:
190
diff
changeset
|
50 // NSRunningApplication* app = [NSRunningApplication runningApplicationWithProcessIdentifier: pid]; |
0fc126d52de4
animia: multiple stylistic choices
Paper <mrpapersonic@gmail.com>
parents:
190
diff
changeset
|
51 const id app = cls_send(objc_getClass("NSRunningApplication"), sel_getUid("runningApplicationWithProcessIdentifier:"), pid); |
0fc126d52de4
animia: multiple stylistic choices
Paper <mrpapersonic@gmail.com>
parents:
190
diff
changeset
|
52 if (!app) |
0fc126d52de4
animia: multiple stylistic choices
Paper <mrpapersonic@gmail.com>
parents:
190
diff
changeset
|
53 return false; |
0fc126d52de4
animia: multiple stylistic choices
Paper <mrpapersonic@gmail.com>
parents:
190
diff
changeset
|
54 |
0fc126d52de4
animia: multiple stylistic choices
Paper <mrpapersonic@gmail.com>
parents:
190
diff
changeset
|
55 // NSString* bundle_id = [app bundleIdentifier]; |
0fc126d52de4
animia: multiple stylistic choices
Paper <mrpapersonic@gmail.com>
parents:
190
diff
changeset
|
56 const CFStringRef bundle_id = reinterpret_cast<CFStringRef>(obj_send(app, sel_getUid("bundleIdentifier"))); |
0fc126d52de4
animia: multiple stylistic choices
Paper <mrpapersonic@gmail.com>
parents:
190
diff
changeset
|
57 if (!bundle_id) |
0fc126d52de4
animia: multiple stylistic choices
Paper <mrpapersonic@gmail.com>
parents:
190
diff
changeset
|
58 return false; |
0fc126d52de4
animia: multiple stylistic choices
Paper <mrpapersonic@gmail.com>
parents:
190
diff
changeset
|
59 |
0fc126d52de4
animia: multiple stylistic choices
Paper <mrpapersonic@gmail.com>
parents:
190
diff
changeset
|
60 // return [bundle_id UTF8String]; |
0fc126d52de4
animia: multiple stylistic choices
Paper <mrpapersonic@gmail.com>
parents:
190
diff
changeset
|
61 return osx::util::StringFromCFString(bundle_id, result); |
0fc126d52de4
animia: multiple stylistic choices
Paper <mrpapersonic@gmail.com>
parents:
190
diff
changeset
|
62 } |
0fc126d52de4
animia: multiple stylistic choices
Paper <mrpapersonic@gmail.com>
parents:
190
diff
changeset
|
63 |
197 | 64 template<typename T> |
65 static bool CFDictionaryGetValue(CFDictionaryRef thedict, CFStringRef key, T& out) { | |
66 CFTypeRef data = nullptr; | |
67 if (!CFDictionaryGetValueIfPresent(thedict, key, reinterpret_cast<const void**>(&data)) || !data) | |
68 return false; | |
69 | |
70 if constexpr (std::is_arithmetic<T>::value) | |
71 osx::util::GetCFNumber(reinterpret_cast<CFNumberRef>(data), out); | |
72 else if constexpr (std::is_same<T, std::string>::value) | |
73 osx::util::StringFromCFString(reinterpret_cast<CFStringRef>(data), out); | |
74 else | |
75 return false; | |
76 | |
77 return true; | |
78 } | |
79 | |
189 | 80 bool QuartzWinTools::EnumerateWindows(window_proc_t window_proc) { |
81 if (!window_proc) | |
82 return false; | |
83 | |
190
2d5823df870f
dep/animia: finalize de-objc-ifying quartz
Paper <mrpapersonic@gmail.com>
parents:
189
diff
changeset
|
84 const CFArrayRef windows = CGWindowListCopyWindowInfo(kCGWindowListOptionAll, kCGNullWindowID); |
189 | 85 if (!windows) |
86 return false; | |
87 | |
190
2d5823df870f
dep/animia: finalize de-objc-ifying quartz
Paper <mrpapersonic@gmail.com>
parents:
189
diff
changeset
|
88 const CFIndex count = CFArrayGetCount(windows); |
2d5823df870f
dep/animia: finalize de-objc-ifying quartz
Paper <mrpapersonic@gmail.com>
parents:
189
diff
changeset
|
89 for (CFIndex i = 0; i < count; i++) { |
2d5823df870f
dep/animia: finalize de-objc-ifying quartz
Paper <mrpapersonic@gmail.com>
parents:
189
diff
changeset
|
90 CFDictionaryRef window = reinterpret_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(windows, i)); |
189 | 91 if (!window) |
92 continue; | |
93 | |
94 Process proc; | |
95 { | |
197 | 96 CFDictionaryGetValue(window, CFSTR("kCGWindowOwnerPID"), proc.pid); |
97 if (!CFDictionaryGetValue(window, CFSTR("kCGWindowOwnerName"), proc.name)) | |
189 | 98 osx::util::GetProcessName(proc.pid, proc.name); |
99 } | |
100 | |
101 Window win; | |
102 { | |
197 | 103 CFDictionaryGetValue(window, CFSTR("kCGWindowNumber"), win.id); |
104 | |
192
50108040d792
dep/animia/quartz: GetWindowBundleIdentifier -> GetProcessBundleIdentifier
Paper <mrpapersonic@gmail.com>
parents:
191
diff
changeset
|
105 if (!GetProcessBundleIdentifier(proc.pid, win.class_name)) { |
191
0fc126d52de4
animia: multiple stylistic choices
Paper <mrpapersonic@gmail.com>
parents:
190
diff
changeset
|
106 // Fallback to the Quartz window name, which is unlikely to be filled, but it |
0fc126d52de4
animia: multiple stylistic choices
Paper <mrpapersonic@gmail.com>
parents:
190
diff
changeset
|
107 // *could* be. |
197 | 108 CFDictionaryGetValue(window, CFSTR("kCGWindowName"), win.class_name); |
189 | 109 } |
197 | 110 |
189 | 111 GetWindowTitle(win.id, win.text); |
112 } | |
113 | |
190
2d5823df870f
dep/animia: finalize de-objc-ifying quartz
Paper <mrpapersonic@gmail.com>
parents:
189
diff
changeset
|
114 if (!window_proc(proc, win)) { |
2d5823df870f
dep/animia: finalize de-objc-ifying quartz
Paper <mrpapersonic@gmail.com>
parents:
189
diff
changeset
|
115 CFRelease(windows); |
189 | 116 return false; |
190
2d5823df870f
dep/animia: finalize de-objc-ifying quartz
Paper <mrpapersonic@gmail.com>
parents:
189
diff
changeset
|
117 } |
189 | 118 } |
119 | |
190
2d5823df870f
dep/animia: finalize de-objc-ifying quartz
Paper <mrpapersonic@gmail.com>
parents:
189
diff
changeset
|
120 CFRelease(windows); |
2d5823df870f
dep/animia: finalize de-objc-ifying quartz
Paper <mrpapersonic@gmail.com>
parents:
189
diff
changeset
|
121 |
189 | 122 return true; |
123 } | |
124 | |
125 } // namespace animia::win::detail |