diff --git a/src/bar/bar.zig b/src/bar/bar.zig index d2c60a9..f11a1a7 100644 --- a/src/bar/bar.zig +++ b/src/bar/bar.zig @@ -142,11 +142,18 @@ pub const Bar = struct { // First number is just the mouse event, skip processing it for now. // TODO: map mouse click and scroll events to the right enum value. _ = it.next(); - const click_x_position = try std.fmt.parseInt(u64, it.next().?, 10); - var y = it.next().?; + var x = it.next(); + var y = it.next(); + if (x == null) { + continue; + } + if (y == null) { + continue; + } + const click_x_position = try std.fmt.parseInt(u64, x.?, 10); // This makes it so it only works on the end of a click not the start // preventing a single click pressing the button twice. - if (y[y.len - 1] == 'm') continue; + if (y.?[y.?.len - 1] == 'm') continue; var current_info_line_length: u64 = 0; for (self.infos.items) |infoItem, index| { @@ -228,10 +235,14 @@ pub const Bar = struct { while (self.running) { if (terminal_version) { if (!disable_terminal_mouse) { - self.terminal_input_process() catch |err| { log.err(.bar, "failed to process terminal input: {}\n", .{err}); }; + self.terminal_input_process() catch |err| { + log.err(.bar, "failed to process terminal input: {}\n", .{err}); + }; } } else { - self.i3bar_input_process() catch |err| { log.err(.bar, "failed to process i3bar input: {}\n", .{err}); }; + self.i3bar_input_process() catch |err| { + log.err(.bar, "failed to process i3bar input: {}\n", .{err}); + }; } } } @@ -245,7 +256,7 @@ pub const Bar = struct { const name_size = info.name.len * @sizeOf(u8); const text_size = info.full_text.len * @sizeOf(u8); const total_size = name_size + text_size; - log.debug(.bar, "Freeing info for \"{}\", name_size={} text_size={} total={}\n", .{info.name, name_size, text_size, total_size}); + //log.debug(.bar, "Freeing info for \"{}\", name_size={} text_size={} total={}\n", .{ info.name, name_size, text_size, total_size }); self.allocator.free(info.name); self.allocator.free(info.full_text); } @@ -257,7 +268,7 @@ pub const Bar = struct { const name_size = info.name.len * @sizeOf(u8); const text_size = info.full_text.len * @sizeOf(u8); const total_size = name_size + text_size; - log.debug(.bar, "Duping info for \"{}\", name_size={} text_size={} total={}\n", .{info.name, name_size, text_size, total_size}); + //log.debug(.bar, "Duping info for \"{}\", name_size={} text_size={} total={}\n", .{ info.name, name_size, text_size, total_size }); const new_name = try self.allocator.alloc(u8, info.name.len); std.mem.copy(u8, new_name, info.name); const new_text = try self.allocator.alloc(u8, info.full_text.len); diff --git a/src/main.zig b/src/main.zig index 12b971e..cc16c8d 100644 --- a/src/main.zig +++ b/src/main.zig @@ -10,7 +10,7 @@ const timeWidget = @import("widgets/time/time.zig"); const batteryWidget = @import("widgets/battery/battery.zig"); const memoryWidget = @import("widgets/memory/memory.zig"); const cpuWidget = @import("widgets/cpu/cpu.zig"); -const marqueeTextWidget = @import("widgets/marqueetext/marqueetext.zig"); +const networkWidget = @import("widgets/network/network.zig"); const DebugAllocator = @import("debug_allocator.zig"); const Info = @import("types/info.zig"); @@ -56,7 +56,9 @@ pub fn main() !void { dbgAlloc = &DebugAllocator.init(std.heap.page_allocator, 8192 * 8192); allocator = &dbgAlloc.allocator; } else { - allocator = std.heap.page_allocator; + var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); + defer arena.deinit(); + allocator = &arena.allocator; } var bar = barImpl.initBar(allocator); var br = Bar.init(&bar); @@ -64,6 +66,8 @@ pub fn main() !void { const widgets = [_]*Widget{ //&Widget.init(&textWidget.New("owo", "potato")), // 4KiB //&Widget.init(&textWidget.New("uwu", "tomato")), // 4KiB + &Widget.init(&networkWidget.New(allocator, &br)), // 4.08KiB + &Widget.init(&cpuWidget.New(&br)), // 4.08KiB &Widget.init(&memoryWidget.New(&br)), // 4.08KiB &Widget.init(&weatherWidget.New(allocator, &br, @import("build_options").weather_location)), // 16.16KiB diff --git a/src/widgets/cpu/cpu.zig b/src/widgets/cpu/cpu.zig index 4906902..ef9aa1b 100644 --- a/src/widgets/cpu/cpu.zig +++ b/src/widgets/cpu/cpu.zig @@ -108,7 +108,14 @@ pub const CPUWidget = struct { } pub fn start(self: *CPUWidget) anyerror!void { - //try self.update_bar(); + if (@import("builtin").os.tag != .linux) { + try self.bar.add(Info{ + .name = "cpu", + .full_text = "unsupported OS", + .markup = "pango", + }); + return; + } while (self.bar.keep_running()) { try self.update_bar(); } diff --git a/src/widgets/memory/memory.zig b/src/widgets/memory/memory.zig index 7020922..5a2f2b0 100644 --- a/src/widgets/memory/memory.zig +++ b/src/widgets/memory/memory.zig @@ -5,6 +5,7 @@ const colour = @import("../../formatting/colour.zig").colour; const comptimeColour = @import("../../formatting/colour.zig").comptimeColour; const MouseEvent = @import("../../types/mouseevent.zig"); const LoopingCounter = @import("../../types/loopingcounter.zig").LoopingCounter; +const log = std.log; const MemInfo = struct { memTotal: u64, @@ -180,6 +181,15 @@ pub const MemoryWidget = struct { } pub fn start(self: *MemoryWidget) anyerror!void { + if (@import("builtin").os.tag != .linux) { + try self.bar.add(Info{ + .name = "mem", + .full_text = "unsupported OS", + .markup = "pango", + }); + return; + } + while (self.bar.keep_running()) { self.update_bar() catch {}; std.time.sleep(500 * std.time.ns_per_ms); diff --git a/src/widgets/network/network.zig b/src/widgets/network/network.zig new file mode 100644 index 0000000..c7d6873 --- /dev/null +++ b/src/widgets/network/network.zig @@ -0,0 +1,159 @@ +const std = @import("std"); +const Info = @import("../../types/info.zig"); +const MouseEvent = @import("../../types/mouseevent.zig"); +const Bar = @import("../../types/bar.zig").Bar; +const fs = std.fs; +const cwd = fs.cwd; +const colour = @import("../../formatting/colour.zig").colour; +const comptimeColour = @import("../../formatting/colour.zig").comptimeColour; +const eql = std.mem.eql; + +pub const NetworkType = enum(u2) { + WiFi = 0, + Ethernet = 1, + Unknown = 2, +}; + +fn toNetworkType(str: []const u8) NetworkType { + if (eql(u8, str, "wifi")) return NetworkType.WiFi; + if (eql(u8, str, "ethernet")) return NetworkType.Ethernet; + return NetworkType.Unknown; +} + +pub const NetworkStatus = enum(u3) { + Connected = 0, + Disconnected = 1, + Unavailable = 2, + Unmanaged = 3, + Unknown = 4, +}; + +fn toNetworkStatus(str: []const u8) NetworkStatus { + if (eql(u8, str, "connected")) return NetworkStatus.Connected; + if (eql(u8, str, "disconnected")) return NetworkStatus.Disconnected; + if (eql(u8, str, "unavailable")) return NetworkStatus.Unavailable; + if (eql(u8, str, "unmanaged")) return NetworkStatus.Unmanaged; + return NetworkStatus.Unknown; +} + +fn networkStatusToColour(s: NetworkStatus) []const u8 { + return switch(s) { + .Connected => "green", + .Disconnected => "red", + else => "darkest" + }; +} + + +pub const NetworkInfo = struct { + network_type: NetworkType = .WiFi, + network_status: NetworkStatus = .Connected, + network_info: [32]u8 = [32]u8{' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}, + network_info_len: usize, +}; + +pub const NetworkWidget = struct { + bar: *Bar, + allocator: *std.mem.Allocator, + network_infos: std.ArrayList(NetworkInfo), + num_interfaces: u8 = 0, + current_interface: u8 = 0, + update_mutex: std.Mutex = std.Mutex.init(), + + pub fn name(self: *NetworkWidget) []const u8 { + return "network"; + } + pub fn initial_info(self: *NetworkWidget) Info { + return Info{ + .name = "network", + .full_text = "network", + .markup = "pango", + }; + } + pub fn mouse_event(self: *NetworkWidget, event: MouseEvent) void { + { + const lock = self.update_mutex.acquire(); + defer lock.release(); + if (self.num_interfaces == self.current_interface) { + self.current_interface = 0; + } else { + self.current_interface += 1; + } + } + self.update_bar() catch |err| { + std.log.err(.network, "Error! {}\n", .{err}); + }; + } + + pub fn update_network_infos(self: *NetworkWidget) anyerror!void { + const lock = self.update_mutex.acquire(); + defer lock.release(); + self.network_infos.shrink(0); + self.num_interfaces = 0; + var arena = std.heap.ArenaAllocator.init(self.allocator); + defer arena.deinit(); + var allocator = &arena.allocator; + var proc = try std.ChildProcess.init(&[_][]const u8{ "nmcli", "-f", "common", "-c", "no", "d" }, allocator); + proc.stdout_behavior = .Pipe; + try proc.spawn(); + if (proc.stdout) |stdout| { + var line_buffer: [128]u8 = undefined; + // Skip header. + _ = try stdout.reader().readUntilDelimiterOrEof(&line_buffer, '\n'); + + while (try stdout.reader().readUntilDelimiterOrEof(&line_buffer, '\n')) |row| { + var it = std.mem.tokenize(row, " "); + _ = it.next(); // Skip interface name + const connection_type = it.next(); + const status = it.next(); + const description = it.next(); + if (connection_type) |t| if (!(eql(u8, t, "wifi") or eql(u8, t, "ethernet"))) continue; + var net_info = NetworkInfo{ + .network_type = toNetworkType(connection_type.?), + .network_status = toNetworkStatus(status.?), + .network_info_len = description.?.len, + }; + std.mem.copy(u8, net_info.network_info[0..description.?.len], description.?[0..description.?.len]); + + try self.network_infos.append(net_info); + self.num_interfaces += 1; + } + } + } + + pub fn update_bar(self: *NetworkWidget) anyerror!void { + var arena = std.heap.ArenaAllocator.init(self.allocator); + defer arena.deinit(); + var allocator = &arena.allocator; + for (self.network_infos.items) |info, i| { + if (i != self.current_interface) continue; + //std.log.debug(.network, "item! {} {}\n", .{ info, i }); + + try self.bar.add(Info{ + .name = "network", + .full_text = try colour(allocator, networkStatusToColour(info.network_status), try std.fmt.allocPrint(allocator, "{} {}", .{@tagName(info.network_type), info.network_info[0..info.network_info_len]})), + .markup = "pango", + }); + } + } + + pub fn start(self: *NetworkWidget) anyerror!void { + var arena = std.heap.ArenaAllocator.init(self.allocator); + defer arena.deinit(); + var allocator = &arena.allocator; + self.network_infos = std.ArrayList(NetworkInfo).init(allocator); + while (self.bar.keep_running()) { + try self.update_network_infos(); + try self.update_bar(); + std.time.sleep(std.time.ns_per_s); + } + } +}; + +pub inline fn New(allocator: *std.mem.Allocator, bar: *Bar) NetworkWidget { + return NetworkWidget{ + .allocator = allocator, + .bar = bar, + .network_infos = undefined, + }; +}