master ohmu/fastfetch-openbsd / src / detection / wm / wm_apple.m
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}