creek

A malleable and minimalist status bar for the River compositor

git clone https://git.8pit.net/creek.git

  1const std = @import("std");
  2const log = std.log;
  3const mem = std.mem;
  4const posix = std.posix;
  5const linux = std.os.linux;
  6const io = std.io;
  7
  8const render = @import("render.zig");
  9const Loop = @This();
 10
 11const state = &@import("root").state;
 12
 13sfd: posix.fd_t,
 14
 15pub fn init() !Loop {
 16    var mask = posix.empty_sigset;
 17    linux.sigaddset(&mask, linux.SIG.INT);
 18    linux.sigaddset(&mask, linux.SIG.TERM);
 19    linux.sigaddset(&mask, linux.SIG.QUIT);
 20
 21    _ = linux.sigprocmask(linux.SIG.BLOCK, &mask, null);
 22    const sfd = linux.signalfd(-1, &mask, linux.SFD.NONBLOCK);
 23
 24    return Loop{ .sfd = @intCast(sfd) };
 25}
 26
 27pub fn run(self: *Loop) !void {
 28    const wayland = &state.wayland;
 29
 30    var fds = [_]posix.pollfd{
 31        .{
 32            .fd = self.sfd,
 33            .events = posix.POLL.IN,
 34            .revents = undefined,
 35        },
 36        .{
 37            .fd = wayland.fd,
 38            .events = posix.POLL.IN,
 39            .revents = undefined,
 40        },
 41        .{
 42            .fd = posix.STDIN_FILENO,
 43            .events = posix.POLL.IN,
 44            .revents = undefined,
 45        },
 46    };
 47
 48    var reader = io.getStdIn().reader();
 49    while (true) {
 50        while (true) {
 51            const ret = wayland.display.dispatchPending();
 52            _ = wayland.display.flush();
 53            if (ret == .SUCCESS) break;
 54        }
 55
 56        _ = posix.poll(&fds, -1) catch |err| {
 57            log.err("poll failed: {s}", .{@errorName(err)});
 58            return;
 59        };
 60
 61        for (fds) |fd| {
 62            if (fd.revents & posix.POLL.HUP != 0 or fd.revents & posix.POLL.ERR != 0) {
 63                return;
 64            }
 65        }
 66
 67        // signals
 68        if (fds[0].revents & posix.POLL.IN != 0) {
 69            return;
 70        }
 71
 72        // wayland
 73        if (fds[1].revents & posix.POLL.IN != 0) {
 74            const errno = wayland.display.dispatch();
 75            if (errno != .SUCCESS) return;
 76        }
 77        if (fds[1].revents & posix.POLL.OUT != 0) {
 78            const errno = wayland.display.flush();
 79            if (errno != .SUCCESS) return;
 80        }
 81
 82        // status input
 83        if (fds[2].revents & posix.POLL.IN != 0) {
 84            if (state.wayland.river_seat) |seat| {
 85                if (seat.focusedBar()) |bar| {
 86                    seat.status_text.reset();
 87                    try reader.streamUntilDelimiter(seat.status_text.writer(), '\n', null);
 88
 89                    render.renderText(bar, seat.status_text.getWritten()) catch |err| {
 90                        log.err("renderText failed for monitor {}: {s}",
 91                            .{bar.monitor.globalName, @errorName(err)});
 92                        continue;
 93                    };
 94
 95                    bar.text.surface.commit();
 96                    bar.background.surface.commit();
 97                }
 98            }
 99        }
100    }
101}