creek

A malleable and minimalist status bar for the River compositor

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

 1const std = @import("std");
 2const mem = std.mem;
 3const posix = std.posix;
 4const linux = std.os.linux;
 5
 6const pixman = @import("pixman");
 7const wl = @import("wayland").client.wl;
 8
 9const Buffer = @This();
10
11mmap: ?[]align(4096) u8 = null,
12data: ?[]u32 = null,
13buffer: ?*wl.Buffer = null,
14pix: ?*pixman.Image = null,
15
16busy: bool = false,
17width: u31 = 0,
18height: u31 = 0,
19size: u31 = 0,
20
21pub fn resize(self: *Buffer, shm: *wl.Shm, width: u31, height: u31) !void {
22    if (width == 0 or height == 0) return;
23
24    self.busy = true;
25    self.width = width;
26    self.height = height;
27
28    const fd = try posix.memfd_create("creek-shm", linux.MFD.CLOEXEC);
29    defer posix.close(fd);
30
31    const stride = width * 4;
32    self.size = stride * height;
33    try posix.ftruncate(fd, self.size);
34
35    self.mmap = try posix.mmap(null, self.size, posix.PROT.READ | posix.PROT.WRITE, .{ .TYPE = .SHARED }, fd, 0);
36    self.data = mem.bytesAsSlice(u32, self.mmap.?);
37
38    const pool = try shm.createPool(fd, self.size);
39    defer pool.destroy();
40
41    self.buffer = try pool.createBuffer(0, width, height, stride, .argb8888);
42    errdefer self.buffer.?.destroy();
43    self.buffer.?.setListener(*Buffer, listener, self);
44
45    self.pix = pixman.Image.createBitsNoClear(.a8r8g8b8, width, height, self.data.?.ptr, stride);
46}
47
48pub fn deinit(self: *Buffer) void {
49    if (self.pix) |pix| _ = pix.unref();
50    if (self.buffer) |buf| buf.destroy();
51    if (self.mmap) |mmap| posix.munmap(mmap);
52}
53
54fn listener(_: *wl.Buffer, event: wl.Buffer.Event, buffer: *Buffer) void {
55    switch (event) {
56        .release => buffer.busy = false,
57    }
58}
59
60pub fn nextBuffer(pool: *[2]Buffer, shm: *wl.Shm, width: u16, height: u16) !*Buffer {
61    if (pool[0].busy and pool[1].busy) {
62        return error.NoAvailableBuffers;
63    }
64    const buffer = if (!pool[0].busy) &pool[0] else &pool[1];
65
66    if (buffer.width != width or buffer.height != height) {
67        buffer.deinit();
68        try buffer.resize(shm, width, height);
69    }
70    return buffer;
71}