diff options
Diffstat (limited to 'src/wl/display.zig')
| -rw-r--r-- | src/wl/display.zig | 128 |
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))), |