diff --git a/main.zig b/main.zig index b773f5d..d32cd7d 100644 --- a/main.zig +++ b/main.zig @@ -25,7 +25,6 @@ const Size = struct { width: u32, height: u32, - fn size(self: *Self) usize { return self.width * self.height; } @@ -88,7 +87,7 @@ fn ListItem(comptime T: type) type { value: T, fn Head() type { - list.Head(Self, "link"); + return list.Head(Self, "link"); } fn fromLink(link: *list.Link) *Self { @@ -164,6 +163,55 @@ const Options = struct { } }; +const Output = struct { + const Self = @This(); + + state: *State, + output: *wl.Output, + + geometry: Box, + logical_geometry: Box, + scale: i32, +}; + +/// helper type to handle dynamic dispatch listeners whatever they're called +fn Listener(comptime T: type, comptime D: type) type { + return struct { + const Self = @This(); + const Fn = *const fn (obj: *T, event: T.Event, data: *D) void; + + data: *D, + callback: Fn, + + fn create(data: *D, callback: Fn) Self { + return Self{ + .data = data, + .callback = callback, + }; + } + + fn listener(obj: *T, event: T.Event, self: *Self) void { + return self.callback(obj, event, self.data); + } + + fn set(self: *Self, obj: *T) void { + obj.setListener(*Self, listener, self); + } + + fn cast( + self: *Self, + comptime D2: type, + new_data: *D2, + new_callback: @TypeOf(Listener(T, D2)).Fn, + ) @TypeOf(Listener(T, D2)) { + const other = @ptrCast(Listener(T, D2), self); + other.new_data = new_data; + other.callback = new_callback; + return other; + } + }; +} + const State = struct { const Uninit = struct { const Self = @This(); @@ -173,6 +221,8 @@ const State = struct { dpy: *wl.Display = undefined, registry: *wl.Registry = undefined, + registry_listener: Listener(wl.Registry, Self) = undefined, + shm: ?*wl.Shm = null, compositor: ?*wl.Compositor = null, layer_shell: ?*zwlr.LayerShellV1 = null, @@ -186,13 +236,19 @@ const State = struct { const self = try ally.create(Self); + const listener = .{ + .data = self, + .callback = registryListener, + }; + self.* = .{ .ally = ally, .dpy = dpy, .registry = registry, + .registry_listener = listener, }; - registry.setListener(*Self, registryListener, self); + self.registry_listener.set(self.registry); if (dpy.roundtrip() != .SUCCESS) return error.RoundtripFailed; return self; @@ -203,21 +259,29 @@ const State = struct { } fn registryListener(registry: *wl.Registry, event: wl.Registry.Event, self: *Self) void { - switch (event) { - .global => |global| { - if (std.cstr.cmp(global.interface, wl.Compositor.getInterface().name) == 0) { - self.compositor = registry.bind(global.name, wl.Compositor, 4) catch return; - } else if (std.cstr.cmp(global.interface, wl.Shm.getInterface().name) == 0) { - self.shm = registry.bind(global.name, wl.Shm, 1) catch return; - } else if (std.cstr.cmp(global.interface, zwlr.LayerShellV1.getInterface().name) == 0) { - self.layer_shell = registry.bind(global.name, zwlr.LayerShellV1, 1) catch return; - } else if (std.cstr.cmp(global.interface, zxdg.OutputManagerV1.getInterface().name) == 0) { - self.xdg_output_manager = registry.bind(global.name, zxdg.OutputManagerV1, 2) catch - return; - } - }, - .global_remove => {}, - } + switch (event) { + .global => |global| { + std.debug.print("global: {s}\n", .{global.interface}); + + if (std.cstr.cmp(global.interface, wl.Compositor.getInterface().name) == 0) { + self.compositor = registry.bind(global.name, wl.Compositor, 4) catch return; + } else if (std.cstr.cmp(global.interface, wl.Shm.getInterface().name) == 0) { + self.shm = registry.bind(global.name, wl.Shm, 1) catch return; + } else if (std.cstr.cmp(global.interface, zwlr.LayerShellV1.getInterface().name) == 0) { + self.layer_shell = registry.bind(global.name, zwlr.LayerShellV1, 1) catch return; + } else if (std.cstr.cmp(global.interface, zxdg.OutputManagerV1.getInterface().name) == 0) { + self.xdg_output_manager = registry.bind(global.name, zxdg.OutputManagerV1, 2) catch + return; + } else if (std.cstr.cmp(global.interface, wl.Seat.getInterface().name) == 0) { + const seat = registry.bind(global.name, wl.Seat, 1) catch return; + _ = seat; + } else if (std.cstr.cmp(global.interface, wl.Output.getInterface().name) == 0) { + const output = registry.bind(global.name, wl.Output, 3) catch return; + _ = output; + } + }, + .global_remove => {}, + } } fn intoInit(self: *Self) !*Init { @@ -242,14 +306,10 @@ const State = struct { const cursor_size = std.fmt.parseInt(u32, buf, 10) catch return error.InvalidXCursorSize; - // i hope this is fine but appears to be requried to reset the listener on the registry - self.registry.destroy(); - const registry = try self.dpy.getRegistry(); - - init.* = Init { + init.* = Init{ .ally = self.ally, .dpy = self.dpy, - .registry = registry, + .registry = self.registry, // these 4 fields are set by the registry listener so they may be null at this point // treat that as a hard error tho. @@ -264,7 +324,10 @@ const State = struct { .cursor_size = cursor_size, }; - init.registry.setListener(*Init, Init.registryListener, init); + init.outputs.init(); + + // i hope this is fine but appears to be requried to reset the listener on the registry + init.registry_listener = self.registry_listener.cast(Init, init, Init.registryListener); return init; } @@ -278,6 +341,8 @@ const State = struct { dpy: *wl.Display = undefined, registry: *wl.Registry = undefined, + registry_listener: Listener(wl.Registry, Self) = undefined, + shm: *wl.Shm = undefined, compositor: *wl.Compositor = undefined, layer_shell: *zwlr.LayerShellV1 = undefined, @@ -285,6 +350,8 @@ const State = struct { xkb_context: *xkb.xkb_context = undefined, + outputs: ListItem(Output).Head() = undefined, + cursor_theme: []const u8 = undefined, cursor_size: u32 = undefined, @@ -294,8 +361,7 @@ const State = struct { std.debug.print("registryListener called after init", .{}); switch (event) { .global => {}, - .global_remove => { - }, + .global_remove => {}, } } @@ -314,7 +380,6 @@ const State = struct { }; }; - pub fn main() !void { // Prints to stderr (it's a shortcut based on `std.io.getStdErr()`) std.debug.print("All your {s} are belong to us.\n", .{"codebase"});