stevee

My wayland statusbar
git clone git://gtms.dev/stevee
Log | Files | Refs | Submodules | README | LICENSE

commit 6bdc9ba0da891c11d9c73d551b6fb3784a558bd7
parent d751f48a9c677a9cba7f22bdad469d527d11df56
Author: Andrea Feletto <andrea@andreafeletto.com>
Date:   Thu, 28 Apr 2022 22:11:30 +0200

split wayland.zig

Diffstat:
Msrc/Bar.zig | 2+-
Asrc/Input.zig | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Monitor.zig | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/Tags.zig | 4++--
Asrc/Wayland.zig | 186+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/main.zig | 2+-
Dsrc/wayland.zig | 332-------------------------------------------------------------------------------
7 files changed, 341 insertions(+), 336 deletions(-)

diff --git a/src/Bar.zig b/src/Bar.zig @@ -5,7 +5,7 @@ const wl = @import("wayland").client.wl; const zwlr = @import("wayland").client.zwlr; const Buffer = @import("Buffer.zig"); -const Monitor = @import("wayland.zig").Monitor; +const Monitor = @import("Monitor.zig"); const render = @import("render.zig"); const State = @import("main.zig").State; const Bar = @This(); diff --git a/src/Input.zig b/src/Input.zig @@ -0,0 +1,98 @@ +const wl = @import("wayland").client.wl; + +const State = @import("main.zig").State; +const Bar = @import("Bar.zig"); +const Input = @This(); + +state: *State, +seat: *wl.Seat, +globalName: u32, + +pointer: struct { + pointer: ?*wl.Pointer, + x: i32, + y: i32, + bar: ?*Bar, + surface: ?*wl.Surface, +}, + +pub fn create(state: *State, registry: *wl.Registry, name: u32) !*Input { + const self = try state.gpa.create(Input); + self.state = state; + self.seat = try registry.bind(name, wl.Seat, 3); + self.globalName = name; + + self.pointer.pointer = null; + self.pointer.bar = null; + self.pointer.surface = null; + + self.seat.setListener(*Input, listener, self); + return self; +} + +pub fn destroy(self: *Input) void { + if (self.pointer.pointer) |pointer| { + pointer.release(); + } + self.seat.release(); + self.state.gpa.destroy(self); +} + +fn listener(seat: *wl.Seat, event: wl.Seat.Event, input: *Input) void { + switch (event) { + .capabilities => |data| { + if (input.pointer.pointer) |pointer| { + pointer.release(); + input.pointer.pointer = null; + } + if (data.capabilities.pointer) { + input.pointer.pointer = seat.getPointer() catch return; + input.pointer.pointer.?.setListener( + *Input, + pointerListener, + input, + ); + } + }, + .name => {}, + } +} + +fn pointerListener( + _: *wl.Pointer, + event: wl.Pointer.Event, + input: *Input, +) void { + switch (event) { + .enter => |data| { + input.pointer.x = data.surface_x.toInt(); + input.pointer.y = data.surface_y.toInt(); + const bar = input.state.wayland.findBar(data.surface); + input.pointer.bar = bar; + input.pointer.surface = data.surface; + }, + .leave => |_| { + input.pointer.bar = null; + input.pointer.surface = null; + }, + .motion => |data| { + input.pointer.x = data.surface_x.toInt(); + input.pointer.y = data.surface_y.toInt(); + }, + .button => |data| { + if (data.state != .pressed) return; + if (input.pointer.bar) |bar| { + if (!bar.configured) return; + + const tagsSurface = bar.tags.surface; + if (input.pointer.surface != tagsSurface) return; + + const x = @intCast(u32, input.pointer.x); + if (x < bar.height * 9) { + bar.monitor.tags.handleClick(x, input) catch return; + } + } + }, + else => {}, + } +} diff --git a/src/Monitor.zig b/src/Monitor.zig @@ -0,0 +1,53 @@ +const wl = @import("wayland").client.wl; + +const State = @import("main.zig").State; +const Bar = @import("Bar.zig"); +const Tags = @import("Tags.zig"); +const Monitor = @This(); + +state: *State, +output: *wl.Output, +globalName: u32, +scale: i32, + +bar: ?*Bar, +tags: *Tags, + +pub fn create(state: *State, registry: *wl.Registry, name: u32) !*Monitor { + const self = try state.gpa.create(Monitor); + self.state = state; + self.output = try registry.bind(name, wl.Output, 3); + self.globalName = name; + self.scale = 1; + + self.bar = null; + self.tags = try Tags.create(state, self); + + self.output.setListener(*Monitor, listener, self); + return self; +} + +pub fn destroy(self: *Monitor) void { + if (self.bar) |bar| { + bar.destroy(); + } + self.tags.destroy(); + self.state.gpa.destroy(self); +} + +fn listener(_: *wl.Output, event: wl.Output.Event, monitor: *Monitor) void { + switch (event) { + .scale => |scale| { + monitor.scale = scale.factor; + }, + .geometry => {}, + .mode => {}, + .name => {}, + .description => {}, + .done => { + if (monitor.bar) |_| {} else { + monitor.bar = Bar.create(monitor) catch return; + } + }, + } +} diff --git a/src/Tags.zig b/src/Tags.zig @@ -2,9 +2,9 @@ const std = @import("std"); const zriver = @import("wayland").client.zriver; -const Monitor = @import("wayland.zig").Monitor; +const Monitor = @import("Monitor.zig"); const render = @import("render.zig"); -const Input = @import("wayland.zig").Input; +const Input = @import("Input.zig"); const State = @import("main.zig").State; const Tags = @This(); diff --git a/src/Wayland.zig b/src/Wayland.zig @@ -0,0 +1,186 @@ +const std = @import("std"); +const mem = std.mem; +const meta = std.meta; +const os = std.os; +const strcmp = std.cstr.cmp; +const ArrayList = std.ArrayList; + +const wl = @import("wayland").client.wl; +const zwlr = @import("wayland").client.zwlr; +const zriver = @import("wayland").client.zriver; + +const Bar = @import("Bar.zig"); +const Event = @import("Loop.zig").Event; +const Input = @import("Input.zig"); +const Monitor = @import("Monitor.zig"); +const State = @import("main.zig").State; +const utils = @import("utils.zig"); +const Wayland = @This(); + +state: *State, +display: *wl.Display, +registry: *wl.Registry, + +monitors: ArrayList(*Monitor), +inputs: ArrayList(*Input), +globals: Globals, +globalsMask: GlobalsMask, + +const Globals = struct { + compositor: *wl.Compositor, + subcompositor: *wl.Subcompositor, + shm: *wl.Shm, + layerShell: *zwlr.LayerShellV1, + statusManager: *zriver.StatusManagerV1, + control: *zriver.ControlV1, +}; +const GlobalsMask = utils.Mask(Globals); + +pub fn init(state: *State) !Wayland { + const display = try wl.Display.connect(null); + + return Wayland{ + .state = state, + .display = display, + .registry = try display.getRegistry(), + .monitors = ArrayList(*Monitor).init(state.gpa), + .inputs = ArrayList(*Input).init(state.gpa), + .globals = undefined, + .globalsMask = mem.zeroes(GlobalsMask), + }; +} + +pub fn deinit(self: *Wayland) void { + for (self.monitors.items) |monitor| monitor.destroy(); + for (self.inputs.items) |input| input.destroy(); + + self.monitors.deinit(); + self.inputs.deinit(); +} + +pub fn registerGlobals(self: *Wayland) !void { + self.registry.setListener(*State, registryListener, self.state); + _ = try self.display.roundtrip(); + + for (self.globalsMask) |is_registered| { + if (!is_registered) return error.UnsupportedGlobal; + } +} + +pub fn getEvent(self: *Wayland) !Event { + const fd = self.display.getFd(); + + return Event{ + .fd = .{ + .fd = @intCast(os.fd_t, fd), + .events = os.POLL.IN, + .revents = undefined, + }, + .data = @ptrCast(*anyopaque, self), + .callbackIn = dispatch, + .callbackOut = flush, + }; +} + +fn dispatch(self_opaque: *anyopaque) error{Terminate}!void { + const self = utils.cast(Wayland)(self_opaque); + _ = self.display.dispatch() catch return; +} + +fn flush(self_opaque: *anyopaque) error{Terminate}!void { + const self = utils.cast(Wayland)(self_opaque); + _ = self.display.flush() catch return; +} + +fn registryListener( + registry: *wl.Registry, + event: wl.Registry.Event, + state: *State, +) void { + const self = &state.wayland; + + switch (event) { + .global => |g| { + self.bindGlobal(registry, g.interface, g.name) catch return; + }, + .global_remove => |data| { + for (self.monitors.items) |monitor, i| { + if (monitor.globalName == data.name) { + monitor.destroy(); + _ = self.monitors.swapRemove(i); + break; + } + } + for (self.inputs.items) |input, i| { + if (input.globalName == data.name) { + input.destroy(); + _ = self.inputs.swapRemove(i); + break; + } + } + }, + } +} + +fn bindGlobal( + self: *Wayland, + registry: *wl.Registry, + iface: [*:0]const u8, + name: u32, +) !void { + if (strcmp(iface, wl.Compositor.getInterface().name) == 0) { + const global = try registry.bind(name, wl.Compositor, 4); + self.setGlobal(global); + } else if (strcmp(iface, wl.Subcompositor.getInterface().name) == 0) { + const global = try registry.bind(name, wl.Subcompositor, 1); + self.setGlobal(global); + } else if (strcmp(iface, wl.Shm.getInterface().name) == 0) { + const global = try registry.bind(name, wl.Shm, 1); + self.setGlobal(global); + } else if (strcmp(iface, zwlr.LayerShellV1.getInterface().name) == 0) { + const global = try registry.bind(name, zwlr.LayerShellV1, 1); + self.setGlobal(global); + } else if ( + strcmp(iface, zriver.StatusManagerV1.getInterface().name) == 0 + ) { + const global = try registry.bind(name, zriver.StatusManagerV1, 1); + self.setGlobal(global); + } else if (strcmp(iface, zriver.ControlV1.getInterface().name) == 0) { + const global = try registry.bind(name, zriver.ControlV1, 1); + self.setGlobal(global); + } else if (strcmp(iface, wl.Output.getInterface().name) == 0) { + const monitor = try Monitor.create(self.state, registry, name); + try self.monitors.append(monitor); + } else if (strcmp(iface, wl.Seat.getInterface().name) == 0) { + const input = try Input.create(self.state, registry, name); + try self.inputs.append(input); + } +} + +pub fn setGlobal(self: *Wayland, global: anytype) void { + inline for (meta.fields(Globals)) |field, i| { + if (field.field_type == @TypeOf(global)) { + @field(self.globals, field.name) = global; + self.globalsMask[i] = true; + break; + } + } +} + +pub fn findBar(self: *Wayland, wlSurface: ?*wl.Surface) ?*Bar { + if (wlSurface == null) { + return null; + } + for (self.monitors.items) |monitor| { + if (monitor.bar) |bar| { + if (bar.background.surface == wlSurface or + bar.tags.surface == wlSurface or + bar.clock.surface == wlSurface or + bar.modules.surface == wlSurface) + { + return bar; + } + } + } + return null; +} diff --git a/src/main.zig b/src/main.zig @@ -10,7 +10,7 @@ const fcft = @import("fcft"); const Config = @import("Config.zig"); const Loop = @import("Loop.zig"); const Modules = @import("Modules.zig"); -const Wayland = @import("wayland.zig").Wayland; +const Wayland = @import("Wayland.zig"); pub const State = struct { gpa: mem.Allocator, diff --git a/src/wayland.zig b/src/wayland.zig @@ -1,332 +0,0 @@ -const std = @import("std"); -const mem = std.mem; -const meta = std.meta; -const os = std.os; -const strcmp = std.cstr.cmp; -const ArrayList = std.ArrayList; - -const wl = @import("wayland").client.wl; -const zwlr = @import("wayland").client.zwlr; -const zriver = @import("wayland").client.zriver; - -const Buffer = @import("Buffer.zig"); -const Event = @import("Loop.zig").Event; -const render = @import("render.zig"); -const State = @import("main.zig").State; -const Bar = @import("Bar.zig"); -const Tags = @import("Tags.zig"); -const utils = @import("utils.zig"); - -pub const Wayland = struct { - state: *State, - display: *wl.Display, - registry: *wl.Registry, - - monitors: ArrayList(*Monitor), - inputs: ArrayList(*Input), - globals: Globals, - globalsMask: GlobalsMask, - - const Globals = struct { - compositor: *wl.Compositor, - subcompositor: *wl.Subcompositor, - shm: *wl.Shm, - layerShell: *zwlr.LayerShellV1, - statusManager: *zriver.StatusManagerV1, - control: *zriver.ControlV1, - }; - const GlobalsMask = utils.Mask(Globals); - - pub fn init(state: *State) !Wayland { - const display = try wl.Display.connect(null); - - return Wayland{ - .state = state, - .display = display, - .registry = try display.getRegistry(), - .monitors = ArrayList(*Monitor).init(state.gpa), - .inputs = ArrayList(*Input).init(state.gpa), - .globals = undefined, - .globalsMask = mem.zeroes(GlobalsMask), - }; - } - - pub fn deinit(self: *Wayland) void { - for (self.monitors.items) |monitor| monitor.destroy(); - for (self.inputs.items) |input| input.destroy(); - - self.monitors.deinit(); - self.inputs.deinit(); - } - - pub fn registerGlobals(self: *Wayland) !void { - self.registry.setListener(*State, registryListener, self.state); - _ = try self.display.roundtrip(); - - for (self.globalsMask) |is_registered| { - if (!is_registered) return error.UnsupportedGlobal; - } - } - - pub fn getEvent(self: *Wayland) !Event { - const fd = self.display.getFd(); - - return Event{ - .fd = .{ - .fd = @intCast(os.fd_t, fd), - .events = os.POLL.IN, - .revents = undefined, - }, - .data = @ptrCast(*anyopaque, self), - .callbackIn = dispatch, - .callbackOut = flush, - }; - } - - fn dispatch(self_opaque: *anyopaque) error{Terminate}!void { - const self = utils.cast(Wayland)(self_opaque); - _ = self.display.dispatch() catch return; - } - - fn flush(self_opaque: *anyopaque) error{Terminate}!void { - const self = utils.cast(Wayland)(self_opaque); - _ = self.display.flush() catch return; - } - - fn registryListener( - registry: *wl.Registry, - event: wl.Registry.Event, - state: *State, - ) void { - const self = &state.wayland; - - switch (event) { - .global => |g| { - self.bindGlobal(registry, g.interface, g.name) catch return; - }, - .global_remove => |data| { - for (self.monitors.items) |monitor, i| { - if (monitor.globalName == data.name) { - monitor.destroy(); - _ = self.monitors.swapRemove(i); - break; - } - } - for (self.inputs.items) |input, i| { - if (input.globalName == data.name) { - input.destroy(); - _ = self.inputs.swapRemove(i); - break; - } - } - }, - } - } - - fn bindGlobal( - self: *Wayland, - registry: *wl.Registry, - iface: [*:0]const u8, - name: u32, - ) !void { - if (strcmp(iface, wl.Compositor.getInterface().name) == 0) { - const global = try registry.bind(name, wl.Compositor, 4); - self.setGlobal(global); - } else if (strcmp(iface, wl.Subcompositor.getInterface().name) == 0) { - const global = try registry.bind(name, wl.Subcompositor, 1); - self.setGlobal(global); - } else if (strcmp(iface, wl.Shm.getInterface().name) == 0) { - const global = try registry.bind(name, wl.Shm, 1); - self.setGlobal(global); - } else if (strcmp(iface, zwlr.LayerShellV1.getInterface().name) == 0) { - const global = try registry.bind(name, zwlr.LayerShellV1, 1); - self.setGlobal(global); - } else if ( - strcmp(iface, zriver.StatusManagerV1.getInterface().name) == 0 - ) { - const global = try registry.bind(name, zriver.StatusManagerV1, 1); - self.setGlobal(global); - } else if (strcmp(iface, zriver.ControlV1.getInterface().name) == 0) { - const global = try registry.bind(name, zriver.ControlV1, 1); - self.setGlobal(global); - } else if (strcmp(iface, wl.Output.getInterface().name) == 0) { - const monitor = try Monitor.create(self.state, registry, name); - try self.monitors.append(monitor); - } else if (strcmp(iface, wl.Seat.getInterface().name) == 0) { - const input = try Input.create(self.state, registry, name); - try self.inputs.append(input); - } - } - - pub fn setGlobal(self: *Wayland, global: anytype) void { - inline for (meta.fields(Globals)) |field, i| { - if (field.field_type == @TypeOf(global)) { - @field(self.globals, field.name) = global; - self.globalsMask[i] = true; - break; - } - } - } - - pub fn findBar(self: *Wayland, wlSurface: ?*wl.Surface) ?*Bar { - if (wlSurface == null) { - return null; - } - for (self.monitors.items) |monitor| { - if (monitor.bar) |bar| { - if (bar.background.surface == wlSurface or - bar.tags.surface == wlSurface or - bar.clock.surface == wlSurface or - bar.modules.surface == wlSurface) - { - return bar; - } - } - } - return null; - } -}; - -pub const Monitor = struct { - state: *State, - output: *wl.Output, - globalName: u32, - scale: i32, - - bar: ?*Bar, - tags: *Tags, - - pub fn create(state: *State, registry: *wl.Registry, name: u32) !*Monitor { - const self = try state.gpa.create(Monitor); - self.state = state; - self.output = try registry.bind(name, wl.Output, 3); - self.globalName = name; - self.scale = 1; - - self.bar = null; - self.tags = try Tags.create(state, self); - - self.output.setListener(*Monitor, listener, self); - return self; - } - - pub fn destroy(self: *Monitor) void { - if (self.bar) |bar| { - bar.destroy(); - } - self.tags.destroy(); - self.state.gpa.destroy(self); - } - - fn listener(_: *wl.Output, event: wl.Output.Event, monitor: *Monitor) void { - switch (event) { - .scale => |scale| { - monitor.scale = scale.factor; - }, - .geometry => {}, - .mode => {}, - .name => {}, - .description => {}, - .done => { - if (monitor.bar) |_| {} else { - monitor.bar = Bar.create(monitor) catch return; - } - }, - } - } -}; - -pub const Input = struct { - state: *State, - seat: *wl.Seat, - globalName: u32, - - pointer: struct { - pointer: ?*wl.Pointer, - x: i32, - y: i32, - bar: ?*Bar, - surface: ?*wl.Surface, - }, - - pub fn create(state: *State, registry: *wl.Registry, name: u32) !*Input { - const self = try state.gpa.create(Input); - self.state = state; - self.seat = try registry.bind(name, wl.Seat, 3); - self.globalName = name; - - self.pointer.pointer = null; - self.pointer.bar = null; - self.pointer.surface = null; - - self.seat.setListener(*Input, listener, self); - return self; - } - - pub fn destroy(self: *Input) void { - if (self.pointer.pointer) |pointer| { - pointer.release(); - } - self.seat.release(); - self.state.gpa.destroy(self); - } - - fn listener(seat: *wl.Seat, event: wl.Seat.Event, input: *Input) void { - switch (event) { - .capabilities => |data| { - if (input.pointer.pointer) |pointer| { - pointer.release(); - input.pointer.pointer = null; - } - if (data.capabilities.pointer) { - input.pointer.pointer = seat.getPointer() catch return; - input.pointer.pointer.?.setListener( - *Input, - pointerListener, - input, - ); - } - }, - .name => {}, - } - } - - fn pointerListener( - _: *wl.Pointer, - event: wl.Pointer.Event, - input: *Input, - ) void { - switch (event) { - .enter => |data| { - input.pointer.x = data.surface_x.toInt(); - input.pointer.y = data.surface_y.toInt(); - const bar = input.state.wayland.findBar(data.surface); - input.pointer.bar = bar; - input.pointer.surface = data.surface; - }, - .leave => |_| { - input.pointer.bar = null; - input.pointer.surface = null; - }, - .motion => |data| { - input.pointer.x = data.surface_x.toInt(); - input.pointer.y = data.surface_y.toInt(); - }, - .button => |data| { - if (data.state != .pressed) return; - if (input.pointer.bar) |bar| { - if (!bar.configured) return; - - const tagsSurface = bar.tags.surface; - if (input.pointer.surface != tagsSurface) return; - - const x = @intCast(u32, input.pointer.x); - if (x < bar.height * 9) { - bar.monitor.tags.handleClick(x, input) catch return; - } - } - }, - else => {}, - } - } -};