commit a28f39e9f7014e1cea6976522693c0ec740d094f
parent c0f0e5a8160064e8dfbf98b7895a4dab9a03ffd9
Author: Andrea Feletto <andrea@andreafeletto.com>
Date: Thu, 30 Jun 2022 18:31:01 +0200
remove inheritance for modules
Diffstat:
9 files changed, 255 insertions(+), 376 deletions(-)
diff --git a/src/Loop.zig b/src/Loop.zig
@@ -10,24 +10,6 @@ const Loop = @This();
state: *State,
sfd: os.fd_t,
-pub const Event = struct {
- fd: os.pollfd,
- data: *anyopaque,
- callbackIn: Callback,
- callbackOut: Callback,
-
- pub const Action = enum { ok, terminate };
- pub const Callback = fn (*anyopaque) Action;
-
- pub fn terminate(_: *anyopaque) Action {
- return .terminate;
- }
-
- pub fn noop(_: *anyopaque) Action {
- return .ok;
- }
-};
-
pub fn init(state: *State) !Loop {
var mask = os.empty_sigset;
os.linux.sigaddset(&mask, os.linux.SIG.INT);
@@ -41,56 +23,82 @@ pub fn init(state: *State) !Loop {
}
pub fn run(self: *Loop) !void {
- const gpa = self.state.gpa;
- const display = self.state.wayland.display;
+ const wayland = &self.state.wayland;
+ const modules = &self.state.modules;
+
+ var fds = [_]os.pollfd{
+ .{
+ .fd = self.sfd,
+ .events = os.POLL.IN,
+ .revents = undefined,
+ },
+ .{
+ .fd = wayland.fd,
+ .events = os.POLL.IN,
+ .revents = undefined,
+ },
+ .{
+ .fd = if (modules.backlight) |mod| mod.fd else -1,
+ .events = os.POLL.IN,
+ .revents = undefined,
+ },
+ .{
+ .fd = if (modules.battery) |mod| mod.fd else -1,
+ .events = os.POLL.IN,
+ .revents = undefined,
+ },
+ .{
+ .fd = if (modules.pulse) |mod| mod.fd else -1,
+ .events = os.POLL.IN,
+ .revents = undefined,
+ },
+ };
- var events: std.MultiArrayList(Event) = .{};
- defer events.deinit(gpa);
-
- try events.append(gpa, .{
- .fd = .{ .fd = self.sfd, .events = os.POLL.IN, .revents = 0 },
- .data = undefined,
- .callbackIn = Event.terminate,
- .callbackOut = Event.noop,
- });
- try events.append(gpa, try self.state.wayland.getEvent());
- for (self.state.modules.modules.items) |*module| {
- try events.append(gpa, try module.getEvent());
- }
-
- const fds = events.items(.fd);
while (true) {
while (true) {
- const ret = display.dispatchPending();
- _ = display.flush();
+ const ret = wayland.display.dispatchPending();
+ _ = wayland.display.flush();
if (ret == .SUCCESS) break;
}
- _ = os.poll(fds, -1) catch |err| {
+ _ = os.poll(&fds, -1) catch |err| {
log.err("poll failed: {s}", .{@errorName(err)});
return;
};
- for (fds) |fd, i| {
- if (fd.revents & os.POLL.HUP != 0) return;
- if (fd.revents & os.POLL.ERR != 0) return;
-
- if (fd.revents & os.POLL.IN != 0) {
- const event = events.get(i);
- const action = event.callbackIn(event.data);
- switch (action) {
- .ok => {},
- .terminate => return,
- }
- }
- if (fd.revents & os.POLL.OUT != 0) {
- const event = events.get(i);
- const action = event.callbackOut(event.data);
- switch (action) {
- .ok => {},
- .terminate => return,
- }
+ for (fds) |fd| {
+ if (fd.revents & os.POLL.HUP != 0 or fd.revents & os.POLL.ERR != 0) {
+ return;
}
}
+
+ // signals
+ if (fds[0].revents & os.POLL.IN != 0) {
+ return;
+ }
+
+ // wayland
+ if (fds[1].revents & os.POLL.IN != 0) {
+ const errno = wayland.display.dispatch();
+ if (errno != .SUCCESS) return;
+ }
+ if (fds[1].revents & os.POLL.OUT != 0) {
+ const errno = wayland.display.flush();
+ if (errno != .SUCCESS) return;
+ }
+
+ // modules
+ if (modules.backlight) |*mod| if (fds[2].revents & os.POLL.IN != 0) {
+ log.info("backlight", .{});
+ mod.refresh() catch return;
+ };
+ if (modules.battery) |*mod| if (fds[3].revents & os.POLL.IN != 0) {
+ log.info("battery", .{});
+ mod.refresh() catch return;
+ };
+ if (modules.pulse) |*mod| if (fds[4].revents & os.POLL.IN != 0) {
+ log.info("pulse", .{});
+ mod.refresh() catch return;
+ };
}
}
diff --git a/src/Modules.zig b/src/Modules.zig
@@ -1,55 +1,48 @@
const std = @import("std");
+const mem = std.mem;
const ArrayList = std.ArrayList;
-const log = std.log;
-const Event = @import("Loop.zig").Event;
const State = @import("main.zig").State;
const Modules = @This();
-state: *State,
-modules: ArrayList(Module),
-
-pub const Backlight = @import("modules/Backlight.zig");
-pub const Battery = @import("modules/Battery.zig");
-pub const Pulse = @import("modules/Pulse.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);
- }
+const Backlight = @import("modules/Backlight.zig");
+const Battery = @import("modules/Battery.zig");
+const Pulse = @import("modules/Pulse.zig");
- pub fn print(self: *Module, writer: StringWriter) !void {
- return self.funcs.print(self.impl, writer);
- }
+const Tag = enum { backlight, battery, pulse };
- pub fn destroyInstance(self: *Module) void {
- return self.funcs.destroy(self.impl);
- }
-};
+state: *State,
+backlight: ?Backlight = null,
+battery: ?Battery = null,
+pulse: ?Pulse = null,
+order: ArrayList(Tag),
pub fn init(state: *State) Modules {
return Modules{
.state = state,
- .modules = ArrayList(Module).init(state.gpa),
+ .order = ArrayList(Tag).init(state.gpa),
};
}
pub fn deinit(self: *Modules) void {
- for (self.modules.items) |*module| module.destroyInstance();
- self.modules.deinit();
+ if (self.backlight) |*mod| mod.deinit();
+ if (self.battery) |*mod| mod.deinit();
+ if (self.pulse) |*mod| mod.deinit();
+ self.order.deinit();
}
-pub fn register(self: *Modules, comptime ModuleType: type) !void {
- const instance = try ModuleType.create(self.state);
- try self.modules.append(try instance.module());
- log.info("registered module: {s}", .{@typeName(ModuleType)});
+pub fn register(self: *Modules, name: []const u8) !void {
+ if (mem.eql(u8, name, "backlight")) {
+ self.backlight = try Backlight.init(self.state);
+ try self.order.append(.backlight);
+ } else if (mem.eql(u8, name, "battery")) {
+ self.battery = try Battery.init(self.state);
+ try self.order.append(.battery);
+ } else if (mem.eql(u8, name, "pulse")) {
+ self.pulse = try Pulse.init(self.state);
+ try self.pulse.?.start();
+ try self.order.append(.pulse);
+ } else {
+ return error.UnknownModule;
+ }
}
diff --git a/src/Wayland.zig b/src/Wayland.zig
@@ -21,6 +21,7 @@ const Wayland = @This();
state: *State,
display: *wl.Display,
+fd: os.fd_t,
monitors: ArrayList(*Monitor),
inputs: ArrayList(*Input),
@@ -39,13 +40,16 @@ const Globals = struct {
const GlobalsMask = utils.Mask(Globals);
pub fn init(state: *State) !Wayland {
- const display = wl.Display.connect(null) catch |err| {
- utils.fatal("failed to connect to a wayland compositor: {s}", .{@errorName(err)});
+ const display = try wl.Display.connect(null);
+ const wfd = wfd: {
+ const fd = display.getFd();
+ break :wfd @intCast(os.fd_t, fd);
};
return Wayland{
.state = state,
.display = display,
+ .fd = wfd,
.monitors = ArrayList(*Monitor).init(state.gpa),
.inputs = ArrayList(*Input).init(state.gpa),
.globals = undefined,
@@ -69,53 +73,33 @@ pub fn deinit(self: *Wayland) void {
}
pub fn registerGlobals(self: *Wayland) !void {
- const registry = self.display.getRegistry() catch |err| {
- utils.fatal("out of memory during initialization: {s}", .{@errorName(err)});
- };
+ const registry = try self.display.getRegistry();
defer registry.destroy();
registry.setListener(*State, registryListener, self.state);
const errno = self.display.roundtrip();
- if (errno != .SUCCESS) {
- utils.fatal("initial roundtrip failed", .{});
- }
-
+ if (errno != .SUCCESS) return error.RoundtripFailed;
for (self.globalsMask) |is_registered| if (!is_registered) {
- utils.fatal("global not advertised", .{});
- };
-}
-
-pub fn getEvent(self: *Wayland) !Event {
- const fd = self.display.getFd();
-
- return Event{
- .fd = .{
- .fd = @intCast(os.fd_t, fd),
- .events = os.POLL.IN,
- .revents = undefined,
- },
- .data = @ptrCast(*anyopaque, self),
- .callbackIn = dispatch,
- .callbackOut = flush,
+ return error.GlobalNotAdvertized;
};
}
-fn dispatch(self_opaque: *anyopaque) Event.Action {
- const self = utils.cast(Wayland)(self_opaque);
- const errno = self.display.dispatch();
- switch (errno) {
- .SUCCESS => return .ok,
- else => return .terminate,
+pub fn findBar(self: *Wayland, wlSurface: ?*wl.Surface) ?*Bar {
+ if (wlSurface == null) {
+ return null;
}
-}
-
-fn flush(self_opaque: *anyopaque) Event.Action {
- const self = utils.cast(Wayland)(self_opaque);
- const errno = self.display.flush();
- switch (errno) {
- .SUCCESS => return .ok,
- else => return .terminate,
+ for (self.monitors.items) |monitor| {
+ if (monitor.bar) |bar| {
+ if (bar.background.surface == wlSurface or
+ bar.tags.surface == wlSurface or
+ bar.clock.surface == wlSurface or
+ bar.modules.surface == wlSurface)
+ {
+ return bar;
+ }
+ }
}
+ return null;
}
fn registryListener(registry: *wl.Registry, event: wl.Registry.Event, state: *State) void {
@@ -146,7 +130,10 @@ fn registryListener(registry: *wl.Registry, event: wl.Registry.Event, state: *St
fn bindGlobal(self: *Wayland, registry: *wl.Registry, name: u32, iface: [*:0]const u8, version: u32) !void {
if (strcmp(iface, wl.Compositor.getInterface().name) == 0) {
- if (version < 4) utils.fatal("wl_compositor version 4 is required", .{});
+ if (version < 4) {
+ log.err("wl_compositor version 4 is required", .{});
+ return;
+ }
const global = try registry.bind(name, wl.Compositor, 4);
self.setGlobal(global);
} else if (strcmp(iface, wl.Subcompositor.getInterface().name) == 0) {
@@ -168,17 +155,23 @@ fn bindGlobal(self: *Wayland, registry: *wl.Registry, name: u32, iface: [*:0]con
const global = try registry.bind(name, zriver.ControlV1, 1);
self.setGlobal(global);
} else if (strcmp(iface, wl.Output.getInterface().name) == 0) {
- if (version < 3) utils.fatal("wl_output version 3 is required", .{});
+ if (version < 3) {
+ log.err("wl_output version 3 is required", .{});
+ return;
+ }
const monitor = try Monitor.create(self.state, registry, name);
try self.monitors.append(monitor);
} else if (strcmp(iface, wl.Seat.getInterface().name) == 0) {
- if (version < 5) utils.fatal("wl_seat version 5 is required", .{});
+ if (version < 5) {
+ log.err("wl_seat version 5 is required", .{});
+ return;
+ }
const input = try Input.create(self.state, registry, name);
try self.inputs.append(input);
}
}
-pub fn setGlobal(self: *Wayland, global: anytype) void {
+fn setGlobal(self: *Wayland, global: anytype) void {
inline for (meta.fields(Globals)) |field, i| {
if (field.field_type == @TypeOf(global)) {
@field(self.globals, field.name) = global;
@@ -187,21 +180,3 @@ pub fn setGlobal(self: *Wayland, global: anytype) void {
}
}
}
-
-pub fn findBar(self: *Wayland, wlSurface: ?*wl.Surface) ?*Bar {
- if (wlSurface == null) {
- return null;
- }
- for (self.monitors.items) |monitor| {
- if (monitor.bar) |bar| {
- if (bar.background.surface == wlSurface or
- bar.tags.surface == wlSurface or
- bar.clock.surface == wlSurface or
- bar.modules.surface == wlSurface)
- {
- return bar;
- }
- }
- }
- return null;
-}
diff --git a/src/main.zig b/src/main.zig
@@ -42,21 +42,24 @@ pub fn main() anyerror!void {
const program_name = args.nextPosix() orelse unreachable;
while (args.nextPosix()) |arg| {
- if (mem.eql(u8, arg, "backlight")) {
- try state.modules.register(Modules.Backlight);
- } else if (mem.eql(u8, arg, "battery")) {
- try state.modules.register(Modules.Battery);
- } else if (mem.eql(u8, arg, "pulse")) {
- try state.modules.register(Modules.Pulse);
- } else {
- try help(program_name);
+ if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
+ help(program_name);
return;
}
- }
-
- if (state.modules.modules.items.len == 0) {
- try help(program_name);
- return;
+ state.modules.register(arg) catch |err| {
+ switch (err) {
+ error.UnknownModule => {
+ log.err("unknown module: {s}", .{arg});
+ },
+ else => {
+ log.err(
+ "initialization error for module {s}: {s}",
+ .{ arg, @errorName(err) },
+ );
+ },
+ }
+ return;
+ };
}
// event loop
@@ -64,8 +67,8 @@ pub fn main() anyerror!void {
try state.loop.run();
}
-fn help(program_name: []const u8) !void {
- const help_text =
+fn help(program_name: []const u8) void {
+ const text =
\\Usage: {s} [module]...
\\
\\Available modules:
@@ -74,5 +77,6 @@ fn help(program_name: []const u8) !void {
\\ pulse speaker volume with pulseaudio
\\
;
- try io.getStdErr().writer().print(help_text, .{program_name});
+ const w = io.getStdErr().writer();
+ w.print(text, .{program_name}) catch unreachable;
}
diff --git a/src/modules/Backlight.zig b/src/modules/Backlight.zig
@@ -6,8 +6,6 @@ const os = std.os;
const udev = @import("udev");
-const Module = @import("../Modules.zig").Module;
-const Event = @import("../Loop.zig").Event;
const render = @import("../render.zig");
const State = @import("../main.zig").State;
const utils = @import("../utils.zig");
@@ -16,6 +14,7 @@ const Backlight = @This();
state: *State,
context: *udev.Udev,
monitor: *udev.Monitor,
+fd: os.fd_t,
devices: DeviceList,
const Device = struct {
@@ -26,56 +25,36 @@ const Device = struct {
const DeviceList = std.ArrayList(Device);
-pub fn create(state: *State) !*Backlight {
- const self = try state.gpa.create(Backlight);
- self.state = state;
- self.context = try udev.Udev.new();
+pub fn init(state: *State) !Backlight {
+ const context = try udev.Udev.new();
- 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();
+ const monitor = try udev.Monitor.newFromNetlink(context, "udev");
+ try monitor.filterAddMatchSubsystemDevType("backlight", null);
+ try monitor.filterAddMatchSubsystemDevType("power_supply", null);
+ try monitor.enableReceiving();
- self.devices = DeviceList.init(state.gpa);
- try updateDevices(state.gpa, self.context, &self.devices);
- if (self.devices.items.len == 0) return error.NoDevicesFound;
+ var devices = DeviceList.init(state.gpa);
+ try updateDevices(state.gpa, context, &devices);
- return self;
-}
-
-pub fn module(self: *Backlight) !Module {
- return Module{
- .impl = @ptrCast(*anyopaque, self),
- .funcs = .{
- .getEvent = getEvent,
- .print = print,
- .destroy = destroy,
- },
+ return Backlight{
+ .state = state,
+ .context = context,
+ .monitor = monitor,
+ .fd = try monitor.getFd(),
+ .devices = devices,
};
}
-fn getEvent(self_opaque: *anyopaque) !Event {
- const self = utils.cast(Backlight)(self_opaque);
-
- return Event{
- .fd = .{
- .fd = try self.monitor.getFd(),
- .events = os.POLL.IN,
- .revents = undefined,
- },
- .data = self_opaque,
- .callbackIn = callbackIn,
- .callbackOut = Event.noop,
- };
+pub fn deinit(self: *Backlight) void {
+ _ = self.context.unref();
+ for (self.devices.items) |*device| {
+ self.state.gpa.free(device.name);
+ }
+ self.devices.deinit();
}
-fn callbackIn(self_opaque: *anyopaque) Event.Action {
- const self = utils.cast(Backlight)(self_opaque);
-
- _ = self.monitor.receiveDevice() catch |err| {
- log.err("failed to receive udev device: {s}", .{@errorName(err)});
- return .terminate;
- };
+pub fn refresh(self: *Backlight) !void {
+ _ = try self.monitor.receiveDevice();
for (self.state.wayland.monitors.items) |monitor| {
if (monitor.bar) |bar| {
@@ -86,12 +65,9 @@ fn callbackIn(self_opaque: *anyopaque) Event.Action {
}
}
}
- return .ok;
}
-fn print(self_opaque: *anyopaque, writer: Module.StringWriter) !void {
- const self = utils.cast(Backlight)(self_opaque);
-
+pub fn print(self: *Backlight, writer: anytype) !void {
try updateDevices(self.state.gpa, self.context, &self.devices);
const device = self.devices.items[0];
var percent = @intToFloat(f64, device.value) * 100.0;
@@ -142,14 +118,3 @@ 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
@@ -15,7 +15,7 @@ const Battery = @This();
state: *State,
context: *udev.Udev,
-timerFd: os.fd_t,
+fd: os.fd_t,
devices: DeviceList,
const Device = struct {
@@ -26,11 +26,8 @@ const Device = struct {
const DeviceList = std.ArrayList(Device);
-pub fn create(state: *State) !*Battery {
- const self = try state.gpa.create(Battery);
- self.state = state;
-
- self.timerFd = tfd: {
+pub fn init(state: *State) !Battery {
+ const tfd = tfd: {
const fd = os.linux.timerfd_create(
os.CLOCK.MONOTONIC,
os.linux.TFD.CLOEXEC,
@@ -43,44 +40,29 @@ pub fn create(state: *State) !*Battery {
break :tfd @intCast(os.fd_t, fd);
};
- self.context = try udev.Udev.new();
-
- self.devices = DeviceList.init(state.gpa);
- try updateDevices(state.gpa, self.context, &self.devices);
- if (self.devices.items.len == 0) return error.NoDevicesFound;
+ const context = try udev.Udev.new();
- return self;
-}
+ var devices = DeviceList.init(state.gpa);
+ try updateDevices(state.gpa, context, &devices);
-pub fn module(self: *Battery) !Module {
- return Module{
- .impl = @ptrCast(*anyopaque, self),
- .funcs = .{
- .getEvent = getEvent,
- .print = print,
- .destroy = destroy,
- },
+ return Battery{
+ .state = state,
+ .context = context,
+ .fd = tfd,
+ .devices = devices,
};
}
-pub fn getEvent(self_opaque: *anyopaque) !Event {
- const self = utils.cast(Battery)(self_opaque);
-
- return Event{
- .fd = .{
- .fd = self.timerFd,
- .events = os.POLL.IN,
- .revents = undefined,
- },
- .data = self_opaque,
- .callbackIn = callbackIn,
- .callbackOut = Event.noop,
- };
+pub fn deinit(self: *Battery) void {
+ _ = self.context.unref();
+ for (self.devices.items) |*device| {
+ self.state.gpa.free(device.name);
+ self.state.gpa.free(device.status);
+ }
+ self.devices.deinit();
}
-pub fn print(self_opaque: *anyopaque, writer: Module.StringWriter) !void {
- const self = utils.cast(Battery)(self_opaque);
-
+pub fn print(self: *Battery, writer: anytype) !void {
try updateDevices(self.state.gpa, self.context, &self.devices);
const device = self.devices.items[0];
@@ -96,26 +78,9 @@ pub fn print(self_opaque: *anyopaque, writer: Module.StringWriter) !void {
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) Event.Action {
- const self = utils.cast(Battery)(self_opaque);
-
+pub fn refresh(self: *Battery) !void {
var expirations = mem.zeroes([8]u8);
- _ = os.read(self.timerFd, &expirations) catch |err| {
- log.err("failed to read timer: {s}", .{@errorName(err)});
- return .terminate;
- };
+ _ = try os.read(self.fd, &expirations);
for (self.state.wayland.monitors.items) |monitor| {
if (monitor.bar) |bar| {
@@ -128,7 +93,6 @@ fn callbackIn(self_opaque: *anyopaque) Event.Action {
}
}
}
- return .ok;
}
fn updateDevices(
diff --git a/src/modules/Pulse.zig b/src/modules/Pulse.zig
@@ -13,69 +13,66 @@ const utils = @import("../utils.zig");
const Pulse = @This();
state: *State,
+fd: os.fd_t,
mainloop: *pulse.pa_threaded_mainloop,
api: *pulse.pa_mainloop_api,
context: *pulse.pa_context,
-fd: os.fd_t,
+// owned by pulse api
sink_name: []const u8,
sink_is_running: bool,
volume: u8,
muted: bool,
-pub fn create(state: *State) !*Pulse {
- const self = try state.gpa.create(Pulse);
- self.state = state;
- self.volume = 0;
- self.muted = false;
- try self.initPulse();
-
+pub fn init(state: *State) !Pulse {
// create descriptor for poll in Loop
- const fd = try os.eventfd(0, os.linux.EFD.NONBLOCK);
- self.fd = @intCast(os.fd_t, fd);
-
- return self;
-}
-
-pub fn module(self: *Pulse) !Module {
- return Module{
- .impl = @ptrCast(*anyopaque, self),
- .funcs = .{
- .getEvent = getEvent,
- .print = print,
- .destroy = destroy,
- },
+ const efd = efd: {
+ const fd = try os.eventfd(0, os.linux.EFD.NONBLOCK);
+ break :efd @intCast(os.fd_t, fd);
};
-}
-fn getEvent(self_opaque: *anyopaque) !Event {
- const self = utils.cast(Pulse)(self_opaque);
+ // setup pulseaudio api
+ const mainloop = pulse.pa_threaded_mainloop_new() orelse {
+ return error.InitFailed;
+ };
+ const api = pulse.pa_threaded_mainloop_get_api(mainloop);
+ const context = pulse.pa_context_new(api, "levee") orelse {
+ return error.InitFailed;
+ };
+ const connected = pulse.pa_context_connect(context, null, pulse.PA_CONTEXT_NOFAIL, null);
+ if (connected < 0) return error.InitFailed;
- return Event{
- .fd = .{ .fd = self.fd, .events = os.POLL.IN, .revents = undefined },
- .data = self_opaque,
- .callbackIn = callbackIn,
- .callbackOut = Event.noop,
+ return Pulse{
+ .state = state,
+ .fd = efd,
+ .mainloop = mainloop,
+ .api = api,
+ .context = context,
+ .sink_name = "",
+ .sink_is_running = false,
+ .volume = 0,
+ .muted = false,
};
}
-fn print(self_opaque: *anyopaque, writer: Module.StringWriter) !void {
- const self = utils.cast(Pulse)(self_opaque);
-
- if (self.muted) {
- try writer.print(" 🔇 ", .{});
- } else {
- try writer.print("🔊 {d}%", .{self.volume});
- }
+pub fn deinit(self: *Pulse) void {
+ if (self.api.quit) |quit| quit(self.api, 0);
+ pulse.pa_threaded_mainloop_stop(self.mainloop);
+ pulse.pa_threaded_mainloop_free(self.mainloop);
}
-fn callbackIn(self_opaque: *anyopaque) Event.Action {
- const self = utils.cast(Pulse)(self_opaque);
+pub fn start(self: *Pulse) !void {
+ pulse.pa_context_set_state_callback(
+ self.context,
+ contextStateCallback,
+ @ptrCast(*anyopaque, self),
+ );
+ const started = pulse.pa_threaded_mainloop_start(self.mainloop);
+ if (started < 0) return error.StartFailed;
+}
+pub fn refresh(self: *Pulse) !void {
var data = mem.zeroes([8]u8);
- _ = os.read(self.fd, &data) catch |err| {
- log.err("pulse: failed to read: {s}", .{@errorName(err)});
- return .terminate;
- };
+ _ = try os.read(self.fd, &data);
for (self.state.wayland.monitors.items) |monitor| {
if (monitor.bar) |bar| {
@@ -88,44 +85,14 @@ fn callbackIn(self_opaque: *anyopaque) Event.Action {
}
}
}
- return .ok;
-}
-
-fn destroy(self_opaque: *anyopaque) void {
- const self = utils.cast(Pulse)(self_opaque);
-
- self.deinitPulse();
- self.state.gpa.destroy(self);
-}
-
-fn initPulse(self: *Pulse) !void {
- self.mainloop = pulse.pa_threaded_mainloop_new() orelse {
- return error.InitFailed;
- };
- self.api = pulse.pa_threaded_mainloop_get_api(self.mainloop);
- self.context = pulse.pa_context_new(self.api, "levee") orelse {
- return error.InitFailed;
- };
- const connected = pulse.pa_context_connect(
- self.context,
- null,
- pulse.PA_CONTEXT_NOFAIL,
- null,
- );
- if (connected < 0) return error.InitFailed;
- pulse.pa_context_set_state_callback(
- self.context,
- contextStateCallback,
- @ptrCast(*anyopaque, self),
- );
- const started = pulse.pa_threaded_mainloop_start(self.mainloop);
- if (started < 0) return error.InitFailed;
}
-fn deinitPulse(self: *Pulse) void {
- if (self.api.quit) |quit| quit(self.api, 0);
- pulse.pa_threaded_mainloop_stop(self.mainloop);
- pulse.pa_threaded_mainloop_free(self.mainloop);
+pub fn print(self: *Pulse, writer: anytype) !void {
+ if (self.muted) {
+ try writer.print(" 🔇 ", .{});
+ } else {
+ try writer.print("🔊 {d}%", .{self.volume});
+ }
}
export fn contextStateCallback(
@@ -156,8 +123,8 @@ export fn contextStateCallback(
},
pulse.PA_CONTEXT_TERMINATED, pulse.PA_CONTEXT_FAILED => {
log.info("pulse: restarting", .{});
- self.deinitPulse();
- self.initPulse() catch return;
+ self.deinit();
+ self.* = Pulse.init(self.state) catch return;
log.info("pulse: restarted", .{});
},
else => {},
diff --git a/src/render.zig b/src/render.zig
@@ -11,6 +11,10 @@ const Bar = @import("Bar.zig");
const Tag = @import("Tags.zig").Tag;
const utils = @import("utils.zig");
+const Backlight = @import("modules/Backlight.zig");
+const Battery = @import("modules/Battery.zig");
+const Pulse = @import("modules/Pulse.zig");
+
pub const RenderFn = fn (*Bar) anyerror!void;
pub fn renderTags(bar: *Bar) !void {
@@ -102,9 +106,13 @@ pub fn renderModules(bar: *Bar) !void {
defer string.deinit();
const writer = string.writer();
- for (state.modules.modules.items) |*module| {
- try std.fmt.format(writer, " | ", .{});
- try module.print(writer);
+ for (state.modules.order.items) |tag| {
+ try writer.print(" | ", .{});
+ switch (tag) {
+ .backlight => try state.modules.backlight.?.print(writer),
+ .battery => try state.modules.battery.?.print(writer),
+ .pulse => try state.modules.pulse.?.print(writer),
+ }
}
// ut8 encoding
diff --git a/src/utils.zig b/src/utils.zig
@@ -5,11 +5,6 @@ const meta = std.meta;
const os = std.os;
const unicode = std.unicode;
-pub fn fatal(comptime format: []const u8, args: anytype) noreturn {
- log.err(format, args);
- os.exit(1);
-}
-
pub fn cast(comptime to: type) fn (*anyopaque) *to {
return (struct {
pub fn cast(module: *anyopaque) *to {