From 8a7392dea729d3ed49a8bf8eee25906c4fd616ac Mon Sep 17 00:00:00 2001 From: Nathan Reiner Date: Wed, 27 Aug 2025 09:02:43 +0200 Subject: Add ancillary data mechanism to send fds to compositor. Currently we are just attaching the fds to the object id. In theory this is not a valid implementation, since if we have more than MAX_FD file descriptors this will not work. But since this wont be the case in basically all cases of the wayland protocol, we can just ignore that for now. --- src/ancillary-data.zig | 38 +++++++++---------- src/event-set.zig | 4 +- src/main.zig | 26 +++++++++++-- src/object.zig | 22 +++++++++-- src/wl/callback.zig | 6 +-- src/wl/compositor.zig | 4 +- src/wl/display.zig | 87 +++++++++++++++++++++++++++++-------------- src/wl/output/root.zig | 16 ++++---- src/wl/registry.zig | 8 ++-- src/wl/shm/anonymous-file.zig | 53 ++++++++++++++++++++++++++ src/wl/shm/pool.zig | 37 +++++++++++++++++- src/wl/shm/root.zig | 25 ++++++++++--- 12 files changed, 248 insertions(+), 78 deletions(-) create mode 100644 src/wl/shm/anonymous-file.zig diff --git a/src/ancillary-data.zig b/src/ancillary-data.zig index 0754720..667ba1f 100644 --- a/src/ancillary-data.zig +++ b/src/ancillary-data.zig @@ -18,47 +18,47 @@ const ControlMessage = extern struct { }; header: Header, - payload: union { + payload: extern union { fd: [255]std.posix.fd_t, }, pub fn alignment(length: usize) usize { - return (length + @sizeOf(usize) - 1) & ~(@sizeOf(usize) - 1); + return (length + @sizeOf(usize) - 1) & ~(@as(usize, @sizeOf(usize) - 1)); } - pub fn space(self: @This()) usize { - return self.alignment(self.length) + self.alignment(@sizeOf(Header)); + pub fn space(length: usize) usize { + return alignment(length) + alignment(@sizeOf(Header)); } pub fn from_fds(fds: []std.posix.fd_t) @This() { - var self: @This() = .{ - }; + var self: @This() = undefined; - self.level = .socket; - self.kind = .rights; - self.length = self.alignment(@sizeOf(Header)) + (fds.len * @sizeOf(std.posix.fd_t)); + self.header.level = .socket; + self.header.kind = .rights; + self.header.length = alignment(@sizeOf(Header)) + (fds.len * @sizeOf(std.posix.fd_t)); - @memcpy(self.payload, fds); + @memcpy(self.payload.fd[0..fds.len], fds); + + return self; } }; -pub fn send_fds(socket: std.posix.socket_t, fds: []std.posix.fd_t) !void { - var iobuf: [1]u8 = std.mem.zeroes([1]u8); +pub fn send_fds(socket: std.posix.socket_t, fds: []std.posix.fd_t, data: []const u8) !void { + var cmsg: ControlMessage = .from_fds(fds); const io = std.posix.iovec { - .base = &iobuf, - .len = iobuf.len, + .base = @constCast(@ptrCast(data)), + .len = data.len, }; - var cmsg: ControlMessage = .from_fds(fds); - const msghdr = std.posix.msghdr_const { .name = null, .namelen = 0, - .iov = &io, - .iolen = 1, + .iov = @ptrCast(&io), + .iovlen = 1, .control = &cmsg, - .controllen = cmsg.control_length(), + .controllen = @intCast(ControlMessage.space(fds.len)), + .flags = 0, }; _ = try std.posix.sendmsg(socket, &msghdr, 0); diff --git a/src/event-set.zig b/src/event-set.zig index 27c28bf..da17734 100644 --- a/src/event-set.zig +++ b/src/event-set.zig @@ -3,7 +3,7 @@ const wayland = @import("root.zig"); pub fn EventSet(T: type, events: anytype) type { return struct { - pub fn on_event(ptr: *anyopaque, ctx: *wayland.Context, opcode: u16, args: []const u8) void { + pub fn on_event(ptr: *anyopaque, ctx: *const wayland.Context, opcode: u16, args: []const u8) void { var offset: usize = 0; inline for (events, 0..) |event, index| { if (@TypeOf(event) != @TypeOf(null) and index == opcode) { @@ -66,7 +66,7 @@ test { a: u32 = 0, b: u32 = 0, - pub fn something(self: *@This(), _: *wayland.Context, a: u32, b: u32) void { + pub fn something(self: *@This(), _: *const wayland.Context, a: u32, b: u32) void { self.a = a; self.b = b; } diff --git a/src/main.zig b/src/main.zig index b6806be..b822109 100644 --- a/src/main.zig +++ b/src/main.zig @@ -2,6 +2,14 @@ const std = @import("std"); const wayland = @import("wayland"); const wl = wayland.wl; +const log = std.log.scoped(.main); + +pub const std_options = std.Options{ + .log_scope_levels = &.{ + .{ .scope = .registry, .level = .info }, + } +}; + pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; const allocator = gpa.allocator(); @@ -17,15 +25,27 @@ pub fn main() !void { try display.roundtrip(allocator); try display.roundtrip(allocator); + const ctx: wayland.Context = .{ + .allocator = allocator, + .display = &display, + }; + + try display.roundtrip(allocator); + for (wl.Output.instances.items) |output| { - std.debug.print("{}\n", .{output}); + log.debug("{}", .{output}); } for (wl.Compositor.instances.items) |compositor| { - std.debug.print("{}\n", .{compositor}); + log.debug("{}", .{compositor}); } for (wl.Shm.instances.items) |shm| { - std.debug.print("{}\n", .{shm}); + log.debug("{}", .{shm}); } + + const pool = try wl.Shm.instances.items[0].create_pool(&ctx, 1024); + defer pool.deinit(&ctx); + + try display.roundtrip(allocator); } diff --git a/src/object.zig b/src/object.zig index 14089c1..5502d3d 100644 --- a/src/object.zig +++ b/src/object.zig @@ -6,13 +6,24 @@ const Self = @This(); pub const Ref = usize; const VTable = struct { - on_event: *const fn (ptr: *anyopaque, ctx: *wayland.Context, opcode: u16, args: []const u8) void, + on_event: *const fn ( + ptr: *anyopaque, + ctx: *const wayland.Context, + opcode: u16, + args: []const u8, + ) void, }; ptr: ?*anyopaque, vtable: VTable, +name: []const u8, -pub inline fn on_event(self: *Self, ctx: *wayland.Context, opcode: u16, args: []const u8) !void { +pub inline fn on_event( + self: *Self, + ctx: *const wayland.Context, + opcode: u16, + args: []const u8, +) !void { if (self.ptr) |ptr| { self.vtable.on_event(ptr, ctx, opcode, args); } else { @@ -21,11 +32,14 @@ pub inline fn on_event(self: *Self, ctx: *wayland.Context, opcode: u16, args: [] } pub inline fn from_self(ptr: anytype) Self { + const T = @TypeOf(ptr.*); + return .{ .ptr = ptr, .vtable = VTable{ - .on_event = @TypeOf(ptr.*).Events.on_event, + .on_event = T.Events.on_event, }, + .name = @typeName(T), }; } @@ -42,5 +56,5 @@ pub fn format( _ = fmt; _ = options; - try writer.print("Object {{ {?} }}", .{self.ptr}); + try writer.print("Object<{s}> {{ {?} }}", .{self.name, self.ptr}); } diff --git a/src/wl/callback.zig b/src/wl/callback.zig index c17e190..24927b4 100644 --- a/src/wl/callback.zig +++ b/src/wl/callback.zig @@ -13,7 +13,7 @@ handle: wayland.Object.Ref, pub fn init( self: *Self, - ctx: *wayland.Context, + ctx: *const wayland.Context, is_done: *bool, ) !void { self.is_done = is_done; @@ -25,11 +25,11 @@ pub fn init( } -pub fn deinit(self: *Self, ctx: *wayland.Context) void { +pub fn deinit(self: *Self, ctx: *const wayland.Context) void { ctx.display.registry.disable_object(self.handle); } -fn done(self: *Self, ctx: *wayland.Context, value: u32) void { +fn done(self: *Self, ctx: *const wayland.Context, value: u32) void { _ = value; _ = ctx; self.is_done.* = true; diff --git a/src/wl/compositor.zig b/src/wl/compositor.zig index 6951446..18db0f0 100644 --- a/src/wl/compositor.zig +++ b/src/wl/compositor.zig @@ -22,7 +22,7 @@ pub const handler: wl.Registry.GlobalHandler = .{ pub fn init( self: *Self, - ctx: *wayland.Context + ctx: *const wayland.Context ) !void { self.* = .{ .handle = try ctx.display.registry.add_object( @@ -32,7 +32,7 @@ pub fn init( }; } -fn register(ctx: *wayland.Context) ?wayland.Object.Ref { +fn register(ctx: *const wayland.Context) ?wayland.Object.Ref { const compositor = ctx.allocator.create(Self) catch return null; compositor.init(ctx) catch return null; diff --git a/src/wl/display.zig b/src/wl/display.zig index 3b5087d..c9e2e6e 100644 --- a/src/wl/display.zig +++ b/src/wl/display.zig @@ -86,7 +86,7 @@ pub fn request(self: *Self, object: anytype, args: @TypeOf(object.*).Request) !v const id: u32 = @truncate(object.handle); var size: u32 = 8; - comptime var fds: []std.posix.fd_t = &.{}; + comptime var count_fds = 0; inline for (data) |value| { switch (@TypeOf(value)) { @@ -97,7 +97,7 @@ pub fn request(self: *Self, object: anytype, args: @TypeOf(object.*).Request) !v const padding_size: usize = padding_len(u8, value.len + 1); size += @as(u32, @intCast(@sizeOf(u32) + (value.len + 1) + padding_size)); }, - wayland.types.Fd => |fd| fds = fds ++ .{ fd }, + wayland.types.Fd => count_fds += 1, else => |t| switch (@typeInfo(t)) { .pointer => |ptr| if (ptr.size == .slice) { const padding_size: usize = padding_len(ptr.child, value.len); @@ -108,14 +108,30 @@ pub fn request(self: *Self, object: anytype, args: @TypeOf(object.*).Request) !v } } - _ = try self.stream.writeAll(&std.mem.toBytes(id)); + { + var fds: [count_fds]std.posix.fd_t = undefined; + comptime var current_fd_index = 0; + + inline for (data) |value| { + switch (@TypeOf(value)) { + wayland.types.Fd => { + fds[current_fd_index] = value.fd; + current_fd_index += 1; + }, + else => {}, + } + } + + try ancillary_data.send_fds(self.stream.handle, &fds, std.mem.asBytes(&id)); + } + _ = try self.stream.writeAll(&std.mem.toBytes((size << 16) | opcode)); inline for (data) |value| { switch (@TypeOf(value)) { u32, i32 => _ = try self.stream.writeAll(std.mem.asBytes(&value)), wayland.Object.Ref => try self.stream.writeAll(std.mem.asBytes(&(@as(u32, @truncate(value))))), - ?wayland.Object.Ref => try self.stream.writeAll(std.mem.asBytes(&(@as(u32, 0)))), + ?wayland.Object.Ref => try self.stream.writeAll(std.mem.asBytes(&(@as(u32, @truncate(if (value) |v| v else 0))))), []const u8, []u8 => { const padding_size: usize = padding_len(u8, value.len + 1); _ = try self.stream.writeAll(std.mem.asBytes(&@as(u32, @truncate(value.len + 1)))); @@ -124,10 +140,10 @@ pub fn request(self: *Self, object: anytype, args: @TypeOf(object.*).Request) !v _ = try self.stream.writeAll(std.mem.asBytes(&@as(u8, 0))); } }, - wayland.types.Fd => {}, + wayland.types.Fd => { }, 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); _ = try self.stream.writeAll(std.mem.asBytes(&@as(u32, @truncate(value.len)))); _ = try self.stream.writeAll(std.mem.sliceAsBytes(value)); for (0..padding_size) |_| { @@ -139,10 +155,6 @@ pub fn request(self: *Self, object: anytype, args: @TypeOf(object.*).Request) !v } } - if (fds.len > 0) { - try ancillary_data.send_fds(self.stream.handle, fds); - } - return; } } @@ -150,7 +162,7 @@ pub fn request(self: *Self, object: anytype, args: @TypeOf(object.*).Request) !v return error.InvalidOpcode; } -fn read_event(self: *Self, ctx: *wayland.Context) !void { +fn read_event(self: *Self, ctx: *const wayland.Context) !void { const endian = @import("builtin").target.cpu.arch.endian(); const reader = self.stream.reader(); @@ -200,7 +212,7 @@ pub fn roundtrip(self: *Self, allocator: std.mem.Allocator) !void { fn err( self: *Self, - ctx: *wayland.Context, + ctx: *const wayland.Context, object: *wayland.Object, code: u32, message: []const u8, @@ -212,7 +224,7 @@ fn err( fn delete_id( self: *Self, - ctx: *wayland.Context, + ctx: *const wayland.Context, id: u32, ) void { _ = ctx; @@ -226,6 +238,7 @@ test "request" { req2: struct { wayland.Object.Ref }, req3: struct { []const u8 }, req4: struct { []const u16 }, + req5: struct { wayland.types.Fd }, }; pub const Events = wayland.EventSet(@This(), .{}); @@ -237,66 +250,86 @@ test "request" { } }; - const in, const out = try std.posix.pipe(); - defer std.posix.close(in); + var tmpdir = std.testing.tmpDir(.{}); + defer tmpdir.cleanup(); + + var pathbuf: [std.fs.max_path_bytes]u8 = undefined; + var dirbuf: [std.fs.max_path_bytes]u8 = undefined; + const path = try std.fmt.bufPrint(&pathbuf, "{s}/testing", .{try tmpdir.dir.realpath(".", &dirbuf)}); + + const address = try std.net.Address.initUnix(path); + var server = try address.listen(.{}); { var sample: Sample = .init(); - var displ: Self = .from_fd(out); + var displ: Self = try .open(path); 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 }} }); + try displ.request(&sample, .{ .req5 = .{ .{ .fd = displ.stream.handle } } }); } - const file = std.fs.File{ .handle = in }; + const conn = try server.accept(); + const file = conn.stream; var test_buffer: [64]u8 = undefined; - _ = try file.readAll(test_buffer[0..12]); + var size = 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], + test_buffer[0..size], ); - _ = try file.readAll(test_buffer[0..12]); + size = 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))), - test_buffer[0..12], + test_buffer[0..size], ); - _ = try file.readAll(test_buffer[0..12]); + size = 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) | 1)) ++ std.mem.toBytes(@as(u32, 42))), - test_buffer[0..12], + test_buffer[0..size], ); - _ = try file.readAll(test_buffer[0..20]); + size = try file.readAll(test_buffer[0..20]); try std.testing.expectEqualSlices( u8, &(std.mem.toBytes(@as(u32, 42)) ++ std.mem.toBytes(@as(u32, (20 << 16) | 2)) ++ std.mem.toBytes(@as(u32, 5))) ++ "abcd\x00\x00\x00\x00", - test_buffer[0..20], + test_buffer[0..size], ); - _ = try file.readAll(test_buffer[0..24]); + size = try file.readAll(test_buffer[0..24]); try std.testing.expectEqualSlices( u8, &(std.mem.toBytes(@as(u32, 42)) ++ std.mem.toBytes(@as(u32, (24 << 16) | 3)) ++ std.mem.toBytes(@as(u32, 5))) ++ std.mem.toBytes([_]u16{ 1, 32, 4, 5, 5, 0 }), - test_buffer[0..24], + test_buffer[0..size], ); + + size = try file.readAll(test_buffer[0..8]); + try std.testing.expectEqualSlices( + u8, + &(std.mem.toBytes(@as(u32, 42)) ++ + std.mem.toBytes(@as(u32, (8 << 16) | 4))), + test_buffer[0..size], + ); + + size = try file.readAll(test_buffer[0..]); + try std.testing.expectEqual(0, size); } diff --git a/src/wl/output/root.zig b/src/wl/output/root.zig index ce2169f..f4ca36d 100644 --- a/src/wl/output/root.zig +++ b/src/wl/output/root.zig @@ -38,7 +38,7 @@ handle: wayland.Object.Ref, pub fn init( self: *Self, - ctx: *wayland.Context, + ctx: *const wayland.Context, ) !void { self.* = .{ .handle = try ctx.display.registry.add_object( @@ -58,7 +58,7 @@ pub const handler: wl.Registry.GlobalHandler = .{ .handler = register, }; -fn register(ctx: *wayland.Context) ?wayland.Object.Ref { +fn register(ctx: *const wayland.Context) ?wayland.Object.Ref { const output = ctx.allocator.create(Self) catch return null; output.init(ctx) catch return null; @@ -68,7 +68,7 @@ fn register(ctx: *wayland.Context) ?wayland.Object.Ref { fn geometry( self: *Self, - ctx: *wayland.Context, + ctx: *const wayland.Context, x: u32, y: u32, physical_width: u32, @@ -93,7 +93,7 @@ fn geometry( fn mode( self: *Self, - ctx: *wayland.Context, + ctx: *const wayland.Context, flags: Mode.Kind, width: u32, height: u32, @@ -108,7 +108,7 @@ fn mode( }; } -fn done(self: *Self, ctx: *wayland.Context) void { +fn done(self: *Self, ctx: *const wayland.Context) void { if (self.info) |info| { ctx.allocator.free(info.name); ctx.allocator.free(info.description); @@ -117,17 +117,17 @@ fn done(self: *Self, ctx: *wayland.Context) void { self.info = self.staging; } -fn scale(self: *Self, ctx: *wayland.Context, factor: u32) void { +fn scale(self: *Self, ctx: *const wayland.Context, factor: u32) void { _ = ctx; self.staging.scale = factor; } -fn name(self: *Self, ctx: *wayland.Context, n: []const u8) !void { +fn name(self: *Self, ctx: *const wayland.Context, n: []const u8) !void { self.staging.name = try ctx.allocator.alloc(u8, n.len); @memcpy(@constCast(self.staging.name), n); } -fn description(self: *Self, ctx: *wayland.Context, d: []const u8) !void { +fn description(self: *Self, ctx: *const wayland.Context, d: []const u8) !void { self.staging.description = try ctx.allocator.alloc(u8, d.len); @memcpy(@constCast(self.staging.description), d); } diff --git a/src/wl/registry.zig b/src/wl/registry.zig index 6c8ebdc..0939d17 100644 --- a/src/wl/registry.zig +++ b/src/wl/registry.zig @@ -18,7 +18,7 @@ pub const Request = union(enum) { pub const GlobalHandler = struct { interface: []const u8, version: u32, - handler: *const fn (ctx: *wayland.Context) ?wayland.Object.Ref, + handler: *const fn (ctx: *const wayland.Context) ?wayland.Object.Ref, }; objects: std.ArrayListUnmanaged(?wayland.Object) = .empty, @@ -52,7 +52,7 @@ pub fn add_object( self: *Self, allocator: std.mem.Allocator, object: wayland.Object, -) !usize { +) !wayland.Object.Ref { for (self.objects.items[1..], 1..) |obj, index| { if (obj == null) { self.objects.items[index] = object; @@ -83,7 +83,7 @@ pub fn get(self: *Self, handle: usize) ?*wayland.Object { fn global( self: *Self, - ctx: *wayland.Context, + ctx: *const wayland.Context, name: u32, interface: []const u8, version: u32, @@ -105,7 +105,7 @@ fn global( fn global_remove( self: *Self, - ctx: *wayland.Context, + ctx: *const wayland.Context, name: u32, ) void { _ = self; diff --git a/src/wl/shm/anonymous-file.zig b/src/wl/shm/anonymous-file.zig new file mode 100644 index 0000000..f73fbc9 --- /dev/null +++ b/src/wl/shm/anonymous-file.zig @@ -0,0 +1,53 @@ +const std = @import("std"); + +const Self = @This(); + +size: usize = 0, +name: [24]u8 = undefined, +fd: std.posix.fd_t = undefined, + +pub fn init_random() !Self { + var buf: [8]u8 = undefined; + try std.posix.getrandom(&buf); + + var self: Self = .{}; + + const name = std.fmt.bufPrint(&self.name, "/wl.shm.{x}{x}{x}{x}{x}{x}{x}{x}", .{ + buf[0], + buf[1], + buf[2], + buf[3], + buf[4], + buf[5], + buf[6], + buf[7], + }) catch unreachable; + + self.fd = try std.posix.memfd_create(name, 0); + + return self; +} + +pub fn truncate(self: *Self, size: usize) !void { + try std.posix.ftruncate(self.fd, size); + self.size = size; +} + +pub fn mmap(self: *Self) ![]u8 { + return std.posix.mmap( + null, + self.size, + std.os.linux.PROT.READ | std.os.linux.PROT.WRITE, + .{ + .TYPE = .SHARED, + .ANONYMOUS = true, + }, + self.fd, + 0, + ); +} + +pub fn close(self: *Self) void { + std.posix.close(self.fd); + self.* = undefined; +} diff --git a/src/wl/shm/pool.zig b/src/wl/shm/pool.zig index dc30d1b..1f42a17 100644 --- a/src/wl/shm/pool.zig +++ b/src/wl/shm/pool.zig @@ -1,5 +1,10 @@ +const std = @import("std"); const wayland = @import("../../root.zig"); -const Format = @import("root.zig").Format; +const wl = wayland.wl; +const Format = wl.Shm.Format; +const AnonymousFile = wl.Shm.AnonymousFile; + +const Self = @This(); pub const Events = wayland.EventSet(@This(), .{}); pub const Requests = union(enum) { @@ -7,3 +12,33 @@ pub const Requests = union(enum) { destroy: struct {}, resize: struct { u32 }, }; + +handle: wayland.Object.Ref, +file: AnonymousFile, +buffer: []u8, + +pub fn init( + self: *Self, + ctx: *const wayland.Context, + size: usize, +) !void { + var file = try AnonymousFile.init_random(); + errdefer file.close(); + try file.truncate(size); + + self.* = .{ + .handle = try ctx.display.registry.add_object( + ctx.allocator, + wayland.Object.from_self(self), + ), + .file = file, + .buffer = try file.mmap(), + }; +} + +pub fn deinit(self: *Self, ctx: *const wayland.Context) void { + self.file.close(); + std.posix.munmap(@alignCast(self.buffer)); + ctx.display.registry.disable_object(self.handle); + self.* = undefined; +} diff --git a/src/wl/shm/root.zig b/src/wl/shm/root.zig index 2d24aca..fd96727 100644 --- a/src/wl/shm/root.zig +++ b/src/wl/shm/root.zig @@ -4,12 +4,13 @@ const wl = wayland.wl; pub const Pool = @import("pool.zig"); pub const Format = @import("format.zig").Format; +pub const AnonymousFile = @import("anonymous-file.zig"); const Self = @This(); pub const Events = wayland.EventSet(Self, .{ announce_format }); -pub const Requests = union(enum) { - create_pool: struct { u32, wayland.types.Fd, u32 }, +pub const Request = union(enum) { + create_pool: struct { wayland.Object.Ref, wayland.types.Fd, u32 }, }; pub var instances: std.ArrayListUnmanaged(*Self) = .empty; @@ -19,7 +20,7 @@ formats: std.EnumSet(Format) = .initEmpty(), pub fn init( self: *Self, - ctx: *wayland.Context, + ctx: *const wayland.Context, ) !void { self.* = .{ .handle = try ctx.display.registry.add_object( @@ -29,7 +30,7 @@ pub fn init( }; } -fn announce_format(self: * Self, ctx: *wayland.Context, fmt: Format) void { +fn announce_format(self: * Self, ctx: *const wayland.Context, fmt: Format) void { _ = ctx; self.formats.insert(fmt); } @@ -40,7 +41,7 @@ pub const handler: wl.Registry.GlobalHandler = .{ .handler = register, }; -fn register(ctx: *wayland.Context) ?wayland.Object.Ref { +fn register(ctx: *const wayland.Context) ?wayland.Object.Ref { const shm = ctx.allocator.create(Self) catch return null; shm.init(ctx) catch return null; @@ -48,6 +49,20 @@ fn register(ctx: *wayland.Context) ?wayland.Object.Ref { return shm.handle; } +pub fn create_pool(self: *Self, ctx: *const wayland.Context, size: usize) !*Pool { + const pool = try ctx.allocator.create(Pool); + errdefer ctx.allocator.destroy(pool); + try pool.init(ctx, size); + + try ctx.display.request(self, .{ .create_pool = .{ + pool.handle, + .{ .fd = pool.file.fd }, + @truncate(size) + } }); + + return pool; +} + pub fn format( self: *const Self, comptime fmt: []const u8, -- cgit v1.2.3-70-g09d2