1const std = @import("std");2const log = std.log;3const mem = std.mem;4const meta = std.meta;5const posix = std.posix;67const wl = @import("wayland").client.wl;8const wp = @import("wayland").client.wp;9const zwlr = @import("wayland").client.zwlr;10const zriver = @import("wayland").client.zriver;1112const Bar = @import("Bar.zig");13const Input = @import("Input.zig");14const Monitor = @import("Monitor.zig");15const Seat = @import("Seat.zig");16const Wayland = @This();1718const state = &@import("root").state;1920display: *wl.Display,21registry: *wl.Registry,22fd: posix.fd_t,2324compositor: ?*wl.Compositor = null,25subcompositor: ?*wl.Subcompositor = null,26seat: ?*wl.Seat = null,27shm: ?*wl.Shm = null,28single_pixel_buffer_manager: ?*wp.SinglePixelBufferManagerV1 = null,29viewporter: ?*wp.Viewporter = null,30layer_shell: ?*zwlr.LayerShellV1 = null,31status_manager: ?*zriver.StatusManagerV1 = null,32control: ?*zriver.ControlV1 = null,3334river_seat: ?*Seat = null,35monitors: std.ArrayList(*Monitor),36inputs: std.ArrayList(*Input),3738pub fn init() !Wayland {39 const display = try wl.Display.connect(null);40 const wfd: posix.fd_t = @intCast(display.getFd());41 const registry = try display.getRegistry();4243 return Wayland{44 .display = display,45 .registry = registry,46 .fd = wfd,47 .monitors = std.ArrayList(*Monitor).empty,48 .inputs = std.ArrayList(*Input).empty,49 };50}5152pub fn deinit(self: *Wayland) void {53 for (self.monitors.items) |monitor| monitor.destroy();54 for (self.inputs.items) |input| input.destroy();5556 if (self.river_seat) |s| s.destroy();57 self.monitors.deinit(state.gpa);58 self.inputs.deinit(state.gpa);5960 if (self.compositor) |global| global.destroy();61 if (self.subcompositor) |global| global.destroy();62 if (self.shm) |global| global.destroy();63 if (self.viewporter) |global| global.destroy();64 if (self.single_pixel_buffer_manager) |global| global.destroy();65 if (self.layer_shell) |global| global.destroy();66 if (self.status_manager) |global| global.destroy();67 if (self.control) |global| global.destroy();68 // TODO: Do we need to .release() the seat?69 if (self.seat) |global| global.destroy();7071 self.registry.destroy();72 self.display.disconnect();73}7475pub fn registerGlobals(self: *Wayland) !void {76 self.registry.setListener(*Wayland, registryListener, self);7778 const errno = self.display.roundtrip();79 if (errno != .SUCCESS) {80 return error.RoundtripFailed;81 }82}8384pub fn findBar(self: *Wayland, wlSurface: ?*wl.Surface) ?*Bar {85 if (wlSurface == null) {86 return null;87 }88 for (self.monitors.items) |monitor| {89 if (monitor.bar) |bar| {90 if (bar.background.surface == wlSurface or91 bar.title.surface == wlSurface or92 bar.tags.surface == wlSurface or93 bar.text.surface == wlSurface)94 {95 return bar;96 }97 }98 }99 return null;100}101102fn registryListener(registry: *wl.Registry, event: wl.Registry.Event, self: *Wayland) void {103 switch (event) {104 .global => |g| {105 self.bindGlobal(registry, g.name, g.interface) catch unreachable;106 },107 .global_remove => |g| {108 for (self.monitors.items, 0..) |monitor, i| {109 if (monitor.globalName == g.name) {110 self.monitors.swapRemove(i).destroy();111 break;112 }113 }114 for (self.inputs.items, 0..) |input, i| {115 if (input.globalName == g.name) {116 self.inputs.swapRemove(i).destroy();117 break;118 }119 }120 },121 }122}123124fn bindGlobal(self: *Wayland, registry: *wl.Registry, name: u32, iface: [*:0]const u8) !void {125 if (mem.orderZ(u8, iface, wl.Compositor.interface.name) == .eq) {126 self.compositor = try registry.bind(name, wl.Compositor, 4);127 } else if (mem.orderZ(u8, iface, wl.Subcompositor.interface.name) == .eq) {128 self.subcompositor = try registry.bind(name, wl.Subcompositor, 1);129 } else if (mem.orderZ(u8, iface, wl.Shm.interface.name) == .eq) {130 self.shm = try registry.bind(name, wl.Shm, 1);131 } else if (mem.orderZ(u8, iface, wp.Viewporter.interface.name) == .eq) {132 self.viewporter = try registry.bind(name, wp.Viewporter, 1);133 } else if (mem.orderZ(u8, iface, wp.SinglePixelBufferManagerV1.interface.name) == .eq) {134 self.single_pixel_buffer_manager = try registry.bind(name, wp.SinglePixelBufferManagerV1, 1);135 } else if (mem.orderZ(u8, iface, zwlr.LayerShellV1.interface.name) == .eq) {136 self.layer_shell = try registry.bind(name, zwlr.LayerShellV1, 1);137 } else if (mem.orderZ(u8, iface, zriver.StatusManagerV1.interface.name) == .eq) {138 self.status_manager = try registry.bind(name, zriver.StatusManagerV1, 2);139 self.river_seat = try Seat.create(); // TODO: find a better way to do this140 } else if (mem.orderZ(u8, iface, zriver.ControlV1.interface.name) == .eq) {141 self.control = try registry.bind(name, zriver.ControlV1, 1);142 } else if (mem.orderZ(u8, iface, wl.Output.interface.name) == .eq) {143 const monitor = try Monitor.create(registry, name);144 try self.monitors.append(state.gpa, monitor);145 } else if (mem.orderZ(u8, iface, wl.Seat.interface.name) == .eq) {146 self.seat = try registry.bind(name, wl.Seat, 5);147 try self.inputs.append(state.gpa, try Input.create(name));148 }149}