From 6564d858454ee995c4af7ff0b5ee4a639ab38405 Mon Sep 17 00:00:00 2001 From: utox39 Date: Mon, 15 Sep 2025 14:59:24 +0200 Subject: [PATCH 1/7] feat(macos): add window manager info --- src/macos/system.zig | 66 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/src/macos/system.zig b/src/macos/system.zig index a231cab..f436bea 100644 --- a/src/macos/system.zig +++ b/src/macos/system.zig @@ -128,3 +128,69 @@ pub fn getOsInfo(allocator: std.mem.Allocator) ![]u8 { return os_info; } + +pub fn getWindowManagerInfo(allocator: std.mem.Allocator) ![]const u8 { + var name = [_]c_int{ c_sysctl.CTL_KERN, c_sysctl.KERN_PROC, c_sysctl.KERN_PROC_ALL }; + var size: usize = 0; + + // First call to get the dimension + if (c_sysctl.sysctl(&name, name.len, null, &size, null, 0) != 0) { + return error.SysctlFailed; + } + + const buffer: []u8 = try allocator.alloc(u8, size); + defer allocator.free(buffer); + + // Second call to retrieve process data + if (c_sysctl.sysctl(&name, name.len, buffer.ptr, &size, null, 0) != 0) { + return error.SysctlFailed; + } + + // Ensure the buffer size is valid + if (size % @sizeOf(c_sysctl.struct_kinfo_proc) != 0) { + return error.InvalidBufferSize; + } + + const kinfo_list = std.mem.bytesAsSlice(c_sysctl.struct_kinfo_proc, buffer); + + var wm_name: ?[]const u8 = null; + + const supported_wms: [7][]const u8 = .{ + "aerospace", + "amethyst", + "chunkwm", + "kwm", + "rectangle", + "spectacle", + "yabai", + }; + + wm_name = outer: { + for (kinfo_list) |kinfo| { + const pid = kinfo.kp_proc.p_pid; + if (pid <= 0) continue; + + // Gets the process pathname + var pathbuf: [c_libproc.PROC_PIDPATHINFO_MAXSIZE]u8 = undefined; + // c_libproc.proc_pidpath saves the process name in `pathbuf` and returns the len + const path_len = @as(usize, @intCast(c_libproc.proc_pidpath(pid, &pathbuf, pathbuf.len))); + const proc_pathname = if (path_len > 0) try allocator.dupe(u8, pathbuf[0..@intCast(path_len)]) else try allocator.dupe(u8, "unknown"); + defer allocator.free(proc_pathname); + + inline for (supported_wms) |wm| { + if (std.ascii.endsWithIgnoreCase(proc_pathname, wm)) { + const basename = if (std.mem.lastIndexOfScalar(u8, proc_pathname, '/')) |index| + proc_pathname[index + 1 ..] + else + proc_pathname; + + break :outer try allocator.dupe(u8, basename); + } + } + } + + break :outer null; + }; + + return wm_name orelse allocator.dupe(u8, "Quartz Compositor"); +} From cec2b8068a0df2b205372df3de24f0929dafc607 Mon Sep 17 00:00:00 2001 From: utox39 Date: Sat, 20 Sep 2025 01:05:59 +0200 Subject: [PATCH 2/7] feat(macos-wm): remove kwm from supported window managers --- src/macos/system.zig | 1 - 1 file changed, 1 deletion(-) diff --git a/src/macos/system.zig b/src/macos/system.zig index f436bea..fc15d44 100644 --- a/src/macos/system.zig +++ b/src/macos/system.zig @@ -159,7 +159,6 @@ pub fn getWindowManagerInfo(allocator: std.mem.Allocator) ![]const u8 { "aerospace", "amethyst", "chunkwm", - "kwm", "rectangle", "spectacle", "yabai", From 2f847fbef3df19ed59a5d69901d9987d96b85ee0 Mon Sep 17 00:00:00 2001 From: utox39 Date: Fri, 3 Oct 2025 12:40:54 +0200 Subject: [PATCH 3/7] feat(config): add wm module --- src/config.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/src/config.zig b/src/config.zig index 2524335..2f335ef 100644 --- a/src/config.zig +++ b/src/config.zig @@ -25,6 +25,7 @@ pub const ModuleType = enum { swap, disk, net, + wm, terminal, locale, custom, From d6978cd4b213962fed6482e270d22a089693bca1 Mon Sep 17 00:00:00 2001 From: utox39 Date: Fri, 3 Oct 2025 12:50:19 +0200 Subject: [PATCH 4/7] feat(formatters): add window manager formatters --- src/formatters.zig | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/formatters.zig b/src/formatters.zig index cf466e7..0bed40d 100644 --- a/src/formatters.zig +++ b/src/formatters.zig @@ -20,6 +20,7 @@ pub const formatters = [_]*const fn (allocator: std.mem.Allocator, key: []const &getFormattedSwapInfo, &getFormattedDiskInfo, &getFormattedNetInfo, + &getFormattedWindowManagerInfo, &getFormattedTerminalNameInfo, &getFormattedLocaleInfo, &getFormattedCustom, @@ -37,6 +38,7 @@ pub const default_formatters = [_]*const fn (allocator: std.mem.Allocator) anyer &getDefaultFormattedSwapInfo, &getDefaultFormattedDiskInfo, &getDefaultFormattedNetInfo, + &getDefaultFormattedWindowManagerInfo, &getDefaultFormattedTerminalNameInfo, &getDefaultFormattedLocaleInfo, }; @@ -192,6 +194,16 @@ pub fn getFormattedDiskInfo(allocator: std.mem.Allocator, key: []const u8, key_c return Result{ .string = try std.fmt.allocPrint(allocator, "{s}{s} ({s}):{s} {d:.2} / {d:.2} GB ({}%)", .{ key_color, key, disk_info.disk_path, ascii.Reset, disk_info.disk_usage, disk_info.disk_size, disk_info.disk_usage_percentage }) }; } +pub fn getDefaultFormattedWindowManagerInfo(allocator: std.mem.Allocator) !Result { + return try getFormattedWindowManagerInfo(allocator, "WM", ascii.Yellow); +} + +pub fn getFormattedWindowManagerInfo(allocator: std.mem.Allocator, key: []const u8, key_color: []const u8) !Result { + const wm = try detection.system.getWindowManagerInfo(allocator); + defer allocator.free(wm); + return Result{ .string = try std.fmt.allocPrint(allocator, "{s}{s}:{s} {s}", .{ key_color, key, ascii.Reset, wm }) }; +} + pub fn getDefaultFormattedTerminalNameInfo(allocator: std.mem.Allocator) !Result { return try getFormattedTerminalNameInfo(allocator, "Terminal", ascii.Yellow); } From 62df4a52dcd9212edbdbc602ddca4b11a89075b0 Mon Sep 17 00:00:00 2001 From: utox39 Date: Sat, 4 Oct 2025 17:15:41 +0200 Subject: [PATCH 5/7] feat(linux): add window manager info --- src/linux/system.zig | 55 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/linux/system.zig b/src/linux/system.zig index 071a6d8..5ebc159 100644 --- a/src/linux/system.zig +++ b/src/linux/system.zig @@ -98,3 +98,58 @@ pub fn getOsInfo(allocator: std.mem.Allocator) ![]u8 { return try allocator.dupe(u8, pretty_name orelse "Unknown"); } + +pub fn getWindowManagerInfo(allocator: std.mem.Allocator) ![]const u8 { + var dir = try std.fs.cwd().openDir("/proc/", .{ .iterate = true }); + defer dir.close(); + + var wm_name: ?[]const u8 = null; + + var iter = dir.iterate(); + wm_name = outer: { + while (try iter.next()) |entry| { + if (entry.kind != .directory) continue; + + // Check if the entry name is numeric + _ = std.fmt.parseInt(i32, entry.name, 10) catch continue; + + var buf: [1024]u8 = undefined; + const file_name = try std.fmt.bufPrint(&buf, "/proc/{s}/comm", .{entry.name}); + const file = try std.fs.cwd().openFile(file_name, .{ .mode = .read_only }); + defer file.close(); + + // NOTE: https://stackoverflow.com/questions/23534263/what-is-the-maximum-allowed-limit-on-the-length-of-a-process-name + var file_buf: [16]u8 = undefined; + var reader = std.fs.File.Reader.init(file, &file_buf); + const read = try reader.read(&file_buf); + const proc_name = file_buf[0..read]; + + const proc_name_trimmed = std.mem.trim(u8, proc_name, "\n"); + + const supported_wms: [9][]const u8 = .{ + "i3", // https://i3wm.org/ + // "i3gaps", // TODO: find a way to recognize i3gaps + "sway", // https://swaywm.org/ + // "swayfx", // TODO: find a way to recognize swayfx + "niri", // https://github.com/YaLTeR/niri + "dwm", // https://dwm.suckless.org/ + // "qtile", // TODO: find a way to recognize qtile + "awesome", // https://awesomewm.org/ + "river", // https://codeberg.org/river/river + "hyprland", // https://hypr.land/ + "bspwm", // https://github.com/baskerville/bspwm + "openbox", // https://openbox.org/ + }; + + inline for (supported_wms) |wm| { + if (std.ascii.eqlIgnoreCase(wm, proc_name_trimmed)) { + break :outer try allocator.dupe(u8, proc_name_trimmed); + } + } + } + + break :outer null; + }; + + return wm_name orelse allocator.dupe(u8, "Unknown"); +} From 19facc09ef697725ecd96407a69d63434df1360f Mon Sep 17 00:00:00 2001 From: utox39 Date: Sat, 4 Oct 2025 20:31:22 +0200 Subject: [PATCH 6/7] docs(README): update README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 3adaf95..fa14940 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,7 @@ Available modules: - Swap - Disk - Net +- WM (Window Manager) - Terminal - Locale - Custom @@ -111,6 +112,7 @@ Available modules: | swap | Yes | Yes | WIP | | disk | Yes | Yes | WIP | | net | Yes | Yes | WIP | +| wm | Yes | Yes | WIP | | terminal | Yes | Yes | WIP | | locale | Yes | Yes | WIP | From 8599fe92cf9e9ec3a4b47d4c67e9333f88a936e1 Mon Sep 17 00:00:00 2001 From: utox39 Date: Sat, 4 Oct 2025 20:36:09 +0200 Subject: [PATCH 7/7] build: bump version to 0.23.0 --- build.zig.zon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.zig.zon b/build.zig.zon index fa15cab..08ad23a 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -10,7 +10,7 @@ // This is a [Semantic Version](https://semver.org/). // In a future version of Zig it will be used for package deduplication. - .version = "0.22.0", + .version = "0.23.0", // Together with name, this represents a globally unique package // identifier. This field is generated by the Zig toolchain when the