11 Commits

Author SHA1 Message Date
utox39
12435bae0e Merge pull request #22 from utox39/feat/window-manager
fix(macos-wm): fix wrong array size
2025-10-04 21:07:25 +02:00
utox39
d26be667a1 fix(macos-wm): fix wrong array size 2025-10-04 21:05:16 +02:00
utox39
b3ca5ae9eb Merge pull request #21 from utox39/feat/window-manager
Feat/window manager
2025-10-04 20:42:12 +02:00
utox39
e30c6ccc73 Merge branch 'main' into feat/window-manager 2025-10-04 20:41:13 +02:00
utox39
8599fe92cf build: bump version to 0.23.0 2025-10-04 20:36:09 +02:00
utox39
19facc09ef docs(README): update README 2025-10-04 20:31:22 +02:00
utox39
62df4a52dc feat(linux): add window manager info 2025-10-04 17:15:41 +02:00
utox39
d6978cd4b2 feat(formatters): add window manager formatters 2025-10-03 12:50:19 +02:00
utox39
2f847fbef3 feat(config): add wm module 2025-10-03 12:40:54 +02:00
utox39
cec2b8068a feat(macos-wm): remove kwm from supported window managers 2025-09-20 01:05:59 +02:00
utox39
6564d85845 feat(macos): add window manager info 2025-09-15 14:59:24 +02:00
6 changed files with 136 additions and 1 deletions

View File

@@ -94,6 +94,7 @@ Available modules:
- Swap - Swap
- Disk - Disk
- Net - Net
- WM (Window Manager)
- Terminal - Terminal
- Locale - Locale
- Custom - Custom
@@ -111,6 +112,7 @@ Available modules:
| swap | Yes | Yes | WIP | | swap | Yes | Yes | WIP |
| disk | Yes | Yes | WIP | | disk | Yes | Yes | WIP |
| net | Yes | Yes | WIP | | net | Yes | Yes | WIP |
| wm | Yes | Yes | WIP |
| terminal | Yes | Yes | WIP | | terminal | Yes | Yes | WIP |
| locale | Yes | Yes | WIP | | locale | Yes | Yes | WIP |

View File

@@ -10,7 +10,7 @@
// This is a [Semantic Version](https://semver.org/). // This is a [Semantic Version](https://semver.org/).
// In a future version of Zig it will be used for package deduplication. // In a future version of Zig it will be used for package deduplication.
.version = "0.22.1", .version = "0.23.0",
// Together with name, this represents a globally unique package // Together with name, this represents a globally unique package
// identifier. This field is generated by the Zig toolchain when the // identifier. This field is generated by the Zig toolchain when the

View File

@@ -25,6 +25,7 @@ pub const ModuleType = enum {
swap, swap,
disk, disk,
net, net,
wm,
terminal, terminal,
locale, locale,
custom, custom,

View File

@@ -20,6 +20,7 @@ pub const formatters = [_]*const fn (allocator: std.mem.Allocator, key: []const
&getFormattedSwapInfo, &getFormattedSwapInfo,
&getFormattedDiskInfo, &getFormattedDiskInfo,
&getFormattedNetInfo, &getFormattedNetInfo,
&getFormattedWindowManagerInfo,
&getFormattedTerminalNameInfo, &getFormattedTerminalNameInfo,
&getFormattedLocaleInfo, &getFormattedLocaleInfo,
&getFormattedCustom, &getFormattedCustom,
@@ -37,6 +38,7 @@ pub const default_formatters = [_]*const fn (allocator: std.mem.Allocator) anyer
&getDefaultFormattedSwapInfo, &getDefaultFormattedSwapInfo,
&getDefaultFormattedDiskInfo, &getDefaultFormattedDiskInfo,
&getDefaultFormattedNetInfo, &getDefaultFormattedNetInfo,
&getDefaultFormattedWindowManagerInfo,
&getDefaultFormattedTerminalNameInfo, &getDefaultFormattedTerminalNameInfo,
&getDefaultFormattedLocaleInfo, &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 }) }; 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 { pub fn getDefaultFormattedTerminalNameInfo(allocator: std.mem.Allocator) !Result {
return try getFormattedTerminalNameInfo(allocator, "Terminal", ascii.Yellow); return try getFormattedTerminalNameInfo(allocator, "Terminal", ascii.Yellow);
} }

View File

@@ -98,3 +98,58 @@ pub fn getOsInfo(allocator: std.mem.Allocator) ![]u8 {
return try allocator.dupe(u8, pretty_name orelse "Unknown"); 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");
}

View File

@@ -128,3 +128,68 @@ pub fn getOsInfo(allocator: std.mem.Allocator) ![]u8 {
return os_info; 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: [6][]const u8 = .{
"aerospace",
"amethyst",
"chunkwm",
"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");
}