From afabc727e4e7bd0150d12a4aebdb705ee93eb08d Mon Sep 17 00:00:00 2001
From: Janis <janis@nirgendwo.xyz>
Date: Thu, 15 Dec 2022 19:12:02 +0100
Subject: [PATCH] formating and listener helper struct

---
 main.zig | 121 ++++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 93 insertions(+), 28 deletions(-)

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"});