diff options
Diffstat (limited to 'src/wl')
| -rw-r--r-- | src/wl/callback.zig | 6 | ||||
| -rw-r--r-- | src/wl/compositor.zig | 4 | ||||
| -rw-r--r-- | src/wl/display.zig | 87 | ||||
| -rw-r--r-- | src/wl/output/root.zig | 16 | ||||
| -rw-r--r-- | src/wl/registry.zig | 8 | ||||
| -rw-r--r-- | src/wl/shm/anonymous-file.zig | 53 | ||||
| -rw-r--r-- | src/wl/shm/pool.zig | 37 | ||||
| -rw-r--r-- | src/wl/shm/root.zig | 25 |
8 files changed, 186 insertions, 50 deletions
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, |