Get client rendering a window with low-level code
parent
00dd8167ae
commit
8b50eeb7eb
|
@ -48,11 +48,8 @@ pub fn main() !void {
|
||||||
|
|
||||||
if (header.object_id == registry_id) {
|
if (header.object_id == registry_id) {
|
||||||
const event = try wayland.deserialize(wayland.core.Registry.Event, header, message_buffer.items);
|
const event = try wayland.deserialize(wayland.core.Registry.Event, header, message_buffer.items);
|
||||||
std.debug.print("{} {s} ", .{ header.object_id, @tagName(event) });
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
.global => |global| {
|
.global => |global| {
|
||||||
std.debug.print("{} \"{}\" v{}\n", .{ global.name, std.zig.fmtEscapes(global.interface), global.version });
|
|
||||||
|
|
||||||
var buffer: [20]u32 = undefined;
|
var buffer: [20]u32 = undefined;
|
||||||
if (std.mem.eql(u8, global.interface, "wl_shm")) {
|
if (std.mem.eql(u8, global.interface, "wl_shm")) {
|
||||||
const message = try wayland.serialize(
|
const message = try wayland.serialize(
|
||||||
|
@ -108,17 +105,306 @@ pub fn main() !void {
|
||||||
try socket.writeAll(std.mem.sliceAsBytes(message));
|
try socket.writeAll(std.mem.sliceAsBytes(message));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.global_remove => std.debug.print("{}\n", .{std.zig.fmtEscapes(std.mem.sliceAsBytes(message_buffer.items))}),
|
.global_remove => {},
|
||||||
}
|
}
|
||||||
} else if (header.object_id == registry_done_id) {
|
} else if (header.object_id == registry_done_id) {
|
||||||
std.debug.print("<-", .{});
|
|
||||||
for (message_buffer.items) |word| {
|
|
||||||
std.debug.print(" {}", .{std.fmt.fmtSliceHexLower(std.mem.asBytes(&word))});
|
|
||||||
}
|
|
||||||
std.debug.print(" (sync event id)\n", .{});
|
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
std.debug.print("{} {x} \"{}\"\n", .{ header.object_id, header.size_and_opcode.opcode, std.zig.fmtEscapes(std.mem.sliceAsBytes(message_buffer.items)) });
|
std.debug.print("{} {x} \"{}\"\n", .{ header.object_id, header.size_and_opcode.opcode, std.zig.fmtEscapes(std.mem.sliceAsBytes(message_buffer.items)) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const surface_id = 8;
|
||||||
|
{
|
||||||
|
var buffer: [10]u32 = undefined;
|
||||||
|
const message = try wayland.serialize(
|
||||||
|
wayland.core.Compositor.Request,
|
||||||
|
&buffer,
|
||||||
|
compositor_id,
|
||||||
|
.{ .create_surface = .{
|
||||||
|
.new_id = surface_id,
|
||||||
|
} },
|
||||||
|
);
|
||||||
|
try socket.writeAll(std.mem.sliceAsBytes(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
const xdg_surface_id = 9;
|
||||||
|
{
|
||||||
|
var buffer: [10]u32 = undefined;
|
||||||
|
const message = try wayland.serialize(
|
||||||
|
wayland.xdg.WmBase.Request,
|
||||||
|
&buffer,
|
||||||
|
xdg_wm_base_id,
|
||||||
|
.{ .get_xdg_surface = .{
|
||||||
|
.id = xdg_surface_id,
|
||||||
|
.surface = surface_id,
|
||||||
|
} },
|
||||||
|
);
|
||||||
|
try socket.writeAll(std.mem.sliceAsBytes(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
const xdg_toplevel_id = 10;
|
||||||
|
{
|
||||||
|
var buffer: [10]u32 = undefined;
|
||||||
|
const message = try wayland.serialize(
|
||||||
|
wayland.xdg.Surface.Request,
|
||||||
|
&buffer,
|
||||||
|
xdg_surface_id,
|
||||||
|
.{ .get_toplevel = .{
|
||||||
|
.id = xdg_toplevel_id,
|
||||||
|
} },
|
||||||
|
);
|
||||||
|
try socket.writeAll(std.mem.sliceAsBytes(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var buffer: [10]u32 = undefined;
|
||||||
|
const message = try wayland.serialize(
|
||||||
|
wayland.core.Surface.Request,
|
||||||
|
&buffer,
|
||||||
|
surface_id,
|
||||||
|
wayland.core.Surface.Request.commit,
|
||||||
|
);
|
||||||
|
try socket.writeAll(std.mem.sliceAsBytes(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var buffer: [5]u32 = undefined;
|
||||||
|
const message = try wayland.serialize(wayland.core.Display.Request, &buffer, 1, .{ .sync = .{ .callback = registry_done_id } });
|
||||||
|
try socket.writeAll(std.mem.sliceAsBytes(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
var done = false;
|
||||||
|
var surface_configured = false;
|
||||||
|
while (!done or !surface_configured) {
|
||||||
|
var header: wayland.Header = undefined;
|
||||||
|
const header_bytes_read = try socket.readAll(std.mem.asBytes(&header));
|
||||||
|
if (header_bytes_read < @sizeOf(wayland.Header)) {
|
||||||
|
return error.SocketClosed;
|
||||||
|
}
|
||||||
|
|
||||||
|
try message_buffer.resize((header.size_and_opcode.size - @sizeOf(wayland.Header)) / @sizeOf(u32));
|
||||||
|
const bytes_read = try socket.readAll(std.mem.sliceAsBytes(message_buffer.items));
|
||||||
|
message_buffer.shrinkRetainingCapacity(bytes_read / @sizeOf(u32));
|
||||||
|
|
||||||
|
if (header.object_id == xdg_surface_id) {
|
||||||
|
const event = try wayland.deserialize(wayland.xdg.Surface.Event, header, message_buffer.items);
|
||||||
|
switch (event) {
|
||||||
|
.configure => |conf| {
|
||||||
|
var buffer: [10]u32 = undefined;
|
||||||
|
const message = try wayland.serialize(
|
||||||
|
wayland.xdg.Surface.Request,
|
||||||
|
&buffer,
|
||||||
|
xdg_surface_id,
|
||||||
|
.{ .ack_configure = .{
|
||||||
|
.serial = conf.serial,
|
||||||
|
} },
|
||||||
|
);
|
||||||
|
try socket.writeAll(std.mem.sliceAsBytes(message));
|
||||||
|
surface_configured = true;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else if (header.object_id == xdg_toplevel_id) {
|
||||||
|
// const event = try wayland.deserialize(wayland.xdg.Toplevel.Event, header, message_buffer.items);
|
||||||
|
// std.debug.print("<- {}\n", .{event});
|
||||||
|
std.debug.print("<- xdg_toplevel@{} {s} {}\n", .{ header.object_id, @tagName(@as(std.meta.Tag(wayland.xdg.Toplevel.Event), @enumFromInt(header.size_and_opcode.opcode))), std.zig.fmtEscapes(std.mem.sliceAsBytes(message_buffer.items)) });
|
||||||
|
} else if (header.object_id == registry_done_id) {
|
||||||
|
done = true;
|
||||||
|
} else if (header.object_id == 1) {
|
||||||
|
const event = try wayland.deserialize(wayland.core.Display.Event, header, message_buffer.items);
|
||||||
|
switch (event) {
|
||||||
|
.@"error" => |err| std.debug.print("<- error({}): {} {s}\n", .{ err.object_id, err.code, err.message }),
|
||||||
|
.delete_id => |id| std.debug.print("<- delete_id {}\n", .{id.name}),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std.debug.print("{} {x} \"{}\"\n", .{ header.object_id, header.size_and_opcode.opcode, std.zig.fmtEscapes(std.mem.sliceAsBytes(message_buffer.items)) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocate a shared memory file for display purposes
|
||||||
|
const Pixel = [4]u8;
|
||||||
|
const framebuffer_size = [2]usize{ 128, 128 };
|
||||||
|
const framebuffer_file_len = framebuffer_size[0] * framebuffer_size[1] * @sizeOf(Pixel);
|
||||||
|
|
||||||
|
const framebuffer_fd = try std.os.memfd_create("my-wayland-framebuffer", 0);
|
||||||
|
try std.os.ftruncate(framebuffer_fd, framebuffer_file_len);
|
||||||
|
const framebuffer_bytes = try std.os.mmap(null, framebuffer_file_len, std.os.PROT.READ | std.os.PROT.WRITE, std.os.MAP.SHARED, framebuffer_fd, 0);
|
||||||
|
const framebuffer = @as([*][4]u8, @ptrCast(framebuffer_bytes.ptr))[0 .. framebuffer_bytes.len / @sizeOf([4]u8)];
|
||||||
|
|
||||||
|
// put some interesting colors into the framebuffer
|
||||||
|
for (framebuffer, 0..) |*pixel, i| {
|
||||||
|
pixel.* = .{
|
||||||
|
@truncate(i),
|
||||||
|
@truncate(i + 64),
|
||||||
|
@truncate(i + 128),
|
||||||
|
0xFF,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const wl_shm_pool_id = 11;
|
||||||
|
{
|
||||||
|
var buffer: [10]u32 = undefined;
|
||||||
|
const message = try wayland.serialize(
|
||||||
|
wayland.core.Shm.Request,
|
||||||
|
&buffer,
|
||||||
|
shm_id,
|
||||||
|
.{ .create_pool = .{
|
||||||
|
.new_id = wl_shm_pool_id,
|
||||||
|
.size = framebuffer_file_len,
|
||||||
|
} },
|
||||||
|
);
|
||||||
|
// Send the file descriptor through a control message
|
||||||
|
const message_bytes = std.mem.sliceAsBytes(message);
|
||||||
|
const msg_iov = [_]std.os.iovec_const{
|
||||||
|
.{
|
||||||
|
.iov_base = message_bytes.ptr,
|
||||||
|
.iov_len = message_bytes.len,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const control_message = cmsg(std.os.fd_t){
|
||||||
|
.level = std.os.SOL.SOCKET,
|
||||||
|
.type = 0x01, // value of SCM_RIGHTS
|
||||||
|
.data = framebuffer_fd,
|
||||||
|
};
|
||||||
|
const socket_message = std.os.msghdr_const{
|
||||||
|
.name = null,
|
||||||
|
.namelen = 0,
|
||||||
|
.iov = &msg_iov,
|
||||||
|
.iovlen = msg_iov.len,
|
||||||
|
// .control = null,
|
||||||
|
// .controllen = 0,
|
||||||
|
.control = &control_message,
|
||||||
|
.controllen = @sizeOf(cmsg(std.os.fd_t)),
|
||||||
|
.flags = 0,
|
||||||
|
};
|
||||||
|
_ = try std.os.sendmsg(socket.handle, &socket_message, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const wl_buffer_id = 12;
|
||||||
|
{
|
||||||
|
var buffer: [10]u32 = undefined;
|
||||||
|
const message = try wayland.serialize(
|
||||||
|
wayland.core.ShmPool.Request,
|
||||||
|
&buffer,
|
||||||
|
wl_shm_pool_id,
|
||||||
|
.{ .create_buffer = .{
|
||||||
|
.new_id = wl_buffer_id,
|
||||||
|
.offset = 0,
|
||||||
|
.width = framebuffer_size[0],
|
||||||
|
.height = framebuffer_size[1],
|
||||||
|
.stride = framebuffer_size[0] * @sizeOf([4]u8),
|
||||||
|
.format = @intFromEnum(wayland.core.Shm.Format.argb8888),
|
||||||
|
} },
|
||||||
|
);
|
||||||
|
try socket.writeAll(std.mem.sliceAsBytes(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var buffer: [10]u32 = undefined;
|
||||||
|
const message = try wayland.serialize(
|
||||||
|
wayland.core.Surface.Request,
|
||||||
|
&buffer,
|
||||||
|
surface_id,
|
||||||
|
.{ .attach = .{
|
||||||
|
.buffer = wl_buffer_id,
|
||||||
|
.x = 0,
|
||||||
|
.y = 0,
|
||||||
|
} },
|
||||||
|
);
|
||||||
|
try socket.writeAll(std.mem.sliceAsBytes(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var buffer: [10]u32 = undefined;
|
||||||
|
const message = try wayland.serialize(
|
||||||
|
wayland.core.Surface.Request,
|
||||||
|
&buffer,
|
||||||
|
surface_id,
|
||||||
|
.{ .damage = .{
|
||||||
|
.x = 0,
|
||||||
|
.y = 0,
|
||||||
|
.width = std.math.maxInt(i32),
|
||||||
|
.height = std.math.maxInt(i32),
|
||||||
|
} },
|
||||||
|
);
|
||||||
|
try socket.writeAll(std.mem.sliceAsBytes(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var buffer: [10]u32 = undefined;
|
||||||
|
const message = try wayland.serialize(
|
||||||
|
wayland.core.Surface.Request,
|
||||||
|
&buffer,
|
||||||
|
surface_id,
|
||||||
|
wayland.core.Surface.Request.commit,
|
||||||
|
);
|
||||||
|
try socket.writeAll(std.mem.sliceAsBytes(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
var running = true;
|
||||||
|
while (running) {
|
||||||
|
var header: wayland.Header = undefined;
|
||||||
|
const header_bytes_read = try socket.readAll(std.mem.asBytes(&header));
|
||||||
|
if (header_bytes_read < @sizeOf(wayland.Header)) {
|
||||||
|
return error.SocketClosed;
|
||||||
|
}
|
||||||
|
|
||||||
|
try message_buffer.resize((header.size_and_opcode.size - @sizeOf(wayland.Header)) / @sizeOf(u32));
|
||||||
|
const bytes_read = try socket.readAll(std.mem.sliceAsBytes(message_buffer.items));
|
||||||
|
message_buffer.shrinkRetainingCapacity(bytes_read / @sizeOf(u32));
|
||||||
|
|
||||||
|
if (header.object_id == xdg_surface_id) {
|
||||||
|
const event = try wayland.deserialize(wayland.xdg.Surface.Event, header, message_buffer.items);
|
||||||
|
switch (event) {
|
||||||
|
.configure => |conf| {
|
||||||
|
var buffer: [10]u32 = undefined;
|
||||||
|
const message = try wayland.serialize(
|
||||||
|
wayland.xdg.Surface.Request,
|
||||||
|
&buffer,
|
||||||
|
xdg_surface_id,
|
||||||
|
.{ .ack_configure = .{
|
||||||
|
.serial = conf.serial,
|
||||||
|
} },
|
||||||
|
);
|
||||||
|
try socket.writeAll(std.mem.sliceAsBytes(message));
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else if (header.object_id == xdg_toplevel_id) {
|
||||||
|
// const event = try wayland.deserialize(wayland.xdg.Toplevel.Event, header, message_buffer.items);
|
||||||
|
// std.debug.print("<- {}\n", .{event});
|
||||||
|
switch (@as(std.meta.Tag(wayland.xdg.Toplevel.Event), @enumFromInt(header.size_and_opcode.opcode))) {
|
||||||
|
.configure => {
|
||||||
|
const width: i32 = @intCast(message_buffer.items[0]);
|
||||||
|
const height: i32 = @intCast(message_buffer.items[1]);
|
||||||
|
std.debug.print("<- xdg_toplevel@{} configure <{}, {}>\n", .{ header.object_id, width, height });
|
||||||
|
},
|
||||||
|
.close => running = false,
|
||||||
|
else => |tag| std.debug.print("<- xdg_toplevel@{} {s} {}\n", .{ header.object_id, @tagName(tag), std.zig.fmtEscapes(std.mem.sliceAsBytes(message_buffer.items)) }),
|
||||||
|
}
|
||||||
|
} else if (header.object_id == wl_buffer_id) {
|
||||||
|
const event = try wayland.deserialize(wayland.core.Buffer.Event, header, message_buffer.items);
|
||||||
|
std.debug.print("<- wl_buffer@{} {}\n", .{ header.object_id, event });
|
||||||
|
} else if (header.object_id == 1) {
|
||||||
|
const event = try wayland.deserialize(wayland.core.Display.Event, header, message_buffer.items);
|
||||||
|
switch (event) {
|
||||||
|
.@"error" => |err| std.debug.print("<- error({}): {} {s}\n", .{ err.object_id, err.code, err.message }),
|
||||||
|
.delete_id => {
|
||||||
|
// TODO: add id to list of free ids
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std.debug.print("{} {x} \"{}\"\n", .{ header.object_id, header.size_and_opcode.opcode, std.zig.fmtEscapes(std.mem.sliceAsBytes(message_buffer.items)) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cmsg(comptime T: type) type {
|
||||||
|
const padding_size = (@sizeOf(T) + @sizeOf(c_long) - 1) & ~(@as(usize, @sizeOf(c_long)) - 1);
|
||||||
|
return extern struct {
|
||||||
|
len: c_ulong = @sizeOf(@This()) - padding_size,
|
||||||
|
level: c_int,
|
||||||
|
type: c_int,
|
||||||
|
data: T,
|
||||||
|
_padding: [padding_size]u8 align(1) = [_]u8{0} ** padding_size,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
139
src/core.zig
139
src/core.zig
|
@ -83,3 +83,142 @@ pub const Registry = struct {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const Compositor = struct {
|
||||||
|
pub const Request = union(Request.Tag) {
|
||||||
|
create_surface: CreateSurface,
|
||||||
|
create_region: CreateRegion,
|
||||||
|
|
||||||
|
pub const Tag = enum(u16) {
|
||||||
|
create_surface,
|
||||||
|
create_region,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const CreateSurface = struct {
|
||||||
|
new_id: u32,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const CreateRegion = struct {
|
||||||
|
new_id: u32,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const ShmPool = struct {
|
||||||
|
pub const Request = union(Request.Tag) {
|
||||||
|
create_buffer: struct {
|
||||||
|
new_id: u32,
|
||||||
|
offset: i32,
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
stride: i32,
|
||||||
|
// Shm.Format
|
||||||
|
format: u32,
|
||||||
|
},
|
||||||
|
destroy: void,
|
||||||
|
resize: struct {
|
||||||
|
size: i32,
|
||||||
|
},
|
||||||
|
|
||||||
|
pub const Tag = enum(u16) {
|
||||||
|
create_buffer,
|
||||||
|
destroy,
|
||||||
|
resize,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Shm = struct {
|
||||||
|
pub const Request = union(Request.Tag) {
|
||||||
|
create_pool: CreatePool,
|
||||||
|
|
||||||
|
pub const Tag = enum(u16) {
|
||||||
|
create_pool,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const CreatePool = struct {
|
||||||
|
new_id: u32,
|
||||||
|
// file descriptors are sent through a control message
|
||||||
|
// fd: u32,
|
||||||
|
size: u32,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Event = union(Event.Tag) {
|
||||||
|
format: Format,
|
||||||
|
|
||||||
|
pub const Tag = enum(u16) {
|
||||||
|
@"error",
|
||||||
|
delete_id,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Format = enum(u32) {
|
||||||
|
argb8888,
|
||||||
|
xrgb8888,
|
||||||
|
_,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Surface = struct {
|
||||||
|
pub const Request = union(Request.Tag) {
|
||||||
|
destroy: void,
|
||||||
|
attach: struct {
|
||||||
|
buffer: u32,
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
},
|
||||||
|
damage: struct {
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
},
|
||||||
|
frame: struct {
|
||||||
|
/// id of a new callback object
|
||||||
|
callback: u32,
|
||||||
|
},
|
||||||
|
set_opaque_region: struct {
|
||||||
|
region: u32,
|
||||||
|
},
|
||||||
|
set_input_region: struct {
|
||||||
|
region: u32,
|
||||||
|
},
|
||||||
|
commit: void,
|
||||||
|
|
||||||
|
pub const Tag = enum(u16) {
|
||||||
|
destroy,
|
||||||
|
attach,
|
||||||
|
damage,
|
||||||
|
frame,
|
||||||
|
set_opaque_region,
|
||||||
|
set_input_region,
|
||||||
|
commit,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Event = union(Event.Tag) {
|
||||||
|
format: Format,
|
||||||
|
|
||||||
|
pub const Tag = enum(u16) {
|
||||||
|
@"error",
|
||||||
|
delete_id,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Format = enum(u32) {
|
||||||
|
argb8888,
|
||||||
|
xrgb8888,
|
||||||
|
_,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Buffer = struct {
|
||||||
|
pub const Request = union(enum) {
|
||||||
|
destroy: void,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Event = union(enum) {
|
||||||
|
release: void,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
53
src/main.zig
53
src/main.zig
|
@ -1,6 +1,7 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
pub const core = @import("./core.zig");
|
pub const core = @import("./core.zig");
|
||||||
|
pub const xdg = @import("./xdg.zig");
|
||||||
|
|
||||||
pub fn getDisplayPath(gpa: std.mem.Allocator) ![]u8 {
|
pub fn getDisplayPath(gpa: std.mem.Allocator) ![]u8 {
|
||||||
const xdg_runtime_dir_path = try std.process.getEnvVarOwned(gpa, "XDG_RUNTIME_DIR");
|
const xdg_runtime_dir_path = try std.process.getEnvVarOwned(gpa, "XDG_RUNTIME_DIR");
|
||||||
|
@ -54,22 +55,55 @@ test "header from []u32" {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn readUInt(buffer: []const u32, parent_pos: *usize) !u32 {
|
||||||
|
var pos = parent_pos.*;
|
||||||
|
if (pos >= buffer.len) return error.EndOfStream;
|
||||||
|
|
||||||
|
const uint: u32 = @bitCast(buffer[pos]);
|
||||||
|
pos += 1;
|
||||||
|
|
||||||
|
parent_pos.* = pos;
|
||||||
|
return uint;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn readInt(buffer: []const u32, parent_pos: *usize) !i32 {
|
||||||
|
var pos = parent_pos.*;
|
||||||
|
if (pos >= buffer.len) return error.EndOfStream;
|
||||||
|
|
||||||
|
const int: i32 = @bitCast(buffer[pos]);
|
||||||
|
pos += 1;
|
||||||
|
|
||||||
|
parent_pos.* = pos;
|
||||||
|
return int;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn readString(buffer: []const u32, parent_pos: *usize) ![:0]const u8 {
|
||||||
|
var pos = parent_pos.*;
|
||||||
|
|
||||||
|
const len = try readUInt(buffer, &pos);
|
||||||
|
const wordlen = std.mem.alignForward(usize, len, @sizeOf(u32)) / @sizeOf(u32);
|
||||||
|
|
||||||
|
if (pos + wordlen > buffer.len) return error.EndOfStream;
|
||||||
|
const string = std.mem.sliceAsBytes(buffer[pos..])[0 .. len - 1 :0];
|
||||||
|
pos += std.mem.alignForward(usize, len, @sizeOf(u32)) / @sizeOf(u32);
|
||||||
|
|
||||||
|
parent_pos.* = pos;
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn deserializeArguments(comptime Signature: type, buffer: []const u32) !Signature {
|
pub fn deserializeArguments(comptime Signature: type, buffer: []const u32) !Signature {
|
||||||
|
if (Signature == void) return {};
|
||||||
var result: Signature = undefined;
|
var result: Signature = undefined;
|
||||||
var pos: usize = 0;
|
var pos: usize = 0;
|
||||||
inline for (std.meta.fields(Signature)) |field| {
|
inline for (std.meta.fields(Signature)) |field| {
|
||||||
switch (@typeInfo(field.type)) {
|
switch (@typeInfo(field.type)) {
|
||||||
.Int => {
|
.Int => |int_info| switch (int_info.signedness) {
|
||||||
@field(result, field.name) = @bitCast(buffer[pos]);
|
.signed => @field(result, field.name) = try readInt(buffer, &pos),
|
||||||
pos += 1;
|
.unsigned => @field(result, field.name) = try readUInt(buffer, &pos),
|
||||||
},
|
},
|
||||||
.Pointer => |ptr| switch (ptr.size) {
|
.Pointer => |ptr| switch (ptr.size) {
|
||||||
.Slice => {
|
.Slice => {
|
||||||
const len = buffer[pos];
|
@field(result, field.name) = try readString(buffer, &pos);
|
||||||
pos += 1;
|
|
||||||
const byte_pos = pos * @sizeOf(u32);
|
|
||||||
@field(result, field.name) = std.mem.sliceAsBytes(buffer)[byte_pos..][0 .. len - 1 :0];
|
|
||||||
pos += std.mem.alignForward(usize, len, @sizeOf(u32)) / @sizeOf(u32);
|
|
||||||
},
|
},
|
||||||
else => @compileError("Unsupported type " ++ @typeName(field.type)),
|
else => @compileError("Unsupported type " ++ @typeName(field.type)),
|
||||||
},
|
},
|
||||||
|
@ -114,12 +148,13 @@ pub fn calculateSerializedWordLen(comptime Signature: type, message: Signature)
|
||||||
|
|
||||||
/// Message must live until the iovec array is written.
|
/// Message must live until the iovec array is written.
|
||||||
pub fn serializeArguments(comptime Signature: type, buffer: []u32, message: Signature) ![]u32 {
|
pub fn serializeArguments(comptime Signature: type, buffer: []u32, message: Signature) ![]u32 {
|
||||||
|
if (Signature == void) return buffer[0..0];
|
||||||
var pos: usize = 0;
|
var pos: usize = 0;
|
||||||
inline for (std.meta.fields(Signature)) |field| {
|
inline for (std.meta.fields(Signature)) |field| {
|
||||||
switch (@typeInfo(field.type)) {
|
switch (@typeInfo(field.type)) {
|
||||||
.Int => {
|
.Int => {
|
||||||
if (pos >= buffer.len) return error.OutOfMemory;
|
if (pos >= buffer.len) return error.OutOfMemory;
|
||||||
buffer[pos] = @field(message, field.name);
|
buffer[pos] = @bitCast(@field(message, field.name));
|
||||||
pos += 1;
|
pos += 1;
|
||||||
},
|
},
|
||||||
.Pointer => |ptr| switch (ptr.size) {
|
.Pointer => |ptr| switch (ptr.size) {
|
||||||
|
|
|
@ -0,0 +1,168 @@
|
||||||
|
pub const WmBase = struct {
|
||||||
|
pub const Request = union(Request.Tag) {
|
||||||
|
destroy: void,
|
||||||
|
create_positioner: struct {
|
||||||
|
id: u32,
|
||||||
|
},
|
||||||
|
get_xdg_surface: struct {
|
||||||
|
id: u32,
|
||||||
|
surface: u32,
|
||||||
|
},
|
||||||
|
pong: struct {
|
||||||
|
serial: u32,
|
||||||
|
},
|
||||||
|
|
||||||
|
pub const Tag = enum(u16) {
|
||||||
|
destroy,
|
||||||
|
create_positioner,
|
||||||
|
get_xdg_surface,
|
||||||
|
pong,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Event = union(Event.Tag) {
|
||||||
|
ping: struct { serial: u32 },
|
||||||
|
|
||||||
|
pub const Tag = enum(u16) {
|
||||||
|
ping,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Error = enum(u32) {
|
||||||
|
role,
|
||||||
|
defunct_surfaces,
|
||||||
|
not_the_topmost_popup,
|
||||||
|
invalid_popup_parent,
|
||||||
|
invalid_surface_state,
|
||||||
|
invalid_positioner,
|
||||||
|
unresponsive,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Surface = struct {
|
||||||
|
pub const Request = union(enum) {
|
||||||
|
destroy: void,
|
||||||
|
get_toplevel: struct {
|
||||||
|
id: u32,
|
||||||
|
},
|
||||||
|
get_popup: struct {
|
||||||
|
id: u32,
|
||||||
|
/// Allows null
|
||||||
|
parent: u32,
|
||||||
|
positioner: u32,
|
||||||
|
},
|
||||||
|
set_window_geometry: struct {
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
},
|
||||||
|
ack_configure: struct {
|
||||||
|
serial: u32,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Event = union(enum) {
|
||||||
|
configure: struct { serial: u32 },
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Error = enum(u32) {
|
||||||
|
not_constructed = 1,
|
||||||
|
already_constructed,
|
||||||
|
unconfigured_buffer,
|
||||||
|
invalid_serial,
|
||||||
|
invalid_size,
|
||||||
|
defunct_role_object,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Toplevel = struct {
|
||||||
|
pub const Request = union(enum) {
|
||||||
|
destroy: void,
|
||||||
|
set_parent: struct {
|
||||||
|
/// Allows null
|
||||||
|
parent: u32,
|
||||||
|
},
|
||||||
|
set_title: struct {
|
||||||
|
title: []const u8,
|
||||||
|
},
|
||||||
|
set_app_id: struct {
|
||||||
|
app_id: []const u8,
|
||||||
|
},
|
||||||
|
show_window_menu: struct {
|
||||||
|
seat: u32,
|
||||||
|
serial: u32,
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
},
|
||||||
|
move: struct {
|
||||||
|
seat: u32,
|
||||||
|
serial: u32,
|
||||||
|
},
|
||||||
|
resize: struct {
|
||||||
|
seat: u32,
|
||||||
|
serial: u32,
|
||||||
|
edges: Toplevel.ResizeEdge,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Event = union(enum) {
|
||||||
|
configure: struct {
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
states: []Toplevel.State,
|
||||||
|
},
|
||||||
|
close: void,
|
||||||
|
configure_bounds: struct {
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
},
|
||||||
|
wm_capabilities: struct {
|
||||||
|
capabilities: []Toplevel.WmCapabilities,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const ResizeEdge = enum(u32) {
|
||||||
|
none,
|
||||||
|
top,
|
||||||
|
bottom,
|
||||||
|
left,
|
||||||
|
top_left,
|
||||||
|
bottom_left,
|
||||||
|
right,
|
||||||
|
top_right,
|
||||||
|
bottom_right,
|
||||||
|
_,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const State = enum(u32) {
|
||||||
|
maximized,
|
||||||
|
fullscreen,
|
||||||
|
resizing,
|
||||||
|
activated,
|
||||||
|
tiled_left,
|
||||||
|
tiled_right,
|
||||||
|
tiled_top,
|
||||||
|
tiled_bottom,
|
||||||
|
suspended,
|
||||||
|
_,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const WmCapabilities = enum(u32) {
|
||||||
|
window_menu,
|
||||||
|
maximize,
|
||||||
|
fullscreen,
|
||||||
|
minimize,
|
||||||
|
_,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Error = enum(u32) {
|
||||||
|
not_constructed = 1,
|
||||||
|
already_constructed,
|
||||||
|
unconfigured_buffer,
|
||||||
|
invalid_serial,
|
||||||
|
invalid_size,
|
||||||
|
defunct_role_object,
|
||||||
|
_,
|
||||||
|
};
|
||||||
|
};
|
Loading…
Reference in New Issue