stevee

My wayland statusbar
git clone git://gtms.dev/stevee
Log | Files | Refs | Submodules | README | LICENSE

commit 485b6cb9f94ffd7c7a057b3a7fc0bbb9460b2932
parent 4934bf6a9050f492e5ae8133eb0efb160e55835d
Author: Andrea Feletto <andrea@andreafeletto.com>
Date:   Tue, 12 Apr 2022 22:49:43 +0200

make module creation dynamic

Diffstat:
Msrc/Loop.zig | 2+-
Asrc/Modules.zig | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/main.zig | 27+++++++--------------------
Dsrc/modules.zig | 23-----------------------
Msrc/modules/Alsa.zig | 67+++++++++++++++++++++++++++++++++++++++++++++----------------------
Msrc/modules/Backlight.zig | 63+++++++++++++++++++++++++++++++--------------------------------
Msrc/modules/Battery.zig | 113+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Msrc/render.zig | 2+-
8 files changed, 196 insertions(+), 154 deletions(-)

diff --git a/src/Loop.zig b/src/Loop.zig @@ -50,7 +50,7 @@ pub fn run(self: *Loop) !void { .callbackOut = Event.noop, }); try events.append(gpa, try self.state.wayland.getEvent()); - for (self.state.modules.items) |*module| { + for (self.state.modules.modules.items) |*module| { try events.append(gpa, try module.getEvent()); } diff --git a/src/Modules.zig b/src/Modules.zig @@ -0,0 +1,53 @@ +const std = @import("std"); +const ArrayList = std.ArrayList; + +const Event = @import("Loop.zig").Event; +const State = @import("main.zig").State; +const Modules = @This(); + +state: *State, +modules: ArrayList(Module), + +pub const Alsa = @import("modules/Alsa.zig"); +pub const Backlight = @import("modules/Backlight.zig"); +pub const Battery = @import("modules/Battery.zig"); + +pub const Module = struct { + impl: *anyopaque, + funcs: struct { + getEvent: fn (*anyopaque) anyerror!Event, + print: fn (*anyopaque, StringWriter) anyerror!void, + destroy: fn (*anyopaque) void, + }, + + pub const StringWriter = std.ArrayList(u8).Writer; + + pub fn getEvent(self: *Module) !Event { + return self.funcs.getEvent(self.impl); + } + + pub fn print(self: *Module, writer: StringWriter) !void { + return self.funcs.print(self.impl, writer); + } + + pub fn destroyInstance(self: *Module) void { + return self.funcs.destroy(self.impl); + } +}; + +pub fn init(state: *State) Modules { + return Modules{ + .state = state, + .modules = ArrayList(Module).init(state.gpa), + }; +} + +pub fn deinit(self: *Modules) void { + for (self.modules.items) |*module| module.destroyInstance(); + self.modules.deinit(); +} + +pub fn register(self: *Modules, comptime ModuleType: type) !void { + const instance = try ModuleType.create(self.state); + try self.modules.append(try instance.module()); +} diff --git a/src/main.zig b/src/main.zig @@ -6,19 +6,15 @@ const fcft = @import("fcft"); const Config = @import("Config.zig"); const Loop = @import("Loop.zig"); -const modules = @import("modules.zig"); +const Modules = @import("Modules.zig"); const Wayland = @import("wayland.zig").Wayland; pub const State = struct { gpa: mem.Allocator, config: Config, wayland: Wayland, + modules: Modules, loop: Loop, - - alsa: modules.Alsa, - backlight: modules.Backlight, - battery: modules.Battery, - modules: std.ArrayList(modules.Module), }; pub fn main() anyerror!void { @@ -33,23 +29,14 @@ pub fn main() anyerror!void { state.config = try Config.init(); state.wayland = try Wayland.init(&state); defer state.wayland.deinit(); + state.modules = Modules.init(&state); + defer state.modules.deinit(); state.loop = try Loop.init(&state); // modules - state.modules = std.ArrayList(modules.Module).init(state.gpa); - defer state.modules.deinit(); - - state.alsa = try modules.Alsa.init(&state); - state.backlight = try modules.Backlight.init(&state); - defer state.backlight.deinit(); - state.battery = try modules.Battery.init(&state); - defer state.battery.deinit(); - - try state.modules.appendSlice(&.{ - try state.backlight.module(), - state.battery.module(), - state.alsa.module(), - }); + try state.modules.register(Modules.Alsa); + try state.modules.register(Modules.Backlight); + try state.modules.register(Modules.Battery); // event loop try state.wayland.registerGlobals(); diff --git a/src/modules.zig b/src/modules.zig @@ -1,23 +0,0 @@ -const std = @import("std"); - -const Event = @import("Loop.zig").Event; - -pub const Alsa = @import("modules/Alsa.zig"); -pub const Backlight = @import("modules/Backlight.zig"); -pub const Battery = @import("modules/Battery.zig"); - -pub const Module = struct { - impl: *anyopaque, - eventFn: fn (*anyopaque) anyerror!Event, - printFn: fn (*anyopaque, StringWriter) anyerror!void, - - pub const StringWriter = std.ArrayList(u8).Writer; - - pub fn getEvent(self: *Module) !Event { - return self.eventFn(self.impl); - } - - pub fn print(self: *Module, writer: StringWriter) !void { - return self.printFn(self.impl, writer); - } -}; diff --git a/src/modules/Alsa.zig b/src/modules/Alsa.zig @@ -6,7 +6,7 @@ const os = std.os; const alsa = @cImport(@cInclude("alsa/asoundlib.h")); -const Module = @import("../modules.zig").Module; +const Module = @import("../Modules.zig").Module; const Event = @import("../Loop.zig").Event; const render = @import("../render.zig"); const State = @import("../main.zig").State; @@ -14,20 +14,44 @@ const utils = @import("../utils.zig"); const Alsa = @This(); state: *State, -context: *alsa.snd_ctl_t, +devices: DeviceList, -pub fn init(state: *State) !Alsa { - return Alsa{ +const Device = struct { + ctl: *alsa.snd_ctl_t, + name: []const u8, +}; + +const DeviceList = std.ArrayList(Device); + +pub fn create(state: *State) !*Alsa { + const self = try state.gpa.create(Alsa); + self.* = .{ .state = state, - .context = try getAlsaCtl(state.gpa), + .devices = DeviceList.init(state.gpa), }; + + var card: i32 = -1; + while(alsa.snd_card_next(&card) >= 0 and card >= 0) { + const name = try fmt.allocPrintZ(state.gpa, "hw:{d}", .{ card }); + + var ctl: ?*alsa.snd_ctl_t = null; + _ = alsa.snd_ctl_open(&ctl, name.ptr, alsa.SND_CTL_READONLY); + _ = alsa.snd_ctl_subscribe_events(ctl, 1); + + try self.devices.append(.{ .ctl = ctl.?, .name = name }); + } + + return self; } -pub fn module(self: *Alsa) Module { - return .{ +pub fn module(self: *Alsa) !Module { + return Module{ .impl = @ptrCast(*anyopaque, self), - .eventFn = getEvent, - .printFn = print, + .funcs = .{ + .getEvent = getEvent, + .print = print, + .destroy = destroy, + }, }; } @@ -35,7 +59,8 @@ fn getEvent(self_opaque: *anyopaque) !Event { const self = utils.cast(Alsa)(self_opaque); var fd = mem.zeroes(alsa.pollfd); - _ = alsa.snd_ctl_poll_descriptors(self.context, &fd, 1); + const device = &self.devices.items[0]; + _ = alsa.snd_ctl_poll_descriptors(device.ctl, &fd, 1); return Event{ .fd = @bitCast(os.pollfd, fd), @@ -61,7 +86,6 @@ fn print(self_opaque: *anyopaque, writer: Module.StringWriter) !void { alsa.snd_mixer_selem_id_set_index(sid, 0); alsa.snd_mixer_selem_id_set_name(sid, "Master"); const elem = alsa.snd_mixer_find_selem(handle, sid); - _ = elem; var unmuted: i32 = 0; _ = alsa.snd_mixer_selem_get_playback_switch( @@ -98,7 +122,9 @@ fn callbackIn(self_opaque: *anyopaque) error{Terminate}!void { var event: ?*alsa.snd_ctl_event_t = null; _ = alsa.snd_ctl_event_malloc(&event); defer alsa.snd_ctl_event_free(event); - _ = alsa.snd_ctl_read(self.context, event); + + const device = &self.devices.items[0]; + _ = alsa.snd_ctl_read(device.ctl, event); for (self.state.wayland.monitors.items) |monitor| { if (monitor.bar) |bar| { @@ -113,15 +139,12 @@ fn callbackIn(self_opaque: *anyopaque) error{Terminate}!void { } } -fn getAlsaCtl(gpa: mem.Allocator) !*alsa.snd_ctl_t { - var card: i32 = -1; - _ = alsa.snd_card_next(&card); - const name = try fmt.allocPrintZ(gpa, "hw:{d}", .{ card }); - defer gpa.free(name); - - var ctl: ?*alsa.snd_ctl_t = null; - _ = alsa.snd_ctl_open(&ctl, name.ptr, alsa.SND_CTL_READONLY); - _ = alsa.snd_ctl_subscribe_events(ctl, 1); +fn destroy(self_opaque: *anyopaque) void { + const self = utils.cast(Alsa)(self_opaque); - return ctl.?; + for (self.devices.items) |*device| { + self.state.gpa.free(device.name); + } + self.devices.deinit(); + self.state.gpa.destroy(self); } diff --git a/src/modules/Backlight.zig b/src/modules/Backlight.zig @@ -5,7 +5,7 @@ const os = std.os; const udev = @import("udev"); -const Module = @import("../modules.zig").Module; +const Module = @import("../Modules.zig").Module; const Event = @import("../Loop.zig").Event; const render = @import("../render.zig"); const State = @import("../main.zig").State; @@ -21,51 +21,39 @@ const Device = struct { name: []const u8, value: u64, max: u64, - - pub fn deinit(self: *Device, gpa: mem.Allocator) void { - gpa.free(self.name); - } }; const DeviceList = std.ArrayList(Device); -pub fn init(state: *State) !Backlight { - const context = try udev.Udev.new(); - - const monitor = try udev.Monitor.newFromNetlink(context, "udev"); - try monitor.filterAddMatchSubsystemDevType("backlight", null); - try monitor.filterAddMatchSubsystemDevType("power_supply", null); - try monitor.enableReceiving(); +pub fn create(state: *State) !*Backlight { + const self = try state.gpa.create(Backlight); + self.state = state; + self.context = try udev.Udev.new(); - var devices = DeviceList.init(state.gpa); - try updateDevices(state.gpa, context, &devices); - if (devices.items.len == 0) return error.NoDevicesFound; + self.monitor = try udev.Monitor.newFromNetlink(self.context, "udev"); + try self.monitor.filterAddMatchSubsystemDevType("backlight", null); + try self.monitor.filterAddMatchSubsystemDevType("power_supply", null); + try self.monitor.enableReceiving(); - return Backlight{ - .state = state, - .context = context, - .monitor = monitor, - .devices = devices, - }; -} + self.devices = DeviceList.init(state.gpa); + try updateDevices(state.gpa, self.context, &self.devices); + if (self.devices.items.len == 0) return error.NoDevicesFound; -pub fn deinit(self: *Backlight) void { - _ = self.context.unref(); - for (self.devices.items) |*device| { - device.deinit(self.state.gpa); - } - self.devices.deinit(); + return self; } pub fn module(self: *Backlight) !Module { return Module{ .impl = @ptrCast(*anyopaque, self), - .eventFn = getEvent, - .printFn = print, + .funcs = .{ + .getEvent = getEvent, + .print = print, + .destroy = destroy, + }, }; } -pub fn getEvent(self_opaque: *anyopaque) !Event { +fn getEvent(self_opaque: *anyopaque) !Event { const self = utils.cast(Backlight)(self_opaque); return Event{ @@ -95,7 +83,7 @@ fn callbackIn(self_opaque: *anyopaque) error{Terminate}!void { } } -pub fn print(self_opaque: *anyopaque, writer: Module.StringWriter) !void { +fn print(self_opaque: *anyopaque, writer: Module.StringWriter) !void { const self = utils.cast(Backlight)(self_opaque); try updateDevices(self.state.gpa, self.context, &self.devices); @@ -148,3 +136,14 @@ fn updateOrAppend( device.value = try fmt.parseInt(u64, value, 10); device.max = try fmt.parseInt(u64, max, 10); } + +fn destroy(self_opaque: *anyopaque) void { + const self = utils.cast(Backlight)(self_opaque); + + _ = self.context.unref(); + for (self.devices.items) |*device| { + self.state.gpa.free(device.name); + } + self.devices.deinit(); + self.state.gpa.destroy(self); +} diff --git a/src/modules/Battery.zig b/src/modules/Battery.zig @@ -5,7 +5,7 @@ const os = std.os; const udev = @import("udev"); -const Module = @import("../modules.zig").Module; +const Module = @import("../Modules.zig").Module; const Event = @import("../Loop.zig").Event; const render = @import("../render.zig"); const State = @import("../main.zig").State; @@ -21,53 +21,44 @@ const Device = struct { name: []const u8, status: []const u8, capacity: u8, - - pub fn deinit(self: *Device, gpa: mem.Allocator) void { - gpa.free(self.name); - gpa.free(self.status); - } }; const DeviceList = std.ArrayList(Device); -pub fn init(state: *State) !Battery { - const tfd = os.linux.timerfd_create( - os.CLOCK.MONOTONIC, - os.linux.TFD.CLOEXEC, - ); - const interval: os.linux.itimerspec = .{ - .it_interval = .{ .tv_sec = 10, .tv_nsec = 0 }, - .it_value = .{ .tv_sec = 10, .tv_nsec = 0 }, +pub fn create(state: *State) !*Battery { + const self = try state.gpa.create(Battery); + self.state = state; + + self.timerFd = tfd: { + const fd = os.linux.timerfd_create( + os.CLOCK.MONOTONIC, + os.linux.TFD.CLOEXEC, + ); + const interval: os.linux.itimerspec = .{ + .it_interval = .{ .tv_sec = 10, .tv_nsec = 0 }, + .it_value = .{ .tv_sec = 10, .tv_nsec = 0 }, + }; + _ = os.linux.timerfd_settime(@intCast(i32, fd), 0, &interval, null); + break :tfd @intCast(os.fd_t, fd); }; - _ = os.linux.timerfd_settime(@intCast(i32, tfd), 0, &interval, null); - const context = try udev.Udev.new(); + self.context = try udev.Udev.new(); - var devices = DeviceList.init(state.gpa); - try updateDevices(state.gpa, context, &devices); - if (devices.items.len == 0) return error.NoDevicesFound; + self.devices = DeviceList.init(state.gpa); + try updateDevices(state.gpa, self.context, &self.devices); + if (self.devices.items.len == 0) return error.NoDevicesFound; - return Battery{ - .state = state, - .context = context, - .timerFd = @intCast(os.fd_t, tfd), - .devices = devices, - }; -} - -pub fn deinit(self: *Battery) void { - _ = self.context.unref(); - for (self.devices.items) |*device| { - device.deinit(self.state.gpa); - } - self.devices.deinit(); + return self; } -pub fn module(self: *Battery) Module { - return .{ +pub fn module(self: *Battery) !Module { + return Module{ .impl = @ptrCast(*anyopaque, self), - .eventFn = getEvent, - .printFn = print, + .funcs = .{ + .getEvent = getEvent, + .print = print, + .destroy = destroy, + }, }; } @@ -86,6 +77,36 @@ pub fn getEvent(self_opaque: *anyopaque) !Event { }; } +pub fn print(self_opaque: *anyopaque, writer: Module.StringWriter) !void { + const self = utils.cast(Battery)(self_opaque); + + try updateDevices(self.state.gpa, self.context, &self.devices); + const device = self.devices.items[0]; + + var icon: []const u8 = "❓"; + if (mem.eql(u8, device.status, "Discharging")) { + icon = "🔋"; + } else if (mem.eql(u8, device.status, "Charging")) { + icon = "🔌"; + } else if (mem.eql(u8, device.status, "Full")) { + icon = "⚡"; + } + + try fmt.format(writer, "{s} {d}%", .{ icon, device.capacity }); +} + +pub fn destroy(self_opaque: *anyopaque) void { + const self = utils.cast(Battery)(self_opaque); + + _ = self.context.unref(); + for (self.devices.items) |*device| { + self.state.gpa.free(device.name); + self.state.gpa.free(device.status); + } + self.devices.deinit(); + self.state.gpa.destroy(self); +} + fn callbackIn(self_opaque: *anyopaque) error{Terminate}!void { const self = utils.cast(Battery)(self_opaque); @@ -105,24 +126,6 @@ fn callbackIn(self_opaque: *anyopaque) error{Terminate}!void { } } -pub fn print(self_opaque: *anyopaque, writer: Module.StringWriter) !void { - const self = utils.cast(Battery)(self_opaque); - - try updateDevices(self.state.gpa, self.context, &self.devices); - const device = self.devices.items[0]; - - var icon: []const u8 = "❓"; - if (mem.eql(u8, device.status, "Discharging")) { - icon = "🔋"; - } else if (mem.eql(u8, device.status, "Charging")) { - icon = "🔌"; - } else if (mem.eql(u8, device.status, "Full")) { - icon = "⚡"; - } - - try fmt.format(writer, "{s} {d}%", .{ icon, device.capacity }); -} - fn updateDevices( gpa: mem.Allocator, context: *udev.Udev, diff --git a/src/render.zig b/src/render.zig @@ -121,7 +121,7 @@ pub fn renderModules(bar: *Bar) !void { defer string.deinit(); const writer = string.writer(); - for (state.modules.items) |*module| { + for (state.modules.modules.items) |*module| { try std.fmt.format(writer, " | ", .{}); try module.print(writer); }