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;
  3
  4const wl = @import("wayland").client.wl;
  5
  6const Bar = @import("Bar.zig");
  7const Input = @This();
  8
  9const state = &@import("root").state;
 10
 11globalName: u32,
 12
 13pointer: struct {
 14    pointer: ?*wl.Pointer,
 15    x: i32,
 16    y: i32,
 17    bar: ?*Bar,
 18    surface: ?*wl.Surface,
 19},
 20
 21pub fn create(name: u32) !*Input {
 22    const self = try state.gpa.create(Input);
 23    const seat = state.wayland.seat.?;
 24
 25    self.globalName = name;
 26    self.pointer.pointer = null;
 27    self.pointer.bar = null;
 28    self.pointer.surface = null;
 29
 30    seat.setListener(*Input, listener, self);
 31    return self;
 32}
 33
 34pub fn destroy(self: *Input) void {
 35    if (self.pointer.pointer) |pointer| {
 36        pointer.release();
 37    }
 38    state.gpa.destroy(self);
 39}
 40
 41fn listener(seat: *wl.Seat, event: wl.Seat.Event, input: *Input) void {
 42    switch (event) {
 43        .capabilities => |data| {
 44            if (input.pointer.pointer) |pointer| {
 45                pointer.release();
 46                input.pointer.pointer = null;
 47            }
 48            if (data.capabilities.pointer) {
 49                input.pointer.pointer = seat.getPointer() catch |err| {
 50                    log.err("cannot obtain seat pointer: {s}", .{@errorName(err)});
 51                    return;
 52                };
 53                input.pointer.pointer.?.setListener(
 54                    *Input,
 55                    pointerListener,
 56                    input,
 57                );
 58            }
 59        },
 60        .name => {},
 61    }
 62}
 63
 64fn pointerListener(
 65    _: *wl.Pointer,
 66    event: wl.Pointer.Event,
 67    input: *Input,
 68) void {
 69    switch (event) {
 70        .enter => |data| {
 71            input.pointer.x = data.surface_x.toInt();
 72            input.pointer.y = data.surface_y.toInt();
 73            const bar = state.wayland.findBar(data.surface);
 74            input.pointer.bar = bar;
 75            input.pointer.surface = data.surface;
 76        },
 77        .leave => |_| {
 78            input.pointer.bar = null;
 79            input.pointer.surface = null;
 80        },
 81        .motion => |data| {
 82            input.pointer.x = data.surface_x.toInt();
 83            input.pointer.y = data.surface_y.toInt();
 84        },
 85        .button => |data| {
 86            if (data.state != .pressed) return;
 87            if (input.pointer.bar) |bar| {
 88                if (!bar.configured) return;
 89
 90                const tagsSurface = bar.tags.surface;
 91                if (input.pointer.surface != tagsSurface) return;
 92
 93                const x: u32 = @intCast(input.pointer.x);
 94                if (x < bar.height * @as(u16, bar.monitor.tags.tags.len)) {
 95                    bar.monitor.tags.handleClick(x) catch |err| {
 96                        log.err("handleClick failed for monitor {}: {s}",
 97                                .{bar.monitor.globalName, @errorName(err)});
 98                        return;
 99                    };
100                }
101            }
102        },
103        else => {},
104    }
105}