summaryrefslogtreecommitdiffstats
path: root/src/detection/wm/wm_apple.m
blob: 89273e9390b617fb622f12ae82b84c91e29f9ed4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include "wm.h"

#include "common/sysctl.h"
#include "common/mallocHelper.h"
#include "common/strutil.h"
#include "common/apple/version.h"

#include <ctype.h>
#include <libproc.h>
#import <Foundation/Foundation.h>

const char* ffDetectWMPlugin(FFstrbuf* pluginName) {
    int request[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
    u_int requestLength = ARRAY_SIZE(request);

    size_t length = 0;
    FF_AUTO_FREE struct kinfo_proc* processes = ffSysctlGetData(request, requestLength, &length);
    if (processes == NULL) {
        return "sysctl(CTL_KERN, KERN_PROC, KERN_PROC_ALL) failed";
    }
    assert(length % sizeof(struct kinfo_proc) == 0);

    for (size_t i = 0; i < length / sizeof(struct kinfo_proc); i++) {
        const struct kinfo_proc* proc = &processes[i];
        if (proc->kp_eproc.e_ppid != 1) {
            continue;
        }

        const char* comm = proc->kp_proc.p_comm;

        if (
            !ffStrEqualsIgnCase(comm, "rectangle") && // 28.6k
            !ffStrEqualsIgnCase(comm, "yabai") &&     // 28.4k
            !ffStrEqualsIgnCase(comm, "aerospace") && // 19.6k
            !ffStrEqualsIgnCase(comm, "amethyst") &&  // 16k
            !ffStrEqualsIgnCase(comm, "glazewm") &&   // 11.6k

#if 0
            // Unmaintained
            !ffStrEqualsIgnCase(comm, "spectacle") && // 13.6k
            !ffStrEqualsIgnCase(comm, "chunkwm") && // repo deleted; was https://github.com/koekeishiya/chunkwm
            !ffStrEqualsIgnCase(comm, "kwm") && // repo deleted; was https://github.com/koekeishiya/kwm
#endif
            true)
            continue;

        if (instance.config.general.detectVersion) {
            char buf[PROC_PIDPATHINFO_MAXSIZE];
            int length = proc_pidpath(proc->kp_proc.p_pid, buf, ARRAY_SIZE(buf) - strlen("Info.plist"));
            if (length > 0) {
                buf[length] = '\0';
                FF_STRBUF_AUTO_DESTROY pluginVersion = ffStrbufCreate();
                if (ffGetAppNameAndVersion(buf, pluginName, &pluginVersion)) {
                    if (pluginName->length == 0) {
                        ffStrbufSetS(pluginName, comm);
                    }
                    if (pluginVersion.length > 0) {
                        ffStrbufAppendC(pluginName, ' ');
                        ffStrbufAppend(pluginName, &pluginVersion);
                    }
                    break;
                }
            }
        }

        ffStrbufAppendS(pluginName, comm);
        pluginName->chars[0] = (char) toupper(pluginName->chars[0]);
        break;
    }

    return NULL;
}

const char* ffDetectWMVersion(const FFstrbuf* wmName, FFstrbuf* result, FF_A_UNUSED FFWMOptions* options) {
    if (!wmName) {
        return "No WM detected";
    }

    if (ffStrbufEqualS(wmName, "WindowServer")) {
        NSError* error;
        NSDictionary* dict = [NSDictionary dictionaryWithContentsOfURL:[NSURL fileURLWithPath:@"/System/Library/PrivateFrameworks/SkyLight.framework/Resources/version.plist" isDirectory:NO]
                                                                 error:&error];
        if (!dict) {
            dict = [NSDictionary dictionaryWithContentsOfURL:[NSURL fileURLWithPath:@"/System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework/Resources/version.plist" isDirectory:NO]
                                                       error:&error];
        }

        if (dict) {
            ffStrbufSetS(result, ((NSString*) dict[@"CFBundleShortVersionString"]).UTF8String);
        }
    }

    return NULL;
}