creek

A malleable and minimalist status bar for the River compositor

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

 1const std = @import("std");
 2const Io = std.Io;
 3const mem = std.mem;
 4const posix = std.posix;
 5const linux = std.os.linux;
 6
 7const pixman = @import("pixman");
 8const wl = @import("wayland").client.wl;
 9
10const Buffer = @This();
11
12const state = &@import("root").state;
13
14mmap: ?Io.File.MemoryMap = null,
15data: ?[]u32 = null,
16buffer: ?*wl.Buffer = null,
17pix: ?*pixman.Image = null,
18
19busy: bool = false,
20width: u31 = 0,
21height: u31 = 0,
22size: u31 = 0,
23
24pub fn resize(self: *Buffer, shm: *wl.Shm, width: u31, height: u31) !void {
25    if (width == 0 or height == 0) return;
26
27    self.busy = true;
28    self.width = width;
29    self.height = height;
30
31    // There doesn't seem to be a way to memfd through a File abstraction, as of Zig 0.16
32    const fd = try posix.memfd_create("creek-shm", linux.MFD.CLOEXEC);
33    const file = Io.File{ .handle = fd, .flags = .{ .nonblocking = false } };
34    defer file.close(state.io);
35
36    const stride = width * 4;
37    self.size = stride * height;
38    try file.setLength(state.io, self.size);
39
40    self.mmap = try file.createMemoryMap(state.io, .{ .len = self.size });
41    self.data = mem.bytesAsSlice(u32, self.mmap.?.memory);
42
43    const pool = try shm.createPool(fd, self.size);
44    defer pool.destroy();
45
46    self.buffer = try pool.createBuffer(0, width, height, stride, .argb8888);
47    errdefer self.buffer.?.destroy();
48    self.buffer.?.setListener(*Buffer, listener, self);
49
50    self.pix = pixman.Image.createBitsNoClear(.a8r8g8b8, width, height, self.data.?.ptr, stride);
51}
52
53pub fn deinit(self: *Buffer) void {
54    if (self.pix) |pix| _ = pix.unref();
55    if (self.buffer) |buf| buf.destroy();
56    if (self.mmap) |*mmap| mmap.destroy(state.io);
57}
58
59fn listener(_: *wl.Buffer, event: wl.Buffer.Event, buffer: *Buffer) void {
60    switch (event) {
61        .release => buffer.busy = false,
62    }
63}
64
65pub fn nextBuffer(pool: *[2]Buffer, shm: *wl.Shm, width: u16, height: u16) !*Buffer {
66    if (pool[0].busy and pool[1].busy) {
67        return error.NoAvailableBuffers;
68    }
69    const buffer = if (!pool[0].busy) &pool[0] else &pool[1];
70
71    if (buffer.width != width or buffer.height != height) {
72        buffer.deinit();
73        try buffer.resize(shm, width, height);
74    }
75    return buffer;
76}