displays cat! 🤯
This commit is contained in:
		
							parent
							
								
									afabc727e4
								
							
						
					
					
						commit
						24796ba50d
					
				
							
								
								
									
										543
									
								
								main.zig
									
									
									
									
									
								
							
							
						
						
									
										543
									
								
								main.zig
									
									
									
									
									
								
							|  | @ -16,14 +16,14 @@ const cairo = @cImport({ | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| const Point = struct { | const Point = struct { | ||||||
|     x: i32, |     x: i32 = 0, | ||||||
|     y: i32, |     y: i32 = 0, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const Size = struct { | const Size = struct { | ||||||
|     const Self = @This(); |     const Self = @This(); | ||||||
|     width: u32, |     width: u32 = 0, | ||||||
|     height: u32, |     height: u32 = 0, | ||||||
| 
 | 
 | ||||||
|     fn size(self: *Self) usize { |     fn size(self: *Self) usize { | ||||||
|         return self.width * self.height; |         return self.width * self.height; | ||||||
|  | @ -33,19 +33,27 @@ const Size = struct { | ||||||
| const Box = struct { | const Box = struct { | ||||||
|     const Self = @This(); |     const Self = @This(); | ||||||
| 
 | 
 | ||||||
|     position: Point, |     position: Point = .{.x = 0, .y = 0,}, | ||||||
|     extents: Size, |     extents: Size = .{.width = 0, .height = 0,}, | ||||||
|  | 
 | ||||||
|  |     fn default() Self { | ||||||
|  |         return Self { | ||||||
|  |             .position = .{.x = 0, .y = 0,}, | ||||||
|  |             .extents = .{.width = 0, .height = 0,}, | ||||||
|  |         }; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     fn intersects(self: *const Self, other: *const Self) bool { |     fn intersects(self: *const Self, other: *const Self) bool { | ||||||
|         const x1 = self.position.x; |         const x1 = self.position.x; | ||||||
|         const y1 = self.position.y; |         const y1 = self.position.y; | ||||||
|         const w1 = self.extents.width; |         const w1 = @intCast(isize, self.extents.width); | ||||||
|         const h1 = self.extents.height; |         const h1 = @intCast(isize, self.extents.height); | ||||||
| 
 | 
 | ||||||
|         const x2 = other.position.x; |         const x2 = other.position.x; | ||||||
|         const y2 = other.position.y; |         const y2 = other.position.y; | ||||||
|         const w2 = other.extents.width; | 
 | ||||||
|         const h2 = other.extents.height; |         const w2 = @intCast(isize, other.extents.width); | ||||||
|  |         const h2 = @intCast(isize, other.extents.height); | ||||||
| 
 | 
 | ||||||
|         // return self.x < other.x + other.width and |         // return self.x < other.x + other.width and | ||||||
|         //     self.x + self.width > other.x and |         //     self.x + self.width > other.x and | ||||||
|  | @ -58,11 +66,29 @@ const Box = struct { | ||||||
|             y1 + h1 > y2; |             y1 + h1 > y2; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn contains(self: *Self, point: Point) bool { |     fn fromCorners(a: Point, b: Point) Self { | ||||||
|  |         const top = @min(a.y, b.y); | ||||||
|  |         const bot = @max(a.y, b.y); | ||||||
|  |         const left = @min(a.x, b.x); | ||||||
|  |         const right = @max(a.x, b.x); | ||||||
|  | 
 | ||||||
|  |         const pos = Point{.x = left, .y = top,}; | ||||||
|  |         const extents = Size{ | ||||||
|  |             .width = right - left, | ||||||
|  |             .height = bot - top, | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         return Self { | ||||||
|  |             .position = pos, | ||||||
|  |             .extents = extents, | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn contains(self: *const Self, point: Point) bool { | ||||||
|         const x1 = self.position.x; |         const x1 = self.position.x; | ||||||
|         const y1 = self.position.y; |         const y1 = self.position.y; | ||||||
|         const w1 = self.extents.width; |         const w1 = @intCast(isize, self.extents.width); | ||||||
|         const h1 = self.extents.height; |         const h1 = @intCast(isize, self.extents.height); | ||||||
| 
 | 
 | ||||||
|         const x2 = point.x; |         const x2 = point.x; | ||||||
|         const y2 = point.y; |         const y2 = point.y; | ||||||
|  | @ -79,12 +105,50 @@ const Box = struct { | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | test "box" { | ||||||
|  |     const a = Box.default(); | ||||||
|  |     const a2 = Box{.extents = .{.width = 1, .height = 1,}}; | ||||||
|  |     const b = Box.default(); | ||||||
|  |     const b2 = Box{.extents = .{.width = 1, .height = 1,}}; | ||||||
|  | 
 | ||||||
|  |     std.debug.assert(!a.contains(.{.x = 0, .y = 0})); | ||||||
|  |     std.debug.assert(!a.intersects(&b)); | ||||||
|  | 
 | ||||||
|  |     std.debug.assert(a2.contains(.{.x = 0, .y = 0})); | ||||||
|  |     std.debug.assert(a2.intersects(&b2)); | ||||||
|  | 
 | ||||||
|  |     const c1 = Box{ | ||||||
|  |         .position = .{.x = 1, .y = 1,}, | ||||||
|  |         .extents = .{.width = 2, .height = 2,}, | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     const c2 = Box{ | ||||||
|  |         .position = .{.x = 1, .y = 1,}, | ||||||
|  |         .extents = .{.width = 1, .height = 1,}, | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     std.debug.assert(!c1.intersects(&a2)); | ||||||
|  |     std.debug.assert(c1.intersects(&c2)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| fn ListItem(comptime T: type) type { | fn ListItem(comptime T: type) type { | ||||||
|     return struct { |     return struct { | ||||||
|         const Self = @This(); |         const Self = @This(); | ||||||
| 
 | 
 | ||||||
|         link: list.Link, |         link: list.Link, | ||||||
|         value: T, |         value: T = undefined, | ||||||
|  | 
 | ||||||
|  |         fn create(ally: std.mem.Allocator, value: T) !*Self { | ||||||
|  |             const self = try ally.create(Self); | ||||||
|  | 
 | ||||||
|  |             self.init(value); | ||||||
|  | 
 | ||||||
|  |             return self; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         fn init(self: *Self, value: T) void { | ||||||
|  |             self.value = value; | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         fn Head() type { |         fn Head() type { | ||||||
|             return list.Head(Self, "link"); |             return list.Head(Self, "link"); | ||||||
|  | @ -94,7 +158,12 @@ fn ListItem(comptime T: type) type { | ||||||
|             return @fieldParentPtr(Self, "link", link); |             return @fieldParentPtr(Self, "link", link); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         /// automatically calls `deinit()` on `data` if a function with that name exists | ||||||
|         fn remove(self: *Self) void { |         fn remove(self: *Self) void { | ||||||
|  |             if (@hasDecl(T, "deinit")) { | ||||||
|  |                 self.value.deinit(); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|             self.link.remove(); |             self.link.remove(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -166,12 +235,252 @@ const Options = struct { | ||||||
| const Output = struct { | const Output = struct { | ||||||
|     const Self = @This(); |     const Self = @This(); | ||||||
| 
 | 
 | ||||||
|     state: *State, |     state: *State.Init = undefined, | ||||||
|     output: *wl.Output, |     output: *wl.Output, | ||||||
| 
 | 
 | ||||||
|     geometry: Box, |     surface: *wl.Surface = undefined, | ||||||
|     logical_geometry: Box, |     layer_surface: *zwlr.LayerSurfaceV1 = undefined, | ||||||
|     scale: i32, |     xdg_output: *zxdg.OutputV1 = undefined, | ||||||
|  | 
 | ||||||
|  |     geometry: Box = Box.default(), | ||||||
|  |     logical_geometry: Box = Box.default(), | ||||||
|  |     scale: i32 = 1, | ||||||
|  | 
 | ||||||
|  |     size: Size = Size{}, | ||||||
|  | 
 | ||||||
|  |     configured: bool = false, | ||||||
|  | 
 | ||||||
|  |     fn init(self: *Self, state: *State.Init) !void { | ||||||
|  |         std.debug.print("output.init()\n", .{}); | ||||||
|  |         self.state = state; | ||||||
|  | 
 | ||||||
|  |         self.output.setListener(*Self, outputListener, self); | ||||||
|  | 
 | ||||||
|  |         self.surface = try state.compositor.createSurface(); | ||||||
|  | 
 | ||||||
|  |         self.layer_surface = try state.layer_shell.getLayerSurface( | ||||||
|  |             self.surface, | ||||||
|  |             self.output, | ||||||
|  |             .overlay, | ||||||
|  |             "selection", | ||||||
|  |         ); | ||||||
|  |         self.layer_surface.setListener(*Self, layerSurfaceListener, self); | ||||||
|  | 
 | ||||||
|  |         self.xdg_output = try state.xdg_output_manager.getXdgOutput(self.output); | ||||||
|  |         self.xdg_output.setListener(*Self, xdgOutputListener, self); | ||||||
|  | 
 | ||||||
|  |         self.layer_surface.setAnchor(.{.top = true, .left = true, .right = true, .bottom = true,}); | ||||||
|  |         self.layer_surface.setKeyboardInteractivity(1); | ||||||
|  |         self.layer_surface.setExclusiveZone(-1); | ||||||
|  |         self.surface.commit(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn deinit(self: *Self) void { | ||||||
|  |         self.output.destroy(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn xdgOutputListener(output: *zxdg.OutputV1, event: zxdg.OutputV1.Event, self: *Self) void { | ||||||
|  |         _ = output; | ||||||
|  | 
 | ||||||
|  |         std.debug.print("zxdg_output listener: {}\n", .{event}); | ||||||
|  | 
 | ||||||
|  |         switch (event) { | ||||||
|  |             .logical_position => |pos| { | ||||||
|  |                 self.logical_geometry.position = .{.x = pos.x, .y = pos.y,}; | ||||||
|  |             }, | ||||||
|  |             .logical_size => |size| { | ||||||
|  |                 self.logical_geometry.extents = .{ | ||||||
|  |                     .width = @intCast(u32, size.width), | ||||||
|  |                     .height = @intCast(u32, size.height), | ||||||
|  |                 }; | ||||||
|  |             }, | ||||||
|  |             else => {}, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn layerSurfaceListener( | ||||||
|  |         layer: *zwlr.LayerSurfaceV1, | ||||||
|  |         event: zwlr.LayerSurfaceV1.Event, | ||||||
|  |         self: *Self, | ||||||
|  |     ) void { | ||||||
|  |         std.debug.print("zwlr_layer_surface listener: {}\n", .{event}); | ||||||
|  | 
 | ||||||
|  |         switch (event) { | ||||||
|  |             .configure => |cfg|{ | ||||||
|  |                 self.configured = true; | ||||||
|  |                 self.size = .{ | ||||||
|  |                     .width = cfg.width, | ||||||
|  |                     .height = cfg.height, | ||||||
|  |                 }; | ||||||
|  | 
 | ||||||
|  |                 layer.ackConfigure(cfg.serial); | ||||||
|  |                 // TODO: send frame | ||||||
|  |             }, | ||||||
|  |             else => {}, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn outputListener(output: *wl.Output, event: wl.Output.Event, self: *Self) void { | ||||||
|  |         _ = output; | ||||||
|  | 
 | ||||||
|  |         std.debug.print("wl_output listener: {}\n", .{event}); | ||||||
|  | 
 | ||||||
|  |         switch (event) { | ||||||
|  |             .geometry => |geom| { | ||||||
|  |                 self.geometry.position = .{.x = geom.x, .y = geom.y}; | ||||||
|  |             }, | ||||||
|  |             .mode => |mode| { | ||||||
|  |                 if (!mode.flags.current) { | ||||||
|  |                     self.geometry.extents = .{ | ||||||
|  |                         .width = @intCast(u32,  mode.width), | ||||||
|  |                         .height = @intCast(u32, mode.height), | ||||||
|  |                     }; | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|  |             .scale => |scale| { | ||||||
|  |                 self.scale = scale.factor; | ||||||
|  |             }, | ||||||
|  |             else => { | ||||||
|  |                 std.debug.print("wl_output listener: unhandled\n", .{}); | ||||||
|  |             }, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const Seat = struct { | ||||||
|  |     const Self = @This(); | ||||||
|  | 
 | ||||||
|  |     state: *State.Init = undefined, | ||||||
|  |     seat: *wl.Seat, | ||||||
|  | 
 | ||||||
|  |     keyboard: ?struct { | ||||||
|  |         keyboard: *wl.Keyboard, | ||||||
|  |         xkb: ?struct { | ||||||
|  |             keymap: *xkb.xkb_keymap, | ||||||
|  |             state: *xkb.xkb_state, | ||||||
|  |         } = null, | ||||||
|  |     } = null, | ||||||
|  | 
 | ||||||
|  |     pointer: ?struct { | ||||||
|  |         pointer: *wl.Pointer, | ||||||
|  |         button_state: ?wl.Pointer.ButtonState = null, | ||||||
|  |     } = null, | ||||||
|  | 
 | ||||||
|  |     fn init(self: *Self, state: *State.Init) void { | ||||||
|  |         self.state = state; | ||||||
|  | 
 | ||||||
|  |         std.debug.print("seat.init()\n", .{}); | ||||||
|  |         self.seat.setListener(*Self, seatListener, self); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn pointerListener(pointer: *wl.Pointer, event: wl.Pointer.Event, self: *Self) void { | ||||||
|  |         _ = pointer; | ||||||
|  |         _ = self; | ||||||
|  |         _ = event; | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn keyboardListener(keyboard: *wl.Keyboard, event: wl.Keyboard.Event, self: *Self) void { | ||||||
|  |         _ = keyboard; | ||||||
|  | 
 | ||||||
|  |         switch (event) { | ||||||
|  |             .keymap => |keymap_event| { | ||||||
|  |                 const keymap = blk: { | ||||||
|  |                     switch (keymap_event.format) { | ||||||
|  |                         .no_keymap => { | ||||||
|  |                             break :blk xkb.xkb_keymap_new_from_names( | ||||||
|  |                                 self.state.xkb_context, | ||||||
|  |                                 null, | ||||||
|  |                                 xkb.XKB_KEYMAP_COMPILE_NO_FLAGS, | ||||||
|  |                             ); | ||||||
|  |                         }, | ||||||
|  |                         .xkb_v1 => { | ||||||
|  |                             const buffer = std.os.mmap( | ||||||
|  |                                 null, | ||||||
|  |                                 keymap_event.size, | ||||||
|  |                                 std.os.PROT.READ, | ||||||
|  |                                 std.os.MAP.PRIVATE, | ||||||
|  |                                 keymap_event.fd, | ||||||
|  |                                 0, | ||||||
|  |                             ) catch break :blk null; | ||||||
|  |                             defer std.os.munmap(buffer); | ||||||
|  |                             defer std.os.close(keymap_event.fd); | ||||||
|  | 
 | ||||||
|  |                             break :blk xkb.xkb_keymap_new_from_buffer( | ||||||
|  |                                 self.state.xkb_context, | ||||||
|  |                                 @ptrCast([*c]const u8, buffer), | ||||||
|  |                                 keymap_event.size - 1, | ||||||
|  |                                 xkb.XKB_KEYMAP_FORMAT_TEXT_V1, | ||||||
|  |                                 xkb.XKB_KEYMAP_COMPILE_NO_FLAGS, | ||||||
|  |                             ); | ||||||
|  | 
 | ||||||
|  |                         }, | ||||||
|  |                         else => unreachable, | ||||||
|  |                     } | ||||||
|  |                 }; | ||||||
|  | 
 | ||||||
|  |                 if (keymap) |map| { | ||||||
|  |                     const state = xkb.xkb_state_new(map); | ||||||
|  |                     if (state) |state_| { | ||||||
|  |                         // SAFETY: keyboard cant be null because we are in the keyboard listener | ||||||
|  |                         self.keyboard.?.xkb = .{ | ||||||
|  |                             .keymap = map, | ||||||
|  |                             .state = state_, | ||||||
|  |                         }; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|  |             .key => |key| { | ||||||
|  |                 std.debug.print("key: {} {s}", .{key.key, if (key.state == .pressed) "pressed" else "released"}); | ||||||
|  |             }, | ||||||
|  |             else => {}, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn seatListener(seat: *wl.Seat, event: wl.Seat.Event, self: *Self) void { | ||||||
|  |         switch (event) { | ||||||
|  |             .capabilities => |value| { | ||||||
|  |                 std.debug.print("seat capabilities: {}\n", .{value.capabilities}); | ||||||
|  |                 const capabilities = value.capabilities; | ||||||
|  |                 if (capabilities.keyboard) { | ||||||
|  |                     const keyboard = seat.getKeyboard() catch return; | ||||||
|  |                     self.keyboard = .{ | ||||||
|  |                         .keyboard = keyboard, | ||||||
|  |                     }; | ||||||
|  | 
 | ||||||
|  |                     keyboard.setListener(*Self, keyboardListener, self); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 if (capabilities.pointer) { | ||||||
|  |                     const pointer = seat.getPointer() catch return; | ||||||
|  |                     self.pointer = .{ | ||||||
|  |                         .pointer = pointer, | ||||||
|  |                     }; | ||||||
|  | 
 | ||||||
|  |                     pointer.setListener(*Self, pointerListener, self); | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|  |             else => {}, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn deinit(self: *Self) void { | ||||||
|  |         if (self.keyboard) |keyboard| { | ||||||
|  |             keyboard.keyboard.destroy(); | ||||||
|  | 
 | ||||||
|  |             if (keyboard.xkb) |kb| { | ||||||
|  |                 xkb.xkb_state_unref(kb.state); | ||||||
|  |                 xkb.xkb_keymap_unref(kb.keymap); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (self.pointer) |pointer| { | ||||||
|  |             pointer.pointer.destroy(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         self.seat.destroy(); | ||||||
|  |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /// helper type to handle dynamic dispatch listeners whatever they're called | /// helper type to handle dynamic dispatch listeners whatever they're called | ||||||
|  | @ -202,10 +511,10 @@ fn Listener(comptime T: type, comptime D: type) type { | ||||||
|             self: *Self, |             self: *Self, | ||||||
|             comptime D2: type, |             comptime D2: type, | ||||||
|             new_data: *D2, |             new_data: *D2, | ||||||
|             new_callback: @TypeOf(Listener(T, D2)).Fn, |             new_callback: Listener(T, D2).Fn, | ||||||
|         ) @TypeOf(Listener(T, D2)) { |         ) *Listener(T, D2) { | ||||||
|             const other = @ptrCast(Listener(T, D2), self); |             const other = @ptrCast(*Listener(T, D2), self); | ||||||
|             other.new_data = new_data; |             other.data = new_data; | ||||||
|             other.callback = new_callback; |             other.callback = new_callback; | ||||||
|             return other; |             return other; | ||||||
|         } |         } | ||||||
|  | @ -221,13 +530,16 @@ const State = struct { | ||||||
|         dpy: *wl.Display = undefined, |         dpy: *wl.Display = undefined, | ||||||
|         registry: *wl.Registry = undefined, |         registry: *wl.Registry = undefined, | ||||||
| 
 | 
 | ||||||
|         registry_listener: Listener(wl.Registry, Self) = undefined, |         registry_listener: *Listener(wl.Registry, Self) = undefined, | ||||||
| 
 | 
 | ||||||
|         shm: ?*wl.Shm = null, |         shm: ?*wl.Shm = null, | ||||||
|         compositor: ?*wl.Compositor = null, |         compositor: ?*wl.Compositor = null, | ||||||
|         layer_shell: ?*zwlr.LayerShellV1 = null, |         layer_shell: ?*zwlr.LayerShellV1 = null, | ||||||
|         xdg_output_manager: ?*zxdg.OutputManagerV1 = null, |         xdg_output_manager: ?*zxdg.OutputManagerV1 = null, | ||||||
| 
 | 
 | ||||||
|  |         seats: *ListItem(Seat).Head() = undefined, | ||||||
|  |         outputs: *ListItem(Output).Head() = undefined, | ||||||
|  | 
 | ||||||
|         fn create() !*Self { |         fn create() !*Self { | ||||||
|             const ally = std.heap.c_allocator; |             const ally = std.heap.c_allocator; | ||||||
| 
 | 
 | ||||||
|  | @ -236,7 +548,9 @@ const State = struct { | ||||||
| 
 | 
 | ||||||
|             const self = try ally.create(Self); |             const self = try ally.create(Self); | ||||||
| 
 | 
 | ||||||
|             const listener = .{ |             const listener = try ally.create(Listener(wl.Registry, Self)); | ||||||
|  | 
 | ||||||
|  |             listener.* = .{ | ||||||
|                 .data = self, |                 .data = self, | ||||||
|                 .callback = registryListener, |                 .callback = registryListener, | ||||||
|             }; |             }; | ||||||
|  | @ -246,16 +560,25 @@ const State = struct { | ||||||
|                 .dpy = dpy, |                 .dpy = dpy, | ||||||
|                 .registry = registry, |                 .registry = registry, | ||||||
|                 .registry_listener = listener, |                 .registry_listener = listener, | ||||||
|  |                 .seats = try ally.create(ListItem(Seat).Head()), | ||||||
|  |                 .outputs = try ally.create(ListItem(Output).Head()), | ||||||
|             }; |             }; | ||||||
| 
 | 
 | ||||||
|  |             self.seats.init(); | ||||||
|  |             self.outputs.init(); | ||||||
|  | 
 | ||||||
|             self.registry_listener.set(self.registry); |             self.registry_listener.set(self.registry); | ||||||
|             if (dpy.roundtrip() != .SUCCESS) return error.RoundtripFailed; |             if (dpy.roundtrip() != .SUCCESS) return error.RoundtripFailed; | ||||||
| 
 | 
 | ||||||
|             return self; |             return self; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         fn deinit(self: *Self) !void { |         fn deinit(self: *Self) void { | ||||||
|  |             self.ally.destroy(self.seats); | ||||||
|  |             self.ally.destroy(self.outputs); | ||||||
|             self.ally.destroy(self); |             self.ally.destroy(self); | ||||||
|  | 
 | ||||||
|  |             // TODO: clean up wayland state | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         fn registryListener(registry: *wl.Registry, event: wl.Registry.Event, self: *Self) void { |         fn registryListener(registry: *wl.Registry, event: wl.Registry.Event, self: *Self) void { | ||||||
|  | @ -270,14 +593,22 @@ const State = struct { | ||||||
|                     } else if (std.cstr.cmp(global.interface, zwlr.LayerShellV1.getInterface().name) == 0) { |                     } else if (std.cstr.cmp(global.interface, zwlr.LayerShellV1.getInterface().name) == 0) { | ||||||
|                         self.layer_shell = registry.bind(global.name, zwlr.LayerShellV1, 1) catch return; |                         self.layer_shell = registry.bind(global.name, zwlr.LayerShellV1, 1) catch return; | ||||||
|                     } else if (std.cstr.cmp(global.interface, zxdg.OutputManagerV1.getInterface().name) == 0) { |                     } else if (std.cstr.cmp(global.interface, zxdg.OutputManagerV1.getInterface().name) == 0) { | ||||||
|                         self.xdg_output_manager = registry.bind(global.name, zxdg.OutputManagerV1, 2) catch |                         self.xdg_output_manager = | ||||||
|  |                             registry.bind(global.name, zxdg.OutputManagerV1, 2) catch | ||||||
|                             return; |                             return; | ||||||
|  | 
 | ||||||
|                     } else if (std.cstr.cmp(global.interface, wl.Seat.getInterface().name) == 0) { |                     } else if (std.cstr.cmp(global.interface, wl.Seat.getInterface().name) == 0) { | ||||||
|                         const seat = registry.bind(global.name, wl.Seat, 1) catch return; |                         const seat = registry.bind(global.name, wl.Seat, 1) catch return; | ||||||
|                         _ = seat; | 
 | ||||||
|  |                         if (ListItem(Seat).create(self.ally, Seat{.seat = seat}) catch null) |ele| { | ||||||
|  |                             self.seats.append(ele); | ||||||
|  |                         } | ||||||
|                     } else if (std.cstr.cmp(global.interface, wl.Output.getInterface().name) == 0) { |                     } else if (std.cstr.cmp(global.interface, wl.Output.getInterface().name) == 0) { | ||||||
|                         const output = registry.bind(global.name, wl.Output, 3) catch return; |                         const output = registry.bind(global.name, wl.Output, 3) catch return; | ||||||
|                         _ = output; | 
 | ||||||
|  |                         if (ListItem(Output).create(self.ally, Output{.output = output}) catch null) |ele| { | ||||||
|  |                             self.outputs.append(ele); | ||||||
|  |                         } | ||||||
|                     } |                     } | ||||||
|                 }, |                 }, | ||||||
|                 .global_remove => {}, |                 .global_remove => {}, | ||||||
|  | @ -292,42 +623,7 @@ const State = struct { | ||||||
|             // free allocated memory if not returning it |             // free allocated memory if not returning it | ||||||
|             errdefer self.ally.destroy(init); |             errdefer self.ally.destroy(init); | ||||||
| 
 | 
 | ||||||
|             const xkb_context = xkb.xkb_context_new(xkb.XKB_CONTEXT_NO_FLAGS) orelse |             try init.init(self); | ||||||
|                 return error.NoXkbContext; |  | ||||||
|             // free xkb_context if we fail to initialize the state |  | ||||||
|             errdefer xkb.xkb_context_unref(xkb_context); |  | ||||||
| 
 |  | ||||||
|             const cursor_theme = std.process.getEnvVarOwned(self.ally, "XCURSOR_THEME") catch ""; |  | ||||||
|             // only free cursor_theme if bailing |  | ||||||
|             errdefer self.ally.free(cursor_theme); |  | ||||||
| 
 |  | ||||||
|             const buf = try std.process.getEnvVarOwned(self.ally, "XCURSOR_SIZE"); |  | ||||||
|             defer self.ally.free(buf); |  | ||||||
| 
 |  | ||||||
|             const cursor_size = std.fmt.parseInt(u32, buf, 10) catch return error.InvalidXCursorSize; |  | ||||||
| 
 |  | ||||||
|             init.* = Init{ |  | ||||||
|                 .ally = self.ally, |  | ||||||
|                 .dpy = self.dpy, |  | ||||||
|                 .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. |  | ||||||
|                 .shm = self.shm orelse return error.NoWlShm, |  | ||||||
|                 .compositor = self.compositor orelse return error.NoWlCompositor, |  | ||||||
|                 .layer_shell = self.layer_shell orelse return error.NoWlrLayerShell, |  | ||||||
|                 .xdg_output_manager = self.xdg_output_manager orelse return error.NoXdgOutputManager, |  | ||||||
| 
 |  | ||||||
|                 // these 3 fields should never be null because init() will bail if these functions fail |  | ||||||
|                 .xkb_context = xkb_context, |  | ||||||
|                 .cursor_theme = cursor_theme, |  | ||||||
|                 .cursor_size = cursor_size, |  | ||||||
|             }; |  | ||||||
| 
 |  | ||||||
|             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; |             return init; | ||||||
|         } |         } | ||||||
|  | @ -341,7 +637,7 @@ const State = struct { | ||||||
|         dpy: *wl.Display = undefined, |         dpy: *wl.Display = undefined, | ||||||
|         registry: *wl.Registry = undefined, |         registry: *wl.Registry = undefined, | ||||||
| 
 | 
 | ||||||
|         registry_listener: Listener(wl.Registry, Self) = undefined, |         registry_listener: *Listener(wl.Registry, Self) = undefined, | ||||||
| 
 | 
 | ||||||
|         shm: *wl.Shm = undefined, |         shm: *wl.Shm = undefined, | ||||||
|         compositor: *wl.Compositor = undefined, |         compositor: *wl.Compositor = undefined, | ||||||
|  | @ -350,11 +646,70 @@ const State = struct { | ||||||
| 
 | 
 | ||||||
|         xkb_context: *xkb.xkb_context = undefined, |         xkb_context: *xkb.xkb_context = undefined, | ||||||
| 
 | 
 | ||||||
|         outputs: ListItem(Output).Head() = undefined, |  | ||||||
| 
 |  | ||||||
|         cursor_theme: []const u8 = undefined, |         cursor_theme: []const u8 = undefined, | ||||||
|         cursor_size: u32 = undefined, |         cursor_size: u32 = undefined, | ||||||
| 
 | 
 | ||||||
|  |         seats: *ListItem(Seat).Head() = undefined, | ||||||
|  |         outputs: *ListItem(Output).Head() = undefined, | ||||||
|  | 
 | ||||||
|  |         fn init(self: *Self, uninit: *Uninit) !void { | ||||||
|  |             const xkb_context = xkb.xkb_context_new(xkb.XKB_CONTEXT_NO_FLAGS) orelse | ||||||
|  |                 return error.NoXkbContext; | ||||||
|  |             // free xkb_context if we fail to initialize the state | ||||||
|  |             errdefer xkb.xkb_context_unref(xkb_context); | ||||||
|  | 
 | ||||||
|  |             const cursor_theme = std.process.getEnvVarOwned(uninit.ally, "XCURSOR_THEME") catch ""; | ||||||
|  |             // only free cursor_theme if bailing | ||||||
|  |             errdefer uninit.ally.free(cursor_theme); | ||||||
|  | 
 | ||||||
|  |             const buf = try std.process.getEnvVarOwned(uninit.ally, "XCURSOR_SIZE"); | ||||||
|  |             defer uninit.ally.free(buf); | ||||||
|  | 
 | ||||||
|  |             const cursor_size = std.fmt.parseInt(u32, buf, 10) catch return error.InvalidXCursorSize; | ||||||
|  | 
 | ||||||
|  |             self.* = Self{ | ||||||
|  |                 .ally = uninit.ally, | ||||||
|  |                 .dpy = uninit.dpy, | ||||||
|  |                 .registry = uninit.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. | ||||||
|  |                 .shm = uninit.shm orelse return error.NoWlShm, | ||||||
|  |                 .compositor = uninit.compositor orelse return error.NoWlCompositor, | ||||||
|  |                 .layer_shell = uninit.layer_shell orelse return error.NoWlrLayerShell, | ||||||
|  |                 .xdg_output_manager = uninit.xdg_output_manager orelse return error.NoXdgOutputManager, | ||||||
|  | 
 | ||||||
|  |                 // these 3 fields should never be null because init() will bail if these functions fail | ||||||
|  |                 .xkb_context = xkb_context, | ||||||
|  |                 .cursor_theme = cursor_theme, | ||||||
|  |                 .cursor_size = cursor_size, | ||||||
|  | 
 | ||||||
|  |                 .seats = uninit.seats, | ||||||
|  |                 .outputs = uninit.outputs, | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             // i hope this is fine but appears to be requried to reset the listener on the registry | ||||||
|  |             self.registry_listener = uninit.registry_listener.cast(Self, self, Self.registryListener); | ||||||
|  | 
 | ||||||
|  |             // init seats | ||||||
|  | 
 | ||||||
|  |             var seats_iter = self.seats.safeIterator(.forward); | ||||||
|  |             while (seats_iter.next()) |item| { | ||||||
|  |                 const seat = item.get(); | ||||||
|  |                 seat.init(self); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // init outputs | ||||||
|  | 
 | ||||||
|  |             var output_iter = self.outputs.safeIterator(.forward); | ||||||
|  |             while (output_iter.next()) |item| { | ||||||
|  |                 const output = item.get(); | ||||||
|  |                 try output.init(self); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (self.dpy.roundtrip() != .SUCCESS) return error.RoundtripFailed; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         fn registryListener(registry: *wl.Registry, event: wl.Registry.Event, self: *Self) void { |         fn registryListener(registry: *wl.Registry, event: wl.Registry.Event, self: *Self) void { | ||||||
|             _ = registry; |             _ = registry; | ||||||
|             _ = self; |             _ = self; | ||||||
|  | @ -365,9 +720,58 @@ const State = struct { | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         fn stuff(self: *Self) !void { | ||||||
|  |             var it = self.outputs.iterator(.forward); | ||||||
|  |             if (it.next()) |link| { | ||||||
|  |                 const output = link.get(); | ||||||
|  |                 const os = std.os; | ||||||
|  | 
 | ||||||
|  |                 const buffer = blk: { | ||||||
|  |                     const width = 128; | ||||||
|  |                     const height = 128; | ||||||
|  |                     const stride = width * 4; | ||||||
|  |                     const size = stride * height; | ||||||
|  | 
 | ||||||
|  |                     const fd = try os.memfd_create("hello-zig-wayland", 0); | ||||||
|  |                     try os.ftruncate(fd, size); | ||||||
|  |                     const data = try os.mmap(null, size, os.PROT.READ | os.PROT.WRITE, os.MAP.SHARED, fd, 0); | ||||||
|  |                     std.mem.copy(u8, data, @embedFile("cat.bgra")); | ||||||
|  | 
 | ||||||
|  |                     const pool = try self.shm.createPool(fd, size); | ||||||
|  |                     defer pool.destroy(); | ||||||
|  | 
 | ||||||
|  |                     break :blk try pool.createBuffer(0, width, height, stride, wl.Shm.Format.argb8888); | ||||||
|  |                 }; | ||||||
|  |                 defer buffer.destroy(); | ||||||
|  | 
 | ||||||
|  |                 output.surface.attach(buffer, 0, 0); | ||||||
|  |                 output.surface.commit(); | ||||||
|  | 
 | ||||||
|  |                 while (true) { | ||||||
|  |                     if (self.dpy.dispatch() != .SUCCESS) return error.DispatchFailed; | ||||||
|  |                     std.debug.print("asdf\n", .{}); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         fn deinit(self: *Self) void { |         fn deinit(self: *Self) void { | ||||||
|             defer self.ally.destroy(self); |             defer self.ally.destroy(self); | ||||||
| 
 | 
 | ||||||
|  |             var seats_iter = self.seats.safeIterator(.forward); | ||||||
|  |             while (seats_iter.next()) |next| { | ||||||
|  |                 next.remove(); | ||||||
|  |                 self.ally.destroy(next); | ||||||
|  |             } | ||||||
|  |             self.ally.destroy(self.seats); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |             var outputs_iter = self.outputs.safeIterator(.forward); | ||||||
|  |             while (outputs_iter.next()) |next| { | ||||||
|  |                 next.remove(); | ||||||
|  |                 self.ally.destroy(next); | ||||||
|  |             } | ||||||
|  |             self.ally.destroy(self.outputs); | ||||||
|  | 
 | ||||||
|             self.shm.destroy(); |             self.shm.destroy(); | ||||||
|             self.compositor.destroy(); |             self.compositor.destroy(); | ||||||
|             self.layer_shell.destroy(); |             self.layer_shell.destroy(); | ||||||
|  | @ -386,8 +790,7 @@ pub fn main() !void { | ||||||
| 
 | 
 | ||||||
|     const state = try State.Uninit.create(); |     const state = try State.Uninit.create(); | ||||||
|     const init = try state.intoInit(); |     const init = try state.intoInit(); | ||||||
| 
 |  | ||||||
|     _ = try std.io.getStdIn().reader().readByte(); |  | ||||||
| 
 |  | ||||||
|     defer init.deinit(); |     defer init.deinit(); | ||||||
|  | 
 | ||||||
|  |     try init.stuff(); | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue