diff --git a/src/Bar.zig b/src/Bar.zig index 87cbcbb..7f0e63b 100644 --- a/src/Bar.zig +++ b/src/Bar.zig @@ -114,7 +114,6 @@ pub fn layerSurfaceListener( bar.configured = true; - log.debug("bwbuhse before render", .{}); bar.render() catch |err| { log.err("Bar render failed: {}", .{err}); }; @@ -125,7 +124,9 @@ pub fn layerSurfaceListener( } } -fn render(bar: *Bar) !void { +// TODO: Configure number of visible tags +/// Renders the bar and its components +pub fn render(bar: *Bar) !void { const buffer = try bar.context.buffer_pool.nextBuffer(bar.context.wl_shm, bar.width, bar.height); // Fill with a solid color (e.g., dark background) @@ -138,7 +139,6 @@ fn render(bar: *Bar) !void { wl_surface.attach(buffer.wl_buffer, 0, 0); wl_surface.damageBuffer(0, 0, bar.width, bar.height); wl_surface.commit(); - log.debug("bwbuhse end of render", .{}); } // Borrowed and modified from https://git.sr.ht/~novakane/zig-fcft-example diff --git a/src/LibinputDevice.zig b/src/LibinputDevice.zig index cb4ca97..31d511c 100644 --- a/src/LibinputDevice.zig +++ b/src/LibinputDevice.zig @@ -107,7 +107,6 @@ pub fn destroy(libinput_device: *LibinputDevice) void { fn riverLibinputDeviceV1Listener(river_libinput_device_v1: *river.LibinputDeviceV1, event: river.LibinputDeviceV1.Event, libinput_device: *LibinputDevice) void { assert(libinput_device.river_libinput_device_v1 == river_libinput_device_v1); const im = libinput_device.context.im; - log.debug("bwbuhse: {s} for {d}", .{ @tagName(event), river_libinput_device_v1.getId() }); switch (event) { .removed => { river_libinput_device_v1.destroy(); diff --git a/src/main.zig b/src/main.zig index 6474085..e1d54cd 100644 --- a/src/main.zig +++ b/src/main.zig @@ -36,48 +36,8 @@ const usage: []const u8 = \\ ; -// TODO: I'd like to clean this function up a bit and move some bits into helpers pub fn main() !void { - const result = flags.parser([*:0]const u8, &.{ - .{ .name = "h", .kind = .boolean }, - .{ .name = "version", .kind = .boolean }, - .{ .name = "log-level", .kind = .arg }, - }).parse(std.os.argv[1..]) catch { - try stderr.writeAll(usage); - try stderr.flush(); - posix.exit(1); - }; - if (result.flags.h) { - try stdout.writeAll(usage); - try stdout.flush(); - posix.exit(0); - } - if (result.args.len != 0) { - log.err("unknown option '{s}'", .{result.args[0]}); - try stderr.writeAll(usage); - try stderr.flush(); - posix.exit(1); - } - - if (result.flags.version) { - try stdout.writeAll(build_options.version ++ "\n"); - try stdout.flush(); - posix.exit(0); - } - if (result.flags.@"log-level") |level| { - if (mem.eql(u8, level, "error")) { - runtime_log_level = .err; - } else if (mem.eql(u8, level, "warning")) { - runtime_log_level = .warn; - } else if (mem.eql(u8, level, "info")) { - runtime_log_level = .info; - } else if (mem.eql(u8, level, "debug")) { - runtime_log_level = .debug; - } else { - log.err("invalid log level '{s}'", .{level}); - posix.exit(1); - } - } + parseArgs(); // Initialize fcft const fcft_log_level: fcft.LogClass = switch (runtime_log_level) { @@ -141,13 +101,130 @@ pub fn main() !void { }); defer context.destroy(); + try run(wl_display, context); +} + +/// Function to handle the main event loop +/// +/// Since we've added a bar with a clock,we need +fn run(wl_display: *wl.Display, context: *Context) !void { + var mask = posix.sigemptyset(); + + posix.sigaddset(&mask, posix.SIG.INT); + posix.sigaddset(&mask, posix.SIG.QUIT); + + posix.sigprocmask(posix.SIG.BLOCK, &mask, null); + + const sig_fd = try posix.signalfd(-1, &mask, 0); + + const poll_wayland = 0; + const poll_sig = 1; + + var pollfds: [2]posix.pollfd = undefined; + + pollfds[poll_wayland] = .{ + .fd = wl_display.getFd(), + .events = posix.POLL.IN, + .revents = 0, + }; + pollfds[poll_sig] = .{ + .fd = sig_fd, + .events = posix.POLL.IN, + .revents = 0, + }; + while (true) { - if (wl_display.dispatch() != .SUCCESS) { - fatal("wayland display dispatch failed", .{}); + const errno = wl_display.flush(); + if (errno != .SUCCESS) { + fatal("wl_display flush failed: E{s}", .{@tagName(errno)}); + } + + // Get the number of milliseconds to the top of the next minute + const time = std.time.timestamp(); + if (time < 0) { + log.err("Got a negative time ({d})", .{time}); + return error.InvalidTime; + } + const timeout: i32 = @intCast((@divTrunc(time, 60) * 60 + 60 - time) * 1000); + + const poll_rc = posix.poll(&pollfds, timeout) catch |err| { + fatal("Failed to poll {s}", .{@errorName(err)}); + }; + if (poll_rc == 0) { + // If poll returns 0, it timed out, meaning we hit the top of the minute + // and need to update the clock. + var it = context.wm.outputs.iterator(.forward); + while (it.next()) |output| { + if (output.bar) |*bar| { + bar.render() catch |err| { + log.err("Bar timer render failed: {}", .{err}); + }; + } + } + } + + // Handle fds that became ready + if (pollfds[poll_wayland].revents & posix.POLL.HUP != 0) { + log.info("Disconnected by compositor", .{}); + break; + } + if (pollfds[poll_wayland].revents & posix.POLL.IN != 0) { + if (wl_display.dispatch() != .SUCCESS) { + fatal("Wayland display dispatch failed", .{}); + } + } + + if (pollfds[poll_sig].revents & posix.POLL.HUP != 0) { + fatal("Signal fd hung up", .{}); + } + if (pollfds[poll_sig].revents & posix.POLL.IN != 0) { + log.info("Exiting beansprout", .{}); + break; } } +} - log.info("Exiting beansprout", .{}); +fn parseArgs() void { + const result = flags.parser([*:0]const u8, &.{ + .{ .name = "h", .kind = .boolean }, + .{ .name = "version", .kind = .boolean }, + .{ .name = "log-level", .kind = .arg }, + }).parse(os.argv[1..]) catch { + stderr.writeAll(usage) catch {}; + stderr.flush() catch {}; + posix.exit(1); + }; + if (result.flags.h) { + stdout.writeAll(usage) catch {}; + stdout.flush() catch {}; + posix.exit(0); + } + if (result.args.len != 0) { + log.err("unknown option '{s}'", .{result.args[0]}); + stderr.writeAll(usage) catch {}; + stderr.flush() catch {}; + posix.exit(1); + } + + if (result.flags.version) { + stdout.writeAll(build_options.version ++ "\n") catch {}; + stdout.flush() catch {}; + posix.exit(0); + } + if (result.flags.@"log-level") |level| { + if (mem.eql(u8, level, "error")) { + runtime_log_level = .err; + } else if (mem.eql(u8, level, "warning")) { + runtime_log_level = .warn; + } else if (mem.eql(u8, level, "info")) { + runtime_log_level = .info; + } else if (mem.eql(u8, level, "debug")) { + runtime_log_level = .debug; + } else { + log.err("invalid log level '{s}'", .{level}); + posix.exit(1); + } + } } fn registryListener(registry: *wl.Registry, event: wl.Registry.Event, globals: *Globals) void { @@ -250,6 +327,7 @@ const std = @import("std"); const fatal = std.process.fatal; const fs = std.fs; const mem = std.mem; +const os = std.os; const posix = std.posix; const process = std.process;