aboutsummaryrefslogtreecommitdiff
path: root/src/wl/display.zig
diff options
context:
space:
mode:
authorNathan Reiner <nathan@nathanreiner.xyz>2025-08-22 20:12:56 +0200
committerNathan Reiner <nathan@nathanreiner.xyz>2025-08-22 20:12:56 +0200
commit956ecb061b1862a4b632c8d5d6b6fa4318e1f640 (patch)
treef00adc9bfced275f280239b25a2b2ae15f57765b /src/wl/display.zig
parent33e1de2710fe44512440e0e6055578d67dab330c (diff)
object refactor and add wl output
Now the Object is held by the registry instead of the struct its referencing and the struct only has a `handle` which is a usize.
Diffstat (limited to 'src/wl/display.zig')
-rw-r--r--src/wl/display.zig128
1 files changed, 77 insertions, 51 deletions
diff --git a/src/wl/display.zig b/src/wl/display.zig
index 4f04746..db5ed3c 100644
--- a/src/wl/display.zig
+++ b/src/wl/display.zig
@@ -14,8 +14,8 @@ pub const Error = enum(u32) {
};
pub const Request = union(enum) {
- sync: struct { *wayland.Object },
- get_registry: struct { *wayland.Object },
+ sync: struct { wayland.Object.Ref },
+ get_registry: struct { wayland.Object.Ref },
};
pub const Events = wayland.EventSet(Self, .{
@@ -24,19 +24,23 @@ pub const Events = wayland.EventSet(Self, .{
});
stream: std.net.Stream,
-interface: wayland.Object,
registry: wl.Registry,
+handle: wayland.Object.Ref,
pub fn init(
self: *Self,
allocator: std.mem.Allocator,
handlers: []const wl.Registry.GlobalHandler,
) !void {
- self.interface = wayland.Object.from_self(self);
try self.registry.init(allocator, self, handlers);
}
-pub fn from_fd(fd: std.posix.fd_t) void {
+pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
+ self.close();
+ self.registry.deinit(allocator);
+}
+
+pub fn from_fd(fd: std.posix.fd_t) Self {
var self: Self = undefined;
self.stream = std.net.Stream{ .handle = fd };
return self;
@@ -65,8 +69,12 @@ pub fn default_path(allocator: std.mem.Allocator) ![]const u8 {
return std.fmt.allocPrint(allocator, "{s}/{s}", .{ xdg_runtime_dir, wayland_display });
}
+fn padding_len(T: type, length: usize) usize {
+ return @mod(@as(usize, @bitCast(-@as(isize, @intCast(length * @sizeOf(T))))), 4);
+}
+
pub fn request(self: *Self, object: anytype, args: @TypeOf(object.*).Request) !void {
- comptime std.debug.assert(@FieldType(@TypeOf(object.*), "interface") == wayland.Object);
+ comptime std.debug.assert(@FieldType(@TypeOf(object.*), "handle") == wayland.Object.Ref);
comptime std.debug.assert(@typeInfo(@TypeOf(object.*).Request) == .@"union");
const tag_type = @typeInfo(@TypeOf(args)).@"union".tag_type.?;
const opcode: u32 = @intFromEnum(args);
@@ -74,21 +82,21 @@ pub fn request(self: *Self, object: anytype, args: @TypeOf(object.*).Request) !v
inline for (@typeInfo(tag_type).@"enum".fields) |f| {
if (f.value == opcode) {
const data = @field(args, f.name);
- const id = object.interface.id orelse return error.UnregisteredObject;
+ const id: u32 = @truncate(object.handle);
var size: u32 = 8;
inline for (data) |value| {
switch (@TypeOf(value)) {
u32, i32 => |t| size += @sizeOf(t),
- *wayland.Object => size += @sizeOf(u32),
+ wayland.Object.Ref => size += @sizeOf(u32),
[]const u8, []u8 => {
- const padding_size: usize = @mod(@as(usize, @bitCast(-@as(isize, @intCast(value.len + 1)))), 4);
+ const padding_size: usize = padding_len(u8, value.len + 1);
size += @as(u32, @intCast(@sizeOf(u32) + (value.len + 1) + padding_size));
},
else => |t| switch (@typeInfo(t)) {
.pointer => |ptr| if (ptr.size == .slice) {
- const padding_size: usize = @mod(@as(usize, @bitCast(-@as(isize, @intCast(value.len * @sizeOf(ptr.child))))), 4);
+ const padding_size: usize = padding_len(ptr.child, value.len);
size += @intCast(@sizeOf(u32) + (value.len * @sizeOf(ptr.child)) + padding_size);
} else @compileError(std.fmt.comptimePrint("size: unsupported type {}", .{t})),
else => @compileError(std.fmt.comptimePrint("size: unsupported type {}", .{t})),
@@ -102,9 +110,9 @@ pub fn request(self: *Self, object: anytype, args: @TypeOf(object.*).Request) !v
inline for (data) |value| {
switch (@TypeOf(value)) {
u32, i32 => _ = try self.stream.writeAll(std.mem.asBytes(&value)),
- *wayland.Object => try self.stream.writeAll(std.mem.asBytes(&(value.id orelse return error.UnregisteredObject))),
+ wayland.Object.Ref => try self.stream.writeAll(std.mem.asBytes(&(@as(u32, @truncate(value))))),
[]const u8, []u8 => {
- const padding_size: usize = @mod(@as(usize, @bitCast(-@as(isize, @intCast(value.len + 1)))), 4);
+ const padding_size: usize = padding_len(u8, value.len + 1);
_ = try self.stream.writeAll(std.mem.asBytes(&@as(u32, @truncate(value.len + 1))));
_ = try self.stream.writeAll(value);
for (0..padding_size + 1) |_| {
@@ -131,41 +139,51 @@ pub fn request(self: *Self, object: anytype, args: @TypeOf(object.*).Request) !v
return error.InvalidOpcode;
}
-pub fn roundtrip(self: *Self, allocator: std.mem.Allocator) !void {
- var done = false;
- var callback: wl.Callback = undefined;
- try callback.init(allocator, self, &done);
+fn read_event(self: *Self, ctx: *wayland.Context) !void {
+ const endian = @import("builtin").target.cpu.arch.endian();
+ const reader = self.stream.reader();
+
+ const object_id = try reader.readInt(u32, endian);
+ const message_info = try reader.readInt(u32, endian);
+
+ const opcode: u16 = @truncate(message_info & 0xffff);
+ const size: u16 = @truncate(((message_info >> 16) & 0xffff));
+ const body_size = size - 2 * @sizeOf(u32);
+
+ const body = try ctx.allocator.alloc(u8, body_size);
+ defer ctx.allocator.free(body);
+ _ = try reader.readAll(body);
+
+ if (object_id >= self.registry.objects.items.len) {
+ return error.UnregisteredObject;
+ }
+
+ if (self.registry.get(object_id)) |object| {
+ try object.on_event(ctx, opcode, body);
+ } else {
+ return error.UnregisteredObject;
+ }
+}
+
+pub fn roundtrip(self: *Self, allocator: std.mem.Allocator) !void {
var context: wayland.Context = .{
.display = self,
.allocator = allocator,
};
- while (!done) {
- const endian = @import("builtin").target.cpu.arch.endian();
- const reader = self.stream.reader();
-
- const object_id = try reader.readInt(u32, endian);
-
- const message_info = try reader.readInt(u32, endian);
-
- const opcode: u16 = @truncate(message_info & 0xffff);
- const size: u16 = @truncate(((message_info >> 16) & 0xffff));
- const body_size = size - 2 * @sizeOf(u32);
+ var done = false;
- const body = try allocator.alloc(u8, body_size);
- defer allocator.free(body);
- _ = try reader.readAll(body);
+ var callback: wl.Callback = undefined;
+ try callback.init(&context, &done);
+ defer callback.deinit(&context);
- if (object_id >= self.registry.objects.items.len) {
- return error.UnregisteredObject;
- }
+ errdefer self.read_event(&context) catch |e| {
+ log.err("cleanup error: {}", .{e});
+ };
- if (self.registry.objects.items[object_id]) |object| {
- try object.on_event(&context, opcode, body);
- } else {
- return error.UnregisteredObject;
- }
+ while (!done) {
+ try self.read_event(&context);
}
}
@@ -194,17 +212,17 @@ test "request" {
const Sample = struct {
pub const Request = union(enum) {
req1: struct { u32 },
- req2: struct { *wayland.Object },
+ req2: struct { wayland.Object.Ref },
req3: struct { []const u8 },
req4: struct { []const u16 },
};
pub const Events = wayland.EventSet(@This(), .{});
- interface: wayland.Object,
+ handle: wayland.Object.Ref,
- pub fn init(self: *@This()) void {
- self.interface = wayland.Object.from_self(self);
+ pub fn init() @This() {
+ return .{ .handle = 42 };
}
};
@@ -212,24 +230,32 @@ test "request" {
defer std.posix.close(in);
{
- var sample: Sample = undefined;
- sample.init();
- sample.interface.id = 42;
+ var sample: Sample = .init();
var displ: Self = .from_fd(out);
- defer displ.close();
- try displ.init();
- try displ.request(sample, .{ .req1 = .{432} });
- try displ.request(sample, .{ .req2 = .{&sample.interface} });
- try displ.request(sample, .{ .req3 = .{"abcd"} });
- try displ.request(sample, .{ .req4 = .{&[_]u16{ 1, 32, 4, 5, 5 }} });
+ defer displ.deinit(std.testing.allocator);
+ try displ.init(std.testing.allocator, &.{});
+ try displ.request(&sample, .{ .req1 = .{432} });
+ try displ.request(&sample, .{ .req2 = .{sample.handle} });
+ try displ.request(&sample, .{ .req3 = .{"abcd"} });
+ try displ.request(&sample, .{ .req4 = .{&[_]u16{ 1, 32, 4, 5, 5 }} });
}
const file = std.fs.File{ .handle = in };
+
var test_buffer: [64]u8 = undefined;
_ = try file.readAll(test_buffer[0..12]);
try std.testing.expectEqualSlices(
u8,
+ &(std.mem.toBytes(@as(u32, 1)) ++
+ std.mem.toBytes(@as(u32, (12 << 16) | 1)) ++
+ std.mem.toBytes(@as(u32, 2))),
+ test_buffer[0..12],
+ );
+
+ _ = try file.readAll(test_buffer[0..12]);
+ try std.testing.expectEqualSlices(
+ u8,
&(std.mem.toBytes(@as(u32, 42)) ++
std.mem.toBytes(@as(u32, (12 << 16) | 0)) ++
std.mem.toBytes(@as(u32, 432))),