ohmu
·
2026-10-15
1#include "wm.h"
2
3#include "common/sysctl.h"
4#include "common/mallocHelper.h"
5#include "common/strutil.h"
6#include "common/apple/version.h"
7
8#include <ctype.h>
9#include <libproc.h>
10#import <Foundation/Foundation.h>
11
12const char* ffDetectWMPlugin(FFstrbuf* pluginName) {
13 int request[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
14 size_t length;
15
16 if (sysctl(request, ARRAY_SIZE(request), nullptr, &length, nullptr, 0) != 0) {
17 return "sysctl({CTL_KERN, KERN_PROC, KERN_PROC_ALL, nullptr}) failed";
18 }
19
20 // The process table may change between the two sysctl calls; retry with a larger buffer.
21 length += length / 8 + sizeof(struct kinfo_proc);
22 FF_AUTO_FREE struct kinfo_proc* processes = malloc(length);
23
24 if (sysctl(request, ARRAY_SIZE(request), processes, &length, nullptr, 0) != 0) {
25 return "sysctl({CTL_KERN, KERN_PROC, KERN_PROC_ALL, processes}) failed";
26 }
27
28 uint32_t count = (uint32_t) (length / sizeof(struct kinfo_proc));
29
30 for (size_t i = 0; i < count; i++) {
31 const struct kinfo_proc* proc = &processes[i];
32 if (proc->kp_eproc.e_ppid != 1) {
33 continue;
34 }
35
36 const char* comm = proc->kp_proc.p_comm;
37
38 if (
39 !ffStrEqualsIgnCase(comm, "rectangle") && // 28.6k
40 !ffStrEqualsIgnCase(comm, "yabai") && // 28.4k
41 !ffStrEqualsIgnCase(comm, "aerospace") && // 19.6k
42 !ffStrEqualsIgnCase(comm, "amethyst") && // 16k
43 !ffStrEqualsIgnCase(comm, "glazewm") && // 11.6k
44
45#if 0
46 // Unmaintained
47 !ffStrEqualsIgnCase(comm, "spectacle") && // 13.6k
48 !ffStrEqualsIgnCase(comm, "chunkwm") && // repo deleted; was https://github.com/koekeishiya/chunkwm
49 !ffStrEqualsIgnCase(comm, "kwm") && // repo deleted; was https://github.com/koekeishiya/kwm
50#endif
51 true)
52 continue;
53
54 if (instance.config.general.detectVersion) {
55 char buf[PROC_PIDPATHINFO_MAXSIZE];
56 int length = proc_pidpath(proc->kp_proc.p_pid, buf, ARRAY_SIZE(buf) - strlen("Info.plist"));
57 if (length > 0) {
58 buf[length] = '\0';
59 FF_STRBUF_AUTO_DESTROY pluginVersion = ffStrbufCreate();
60 if (ffGetAppNameAndVersion(buf, pluginName, &pluginVersion)) {
61 if (pluginName->length == 0) {
62 ffStrbufSetS(pluginName, comm);
63 }
64 if (pluginVersion.length > 0) {
65 ffStrbufAppendC(pluginName, ' ');
66 ffStrbufAppend(pluginName, &pluginVersion);
67 }
68 break;
69 }
70 }
71 }
72
73 ffStrbufAppendS(pluginName, comm);
74 pluginName->chars[0] = (char) toupper(pluginName->chars[0]);
75 break;
76 }
77
78 return nullptr;
79}
80
81const char* ffDetectWMVersion(const FFstrbuf* wmName, FFstrbuf* result, [[maybe_unused]] FFWMOptions* options) {
82 if (!wmName) {
83 return "No WM detected";
84 }
85
86 if (ffStrbufEqualS(wmName, "WindowServer")) {
87 NSError* error;
88 NSDictionary* dict = [NSDictionary dictionaryWithContentsOfURL:[NSURL fileURLWithPath:@"/System/Library/PrivateFrameworks/SkyLight.framework/Resources/version.plist" isDirectory:NO]
89 error:&error];
90 if (!dict) {
91 dict = [NSDictionary dictionaryWithContentsOfURL:[NSURL fileURLWithPath:@"/System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework/Resources/version.plist" isDirectory:NO]
92 error:&error];
93 }
94
95 if (dict) {
96 ffStrbufSetS(result, ((NSString*) dict[@"CFBundleShortVersionString"]).UTF8String);
97 }
98 }
99
100 return nullptr;
101}