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