From ecda6104ac10be428c6b57b703eef6fd8f1df0a7 Mon Sep 17 00:00:00 2001 From: RadsammyT Date: Mon, 16 Mar 2026 20:54:00 -0400 Subject: [PATCH] custom info: less buggy --- src/config/custom.zig | 18 ++++++- src/config/migrator.zig | 38 ++++++++++++-- src/main.zig | 114 ++++++++++++++++++++++++++++++++++------ 3 files changed, 146 insertions(+), 24 deletions(-) diff --git a/src/config/custom.zig b/src/config/custom.zig index f60b4bc..676f537 100644 --- a/src/config/custom.zig +++ b/src/config/custom.zig @@ -2,11 +2,25 @@ const std = @import("std"); const custom = @This(); -pub const command = struct { +pub const customCommandBind = struct { name: []const u8 = undefined, cmd: []const u8 = undefined, posX: u32 = 0, posY: u32 = 0, }; -pub var mapping: std.StringHashMap(command) = undefined; +pub const customCommandInfo = struct { + cmd: []const u8 = undefined, + /// SET TO LABELS WIDGET ID!!! + id: u64 = 0, + + /// In milliseconds, the refresh rate for the `cmd` to run again + /// If 0, only run once. + refresh: u32 = 0, + counter: u32 = 0, + posX: u32 = 0, + posY: u32 = 0, +}; + +pub var binds: std.StringHashMap(customCommandBind) = undefined; +pub var labels: std.StringHashMap(customCommandInfo) = undefined; diff --git a/src/config/migrator.zig b/src/config/migrator.zig index e051a9f..3552086 100644 --- a/src/config/migrator.zig +++ b/src/config/migrator.zig @@ -165,13 +165,13 @@ pub fn configFieldHandler(_: std.mem.Allocator, field: ini.IniField) ?ini.IniFie if (std.mem.startsWith(u8, field.header, "cmd:")) { const key = field.header[4..]; const keyZ = temporary_allocator.dupe(u8, key) catch @panic("FUCK"); - if (!CustomCommands.mapping.contains(key)) { - CustomCommands.mapping.put(keyZ, .{}) catch |e| { - std.log.err("CustomCommands: {} while putting for key {s}", .{e, key}); - @panic("CustomCommands failed"); + if (!CustomCommands.binds.contains(key)) { + CustomCommands.binds.put(keyZ, .{}) catch |e| { + std.log.err("CustomCommands.binds: {} while putting for key {s}", .{e, key}); + @panic("CustomCommands.binds failed"); }; } - if (CustomCommands.mapping.getPtr(keyZ)) |command| { + if (CustomCommands.binds.getPtr(keyZ)) |command| { if (std.mem.eql(u8, field.key, "name")) { command.name = temporary_allocator.dupe(u8, field.value) catch { @panic("FUCK"); @@ -191,6 +191,34 @@ pub fn configFieldHandler(_: std.mem.Allocator, field: ini.IniField) ?ini.IniFie } } + if (std.mem.startsWith(u8, field.header, "lbl:")) { + const key = field.header[4..]; + const keyZ = temporary_allocator.dupe(u8, key) catch @panic("FUCK"); + if (!CustomCommands.labels.contains(keyZ)) { + CustomCommands.labels.put(keyZ, .{}) catch |e| { + std.log.err("CustomCommands.labels: {} while putting for key {s}", .{e, key}); + @panic("CustomCommands.labels failed"); + }; + } + if (CustomCommands.labels.getPtr(keyZ)) |label| { + if (std.mem.eql(u8, field.key, "cmd")) { + label.cmd = temporary_allocator.dupe(u8, field.value) catch { + @panic("FUCK"); + }; + } + if (std.mem.eql(u8, field.key, "posX")) { + label.posX = std.fmt.parseInt(u32, field.value, 10) catch blk: { break :blk 0; }; + } + if (std.mem.eql(u8, field.key, "posY")) { + label.posY = std.fmt.parseInt(u32, field.value, 10) catch blk: { break :blk 0; }; + } + if (std.mem.eql(u8, field.key, "refresh")) { + label.refresh = std.fmt.parseInt(u32, field.value, 10) catch blk: { break :blk 0; }; + } + + } + } + return field; } diff --git a/src/main.zig b/src/main.zig index 1a2da42..bb6bad5 100644 --- a/src/main.zig +++ b/src/main.zig @@ -65,12 +65,17 @@ fn ttyControlTransferSignalHandler(_: c_int) callconv(.c) void { TerminalBuffer.shutdown(); } -const CustomLabel = struct { - cmd: CustomCommands.command, +const CustomBindLabel = struct { + cmd: CustomCommands.customCommandBind, key: []const u8, lbl: Label }; +const CustomInfoLabel = struct { + info: CustomCommands.customCommandInfo, + lbl: Label +}; + const UiState = struct { allocator: Allocator, auth_fails: u64, @@ -114,7 +119,8 @@ const UiState = struct { bigclock_format_buf: [16:0]u8, clock_buf: [64:0]u8, bigclock_buf: [32:0]u8, - custom_commands: std.ArrayList(CustomLabel), + custom_binds: std.ArrayList(CustomBindLabel), + custom_info: std.ArrayList(CustomInfoLabel), }; var shutdown = false; @@ -150,7 +156,9 @@ pub fn main() !void { } } - var gpa = std.heap.DebugAllocator(.{}).init; + var gpa = std.heap.DebugAllocator(.{ + .retain_metadata = true, + }).init; defer _ = gpa.deinit(); state.allocator = gpa.allocator(); @@ -214,19 +222,26 @@ pub fn main() !void { const config_path = try std.fs.path.join(state.allocator, &[_][]const u8{ config_parent_path, "config.ini" }); defer state.allocator.free(config_path); - CustomCommands.mapping = .init(state.allocator); + CustomCommands.binds = .init(state.allocator); + CustomCommands.labels = .init(state.allocator); var config_parser = try IniParser(Config).init(state.allocator, config_path, migrator.configFieldHandler); defer config_parser.deinit(); // mapping.deinit() has to be done here defer { if (!shutdown or !restart) { - var iter = CustomCommands.mapping.iterator(); + var iter = CustomCommands.binds.iterator(); while (iter.next()) |i| { temporary_allocator.free(i.key_ptr.*); temporary_allocator.free(i.value_ptr.*.cmd); temporary_allocator.free(i.value_ptr.*.name); } - CustomCommands.mapping.deinit(); + CustomCommands.binds.deinit(); + var labelIter = CustomCommands.labels.iterator(); + while (labelIter.next()) |i| { + temporary_allocator.free(i.key_ptr.*); + temporary_allocator.free(i.value_ptr.*.cmd); + } + CustomCommands.labels.deinit(); } } @@ -1032,11 +1047,36 @@ pub fn main() !void { // Layer 2 var layer2: std.ArrayList(Widget) = .empty; - state.custom_commands = .empty; - defer state.custom_commands.deinit(state.allocator); + state.custom_binds = .empty; + state.custom_info = .empty; + defer state.custom_binds.deinit(state.allocator); + defer state.custom_info.deinit(state.allocator); defer layer2.deinit(state.allocator); + + var lblIter = CustomCommands.labels.iterator(); + while (lblIter.next()) |i| { + var w = Label.init("", + null, + state.buffer.fg, + state.buffer.bg, + &updateCustomInfo, + null, + ); + i.value_ptr.id = w.widget().id; + i.value_ptr.counter = 2; + try state.custom_info.append(state.allocator, .{ + .info = i.value_ptr.*, + .lbl = w + }); + } + defer { + for (state.custom_info.items) |*item| { + state.allocator.free(item.lbl.text); + item.lbl.deinit(); + } + } - var iter = CustomCommands.mapping.iterator(); + var iter = CustomCommands.binds.iterator(); while (iter.next()) |i| { const concat = try std.mem.concat(state.allocator, u8, &[_][]u8{ @@ -1045,7 +1085,7 @@ pub fn main() !void { @constCast(i.value_ptr.name) } ); - try state.custom_commands.append(state.allocator, .{ + try state.custom_binds.append(state.allocator, .{ .lbl = .init( concat, null, @@ -1057,10 +1097,10 @@ pub fn main() !void { .cmd = i.value_ptr.*, .key = i.key_ptr.*, }); - state.custom_commands.items[state.custom_commands.items.len-1].lbl.allocator = state.allocator; + state.custom_binds.items[state.custom_binds.items.len-1].lbl.allocator = state.allocator; } defer { - for (state.custom_commands.items) |*i| { + for (state.custom_binds.items) |*i| { i.lbl.deinit(); } } @@ -1104,7 +1144,10 @@ pub fn main() !void { try layer2.append(state.allocator, state.version_label.widget()); } - for (state.custom_commands.items) |*item| { + for (state.custom_binds.items) |*item| { + try layer2.append(state.allocator, item.lbl.widget()); + } + for (state.custom_info.items) |*item| { try layer2.append(state.allocator, item.lbl.widget()); } @@ -1116,7 +1159,7 @@ pub fn main() !void { try widgets.append(state.allocator, &layer3); } - for (state.custom_commands.items) |*item| { + for (state.custom_binds.items) |*item| { try state.buffer.registerKeybind(item.key, &customCommand, item); } @@ -1270,7 +1313,7 @@ fn quit(ptr: *anyopaque) !bool { } fn customCommand(ptr: *anyopaque) !bool { - const lbl: *CustomLabel = @ptrCast(@alignCast(ptr)); + const lbl: *CustomBindLabel = @ptrCast(@alignCast(ptr)); var proc = std.process.Child.init(&[_][]const u8 { "/bin/sh", "-c", @@ -1669,6 +1712,38 @@ fn updateClock(self: *Label, ptr: *anyopaque) !void { } } +fn updateCustomInfo(lbl: *Label, ptr: *anyopaque) !void { + const state: *UiState = @ptrCast(@alignCast(ptr)); + const wid = lbl.widget().id; + var stdout = std.ArrayList(u8).empty; + defer stdout.deinit(state.allocator); + var stderr = std.ArrayList(u8).empty; + defer stderr.deinit(state.allocator); + for (state.custom_info.items) |*i| { + if (i.info.id != wid) continue; + if (i.info.counter == 1) { + var c = std.process.Child.init(&[_][]const u8 { + "/bin/sh", + "-c", + i.info.cmd + }, state.allocator); + c.stderr_behavior = .Pipe; + c.stdout_behavior = .Pipe; + try c.spawn(); + try c.collectOutput(state.allocator, &stdout, &stderr, 128); + _ = try c.wait(); + state.allocator.free(lbl.text); + if (std.ascii.isAscii(stdout.items[stdout.items.len-1])) _ = stdout.pop(); + lbl.text = try state.allocator.dupe(u8, stdout.items); + if (i.info.refresh != 0) + i.info.counter = i.info.refresh; + break; + } + i.info.counter -= 1; + + } +} + fn calculateClockTimeout(_: *Label, _: *anyopaque) !?usize { const time = try interop.getTimeOfDay(); @@ -1747,11 +1822,16 @@ fn positionWidgets(ptr: *anyopaque) !void { state.brightness_up_label.positionXY(state.brightness_down_label .childrenPosition() .addX(1)); - for (state.custom_commands.items) |*item| { + for (state.custom_binds.items) |*item| { item.lbl.positionXY(state.edge_margin .addX(@intCast(item.cmd.posX)) .addY(@intCast(item.cmd.posY))); } + for (state.custom_info.items) |*item| { + item.lbl.positionXY(state.edge_margin + .addX(@intCast(item.info.posX)) + .addY(@intCast(item.info.posY))); + } } state.battery_label.positionXY(state.edge_margin