feat: reduce repetition when calling wayland api
parent
18a8befacd
commit
adadca6827
154
src/core.zig
154
src/core.zig
|
@ -1,4 +1,5 @@
|
||||||
const types = @import("types.zig");
|
const types = @import("types.zig");
|
||||||
|
const Conn = @import("root.zig").Conn;
|
||||||
|
|
||||||
pub const Display = struct {
|
pub const Display = struct {
|
||||||
pub const Request = union(enum) {
|
pub const Request = union(enum) {
|
||||||
|
@ -29,9 +30,44 @@ pub const Display = struct {
|
||||||
no_memory,
|
no_memory,
|
||||||
implementation,
|
implementation,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
conn: *Conn,
|
||||||
|
id: u32,
|
||||||
|
|
||||||
|
pub fn init(conn: *Conn, id: u32) Compositor {
|
||||||
|
return .{ .conn = conn, .id = id };
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: take callback
|
||||||
|
pub fn sync(display: Display) !u32 {
|
||||||
|
const new_id = display.conn.id_pool.create();
|
||||||
|
try display.conn.send(
|
||||||
|
Request,
|
||||||
|
display.id,
|
||||||
|
.{ .sync = .{
|
||||||
|
.callback = new_id,
|
||||||
|
} },
|
||||||
|
);
|
||||||
|
return new_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_registry(display: Display) Registry {
|
||||||
|
const new_id = display.conn.id_pool.create();
|
||||||
|
try display.conn.send(
|
||||||
|
Request,
|
||||||
|
display.id,
|
||||||
|
.{ .get_registry = .{
|
||||||
|
.registery = new_id,
|
||||||
|
} },
|
||||||
|
);
|
||||||
|
return Registry.init(display.conn, new_id);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Registry = struct {
|
pub const Registry = struct {
|
||||||
|
pub const INTERFACE = "wl_registry";
|
||||||
|
pub const VERSION = 1;
|
||||||
|
|
||||||
pub const Event = union(enum) {
|
pub const Event = union(enum) {
|
||||||
global: struct {
|
global: struct {
|
||||||
name: u32,
|
name: u32,
|
||||||
|
@ -51,6 +87,13 @@ pub const Registry = struct {
|
||||||
new_id: u32,
|
new_id: u32,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
conn: *Conn,
|
||||||
|
id: u32,
|
||||||
|
|
||||||
|
pub fn init(conn: *Conn, id: u32) Registry {
|
||||||
|
return .{ .conn = conn, .id = id };
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Compositor = struct {
|
pub const Compositor = struct {
|
||||||
|
@ -65,6 +108,33 @@ pub const Compositor = struct {
|
||||||
new_id: u32,
|
new_id: u32,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
conn: *Conn,
|
||||||
|
id: u32,
|
||||||
|
|
||||||
|
pub fn init(conn: *Conn, id: u32) Compositor {
|
||||||
|
return .{ .conn = conn, .id = id };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_surface(compositor: *const Compositor) !Surface {
|
||||||
|
const new_id = compositor.conn.id_pool.create();
|
||||||
|
try compositor.conn.send(
|
||||||
|
Request,
|
||||||
|
compositor.id,
|
||||||
|
.{ .create_surface = .{ .new_id = new_id } },
|
||||||
|
);
|
||||||
|
return Surface.init(compositor.conn, new_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// pub fn create_region(compositor: *Compositor) Region {
|
||||||
|
// const new_id = compositor.conn.id_pool.create();
|
||||||
|
// try compositor.conn.send(
|
||||||
|
// Request,
|
||||||
|
// compositor.id,
|
||||||
|
// .{ .create_region = .{.new_id = new_id} },
|
||||||
|
// );
|
||||||
|
// return Region.init(compositor.conn, new_id);
|
||||||
|
// }
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const ShmPool = struct {
|
pub const ShmPool = struct {
|
||||||
|
@ -82,6 +152,30 @@ pub const ShmPool = struct {
|
||||||
size: i32,
|
size: i32,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
conn: *Conn,
|
||||||
|
id: u32,
|
||||||
|
|
||||||
|
pub fn init(conn: *Conn, id: u32) ShmPool {
|
||||||
|
return .{ .conn = conn, .id = id };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_buffer(shm_pool: ShmPool, offset: i32, width: i32, height: i32, stride: i32, format: Shm.Format) u32 {
|
||||||
|
const new_id = shm_pool.conn.id_pool.create();
|
||||||
|
try shm_pool.conn.send(
|
||||||
|
Request,
|
||||||
|
shm_pool.id,
|
||||||
|
.{ .create_buffer = .{
|
||||||
|
.new_id = new_id,
|
||||||
|
.offset = offset,
|
||||||
|
.width = width,
|
||||||
|
.height = height,
|
||||||
|
.stride = stride,
|
||||||
|
.format = format,
|
||||||
|
} },
|
||||||
|
);
|
||||||
|
return Surface.init(shm_pool.conn, new_id);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Shm = struct {
|
pub const Shm = struct {
|
||||||
|
@ -114,6 +208,23 @@ pub const Shm = struct {
|
||||||
xrgb8888,
|
xrgb8888,
|
||||||
_,
|
_,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
conn: *Conn,
|
||||||
|
id: u32,
|
||||||
|
|
||||||
|
pub fn init(conn: *Conn, id: u32) Shm {
|
||||||
|
return .{ .conn = conn, .id = id };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_pool(shm: *const Shm, pool_fd: u32, size: u32) ShmPool {
|
||||||
|
const new_id = shm.conn.id_pool.create();
|
||||||
|
try shm.conn.send(
|
||||||
|
Request,
|
||||||
|
shm.id,
|
||||||
|
.{ .create_pool = .{ .new_id = new_id, .fd = @enumFromInt(pool_fd), .size = size } },
|
||||||
|
);
|
||||||
|
return ShmPool.init(shm.conn, new_id);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Surface = struct {
|
pub const Surface = struct {
|
||||||
|
@ -165,6 +276,21 @@ pub const Surface = struct {
|
||||||
invalid_offset,
|
invalid_offset,
|
||||||
defunct_role_object,
|
defunct_role_object,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
conn: *Conn,
|
||||||
|
id: u32,
|
||||||
|
|
||||||
|
pub fn init(conn: *Conn, id: u32) Surface {
|
||||||
|
return .{ .conn = conn, .id = id };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn commit(surface: Surface) !void {
|
||||||
|
try surface.conn.send(
|
||||||
|
Request,
|
||||||
|
surface.id,
|
||||||
|
.commit,
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Buffer = struct {
|
pub const Buffer = struct {
|
||||||
|
@ -211,6 +337,13 @@ pub const Seat = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Error = enum(u32) {};
|
pub const Error = enum(u32) {};
|
||||||
|
|
||||||
|
conn: *Conn,
|
||||||
|
id: u32,
|
||||||
|
|
||||||
|
pub fn init(conn: *Conn, id: u32) Seat {
|
||||||
|
return .{ .conn = conn, .id = id };
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Pointer = struct {
|
pub const Pointer = struct {
|
||||||
|
@ -298,6 +431,13 @@ pub const Pointer = struct {
|
||||||
identical,
|
identical,
|
||||||
inverted,
|
inverted,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
conn: *Conn,
|
||||||
|
id: u32,
|
||||||
|
|
||||||
|
pub fn init(conn: *Conn, id: u32) Seat {
|
||||||
|
return .{ .conn = conn, .id = id };
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Keyboard = struct {
|
pub const Keyboard = struct {
|
||||||
|
@ -348,6 +488,13 @@ pub const Keyboard = struct {
|
||||||
released,
|
released,
|
||||||
pressed,
|
pressed,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
conn: *Conn,
|
||||||
|
id: u32,
|
||||||
|
|
||||||
|
pub fn init(conn: *Conn, id: u32) Seat {
|
||||||
|
return .{ .conn = conn, .id = id };
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Touch = struct {
|
pub const Touch = struct {
|
||||||
|
@ -387,4 +534,11 @@ pub const Touch = struct {
|
||||||
orientation: i32,
|
orientation: i32,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
conn: *Conn,
|
||||||
|
id: u32,
|
||||||
|
|
||||||
|
pub fn init(conn: *Conn, id: u32) Seat {
|
||||||
|
return .{ .conn = conn, .id = id };
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
571
src/main.zig
571
src/main.zig
|
@ -1,5 +1,28 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const wayland = @import("root.zig");
|
const wayland = @import("root.zig");
|
||||||
|
|
||||||
|
const Conn = wayland.Conn;
|
||||||
|
const Context = wayland.Context(&.{
|
||||||
|
// Core protocol
|
||||||
|
wayland.core.Registry,
|
||||||
|
wayland.core.Compositor,
|
||||||
|
// wayland.core.ShmPool,
|
||||||
|
wayland.core.Shm,
|
||||||
|
// wayland.core.Surface,
|
||||||
|
// wayland.core.Buffer,
|
||||||
|
wayland.core.Seat,
|
||||||
|
// wayland.core.Pointer,
|
||||||
|
// wayland.core.Keyboard,
|
||||||
|
// wayland.core.Touch,
|
||||||
|
|
||||||
|
// XDG Shell protocol
|
||||||
|
wayland.xdg.WmBase,
|
||||||
|
|
||||||
|
// XDG Decoration
|
||||||
|
// wayland.zxdg.DecorationManagerV1,
|
||||||
|
// wayland.zxdg.TopLevelDecorationV1,
|
||||||
|
});
|
||||||
|
|
||||||
const font8x8 = @cImport({
|
const font8x8 = @cImport({
|
||||||
@cInclude("font8x8.h");
|
@cInclude("font8x8.h");
|
||||||
});
|
});
|
||||||
|
@ -37,91 +60,25 @@ pub fn main() !void {
|
||||||
const display_path = try wayland.getDisplayPath(gpa);
|
const display_path = try wayland.getDisplayPath(gpa);
|
||||||
defer gpa.free(display_path);
|
defer gpa.free(display_path);
|
||||||
|
|
||||||
var conn = try wayland.Conn.init(gpa, display_path);
|
var conn = try Conn.init(gpa, display_path);
|
||||||
defer conn.deinit();
|
defer conn.deinit();
|
||||||
|
|
||||||
// Create an id pool to allocate ids for us
|
var ctx = try Context.init(&conn);
|
||||||
var id_pool = wayland.IdPool{};
|
|
||||||
|
|
||||||
const ids = try wayland.registerGlobals(gpa, &id_pool, conn.socket, &.{
|
const compositor = try ctx.getGlobal(wayland.core.Compositor);
|
||||||
wayland.core.Shm,
|
const surface = try compositor.create_surface();
|
||||||
wayland.core.Compositor,
|
|
||||||
wayland.xdg.WmBase,
|
|
||||||
wayland.core.Seat,
|
|
||||||
wayland.zxdg.DecorationManagerV1,
|
|
||||||
wayland.zwp.TextInputManagerV3,
|
|
||||||
});
|
|
||||||
|
|
||||||
const DISPLAY_ID = 1;
|
const xdg_wm_base = try ctx.getGlobal(wayland.xdg.WmBase);
|
||||||
const shm_id = ids[0] orelse return error.NeccessaryWaylandExtensionMissing;
|
const xdg_surface = try xdg_wm_base.get_xdg_surface(surface);
|
||||||
const compositor_id = ids[1] orelse return error.NeccessaryWaylandExtensionMissing;
|
const xdg_toplevel = try xdg_surface.get_toplevel();
|
||||||
const xdg_wm_base_id = ids[2] orelse return error.NeccessaryWaylandExtensionMissing;
|
|
||||||
const wl_seat_id = ids[3] orelse return error.NeccessaryWaylandExtensionMissing;
|
|
||||||
const zwp_text_input_manager_v3 = ids[5] orelse return error.NeccessaryWaylandExtensionMissing;
|
|
||||||
|
|
||||||
const surface_id = id_pool.create();
|
try surface.commit();
|
||||||
try conn.send(
|
|
||||||
wayland.core.Compositor.Request,
|
|
||||||
compositor_id,
|
|
||||||
.{ .create_surface = .{
|
|
||||||
.new_id = surface_id,
|
|
||||||
} },
|
|
||||||
);
|
|
||||||
|
|
||||||
const xdg_surface_id = id_pool.create();
|
const display = try ctx.getGlobal(wayland.core.Display);
|
||||||
try conn.send(
|
const registry_done = try display.sync();
|
||||||
wayland.xdg.WmBase.Request,
|
|
||||||
xdg_wm_base_id,
|
|
||||||
.{ .get_xdg_surface = .{
|
|
||||||
.id = xdg_surface_id,
|
|
||||||
.surface = surface_id,
|
|
||||||
} },
|
|
||||||
);
|
|
||||||
|
|
||||||
const xdg_toplevel_id = id_pool.create();
|
const shm = try ctx.getGlobal(wayland.core.Shm);
|
||||||
try conn.send(
|
const seat = try ctx.getGlobal(wayland.core.Seat);
|
||||||
wayland.xdg.Surface.Request,
|
|
||||||
xdg_surface_id,
|
|
||||||
.{ .get_toplevel = .{
|
|
||||||
.id = xdg_toplevel_id,
|
|
||||||
} },
|
|
||||||
);
|
|
||||||
|
|
||||||
const zwp_text_input_v3_id = id_pool.create();
|
|
||||||
try conn.send(
|
|
||||||
wayland.zwp.TextInputManagerV3.Request,
|
|
||||||
zwp_text_input_manager_v3,
|
|
||||||
.{ .get_text_input = .{
|
|
||||||
.id = zwp_text_input_v3_id,
|
|
||||||
.seat = wl_seat_id,
|
|
||||||
} },
|
|
||||||
);
|
|
||||||
|
|
||||||
var zxdg_toplevel_decoration_id_opt: ?u32 = null;
|
|
||||||
if (ids[4]) |zxdg_decoration_manager_id| {
|
|
||||||
zxdg_toplevel_decoration_id_opt = id_pool.create();
|
|
||||||
try conn.send(
|
|
||||||
wayland.zxdg.DecorationManagerV1.Request,
|
|
||||||
zxdg_decoration_manager_id,
|
|
||||||
.{ .get_toplevel_decoration = .{
|
|
||||||
.new_id = zxdg_toplevel_decoration_id_opt.?,
|
|
||||||
.toplevel = xdg_toplevel_id,
|
|
||||||
} },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
try conn.send(
|
|
||||||
wayland.core.Surface.Request,
|
|
||||||
surface_id,
|
|
||||||
wayland.core.Surface.Request.commit,
|
|
||||||
);
|
|
||||||
|
|
||||||
const registry_done_id = id_pool.create();
|
|
||||||
try conn.send(
|
|
||||||
wayland.core.Display.Request,
|
|
||||||
DISPLAY_ID,
|
|
||||||
.{ .sync = .{ .callback = registry_done_id } },
|
|
||||||
);
|
|
||||||
|
|
||||||
var done = false;
|
var done = false;
|
||||||
var surface_configured = false;
|
var surface_configured = false;
|
||||||
|
@ -129,34 +86,25 @@ pub fn main() !void {
|
||||||
while (!done or !surface_configured) {
|
while (!done or !surface_configured) {
|
||||||
const header, const body = try conn.recv();
|
const header, const body = try conn.recv();
|
||||||
|
|
||||||
if (header.object_id == xdg_surface_id) {
|
if (header.object_id == xdg_surface.id) {
|
||||||
const event = try wayland.deserialize(wayland.xdg.Surface.Event, header, body);
|
const event = try wayland.deserialize(wayland.xdg.Surface.Event, header, body);
|
||||||
switch (event) {
|
switch (event) {
|
||||||
.configure => |conf| {
|
.configure => |conf| {
|
||||||
try conn.send(
|
try xdg_surface.ack_configure(conf.serial);
|
||||||
wayland.xdg.Surface.Request,
|
|
||||||
xdg_surface_id,
|
|
||||||
.{ .ack_configure = .{
|
|
||||||
.serial = conf.serial,
|
|
||||||
} },
|
|
||||||
);
|
|
||||||
surface_configured = true;
|
surface_configured = true;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else if (zxdg_toplevel_decoration_id_opt != null and header.object_id == zxdg_toplevel_decoration_id_opt.?) {
|
} else if (header.object_id == xdg_toplevel.id) {
|
||||||
const event = try wayland.deserialize(wayland.zxdg.ToplevelDecorationV1.Event, header, body);
|
|
||||||
std.debug.print("<- zxdg_toplevel_decoration@{}\n", .{event});
|
|
||||||
} else if (header.object_id == xdg_toplevel_id) {
|
|
||||||
const event = try wayland.deserialize(wayland.xdg.Toplevel.Event, header, body);
|
const event = try wayland.deserialize(wayland.xdg.Toplevel.Event, header, body);
|
||||||
std.debug.print("<- {}\n", .{event});
|
std.debug.print("<- {}\n", .{event});
|
||||||
} else if (header.object_id == registry_done_id) {
|
} else if (header.object_id == registry_done) {
|
||||||
done = true;
|
done = true;
|
||||||
} else if (header.object_id == shm_id) {
|
} else if (header.object_id == shm.id) {
|
||||||
const event = try wayland.deserialize(wayland.core.Shm.Event, header, body);
|
const event = try wayland.deserialize(wayland.core.Shm.Event, header, body);
|
||||||
switch (event) {
|
switch (event) {
|
||||||
.format => |format| std.debug.print("<- format {} {}\n", .{ format.format, std.zig.fmtEscapes(std.mem.asBytes(&format.format)) }),
|
.format => |format| std.debug.print("<- format {} {}\n", .{ format.format, std.zig.fmtEscapes(std.mem.asBytes(&format.format)) }),
|
||||||
}
|
}
|
||||||
} else if (header.object_id == wl_seat_id) {
|
} else if (header.object_id == seat.id) {
|
||||||
const event = try wayland.deserialize(wayland.core.Seat.Event, header, body);
|
const event = try wayland.deserialize(wayland.core.Seat.Event, header, body);
|
||||||
switch (event) {
|
switch (event) {
|
||||||
.capabilities => |capabilities| {
|
.capabilities => |capabilities| {
|
||||||
|
@ -168,450 +116,17 @@ pub fn main() !void {
|
||||||
std.debug.print("<- wl_seat.name = {s}\n", .{name.name});
|
std.debug.print("<- wl_seat.name = {s}\n", .{name.name});
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else if (header.object_id == DISPLAY_ID) {
|
} else if (header.object_id == display.id) {
|
||||||
const event = try wayland.deserialize(wayland.core.Display.Event, header, body);
|
const event = try wayland.deserialize(wayland.core.Display.Event, header, body);
|
||||||
switch (event) {
|
switch (event) {
|
||||||
.@"error" => |err| std.debug.print("<- error({}): {} {s}\n", .{ err.object_id, err.code, err.message }),
|
.@"error" => |err| std.debug.print("<- error({}): {} {s}\n", .{ err.object_id, err.code, err.message }),
|
||||||
.delete_id => |id| {
|
.delete_id => |id| {
|
||||||
std.debug.print("id {} deleted\n", .{id});
|
std.debug.print("id {} deleted\n", .{id});
|
||||||
id_pool.destroy(id.id);
|
conn.id_pool.destroy(id.id);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
std.debug.print("{} {x} \"{}\"\n", .{ header.object_id, header.size_and_opcode.opcode, std.zig.fmtEscapes(std.mem.sliceAsBytes(body)) });
|
std.debug.print("{} {x} \"{}\"\n", .{ header.object_id, header.size_and_opcode.opcode, std.zig.fmtEscapes(std.mem.sliceAsBytes(body)) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var wl_touch_id_opt: ?u32 = null;
|
|
||||||
var wl_keyboard_id_opt: ?u32 = null;
|
|
||||||
if (seat_capabilties) |caps| {
|
|
||||||
if (caps.touch) {
|
|
||||||
wl_touch_id_opt = id_pool.create();
|
|
||||||
std.debug.print("wl touch id: {}\n", .{wl_touch_id_opt.?});
|
|
||||||
try conn.send(
|
|
||||||
wayland.core.Seat.Request,
|
|
||||||
wl_seat_id,
|
|
||||||
.{ .get_touch = .{
|
|
||||||
.new_id = wl_touch_id_opt.?,
|
|
||||||
} },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (caps.keyboard) {
|
|
||||||
wl_keyboard_id_opt = id_pool.create();
|
|
||||||
std.debug.print("wl keyboard id: {}\n", .{wl_keyboard_id_opt.?});
|
|
||||||
try conn.send(
|
|
||||||
wayland.core.Seat.Request,
|
|
||||||
wl_seat_id,
|
|
||||||
.{ .get_keyboard = .{
|
|
||||||
.new_id = wl_keyboard_id_opt.?,
|
|
||||||
} },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const wl_touch_id = wl_touch_id_opt orelse return error.MissingTouch;
|
|
||||||
const wl_keyboard_id = wl_keyboard_id_opt orelse return error.MissingKeyboard;
|
|
||||||
|
|
||||||
// allocate a shared memory file for display purposes
|
|
||||||
const framebuffer_size = [2]u32{ 128, 128 };
|
|
||||||
const pool_file_len = 1024 * framebuffer_size[0] * framebuffer_size[1] * @sizeOf(Pixel);
|
|
||||||
|
|
||||||
const pool_fd = try std.os.memfd_create("my-wayland-framebuffer", 0);
|
|
||||||
try std.os.ftruncate(pool_fd, pool_file_len);
|
|
||||||
const pool_bytes = try std.os.mmap(null, pool_file_len, std.os.PROT.READ | std.os.PROT.WRITE, std.os.MAP.SHARED, pool_fd, 0);
|
|
||||||
var pool_fixed_buffer_allocator = std.heap.FixedBufferAllocator.init(pool_bytes);
|
|
||||||
var pool_general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){ .backing_allocator = pool_fixed_buffer_allocator.allocator() };
|
|
||||||
const pool_alloc = pool_general_purpose_allocator.allocator();
|
|
||||||
|
|
||||||
const framebuffer = try pool_alloc.alloc(Pixel, framebuffer_size[0] * framebuffer_size[1]);
|
|
||||||
|
|
||||||
// put some interesting colors into the framebuffer
|
|
||||||
renderGradient(framebuffer, framebuffer_size);
|
|
||||||
|
|
||||||
const wl_shm_pool_id = id_pool.create();
|
|
||||||
{
|
|
||||||
std.debug.print("framebuffer_fd: {}\n", .{pool_fd});
|
|
||||||
try conn.send(
|
|
||||||
wayland.core.Shm.Request,
|
|
||||||
shm_id,
|
|
||||||
.{ .create_pool = .{
|
|
||||||
.new_id = wl_shm_pool_id,
|
|
||||||
.fd = @enumFromInt(pool_fd),
|
|
||||||
.size = pool_file_len,
|
|
||||||
} },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
var framebuffers = std.AutoHashMap(u32, []Pixel).init(gpa);
|
|
||||||
defer framebuffers.deinit();
|
|
||||||
try framebuffers.put(wl_shm_pool_id, framebuffer);
|
|
||||||
|
|
||||||
const wl_buffer_id = id_pool.create();
|
|
||||||
try conn.send(
|
|
||||||
wayland.core.ShmPool.Request,
|
|
||||||
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 = .argb8888,
|
|
||||||
} },
|
|
||||||
);
|
|
||||||
|
|
||||||
try conn.send(
|
|
||||||
wayland.core.Surface.Request,
|
|
||||||
surface_id,
|
|
||||||
.{ .attach = .{
|
|
||||||
.buffer = wl_buffer_id,
|
|
||||||
.x = 0,
|
|
||||||
.y = 0,
|
|
||||||
} },
|
|
||||||
);
|
|
||||||
|
|
||||||
try conn.send(
|
|
||||||
wayland.core.Surface.Request,
|
|
||||||
surface_id,
|
|
||||||
.{ .damage = .{
|
|
||||||
.x = 0,
|
|
||||||
.y = 0,
|
|
||||||
.width = std.math.maxInt(i32),
|
|
||||||
.height = std.math.maxInt(i32),
|
|
||||||
} },
|
|
||||||
);
|
|
||||||
|
|
||||||
try conn.send(
|
|
||||||
wayland.core.Surface.Request,
|
|
||||||
surface_id,
|
|
||||||
wayland.core.Surface.Request.commit,
|
|
||||||
);
|
|
||||||
|
|
||||||
var window_size: [2]u32 = [2]u32{ @intCast(framebuffer_size[0]), @intCast(framebuffer_size[1]) };
|
|
||||||
|
|
||||||
var scrollpos: [2]i32 = .{ 10, 10 };
|
|
||||||
var touchstart: ?[2]i32 = null;
|
|
||||||
|
|
||||||
var running = true;
|
|
||||||
while (running) {
|
|
||||||
const header, const body = try conn.recv();
|
|
||||||
|
|
||||||
if (header.object_id == xdg_surface_id) {
|
|
||||||
const event = try wayland.deserialize(wayland.xdg.Surface.Event, header, body);
|
|
||||||
switch (event) {
|
|
||||||
.configure => |conf| {
|
|
||||||
try conn.send(
|
|
||||||
wayland.xdg.Surface.Request,
|
|
||||||
xdg_surface_id,
|
|
||||||
.{ .ack_configure = .{
|
|
||||||
.serial = conf.serial,
|
|
||||||
} },
|
|
||||||
);
|
|
||||||
|
|
||||||
const new_buffer_id = id_pool.create();
|
|
||||||
const new_framebuffer = try pool_alloc.alloc(Pixel, window_size[0] * window_size[1]);
|
|
||||||
try framebuffers.put(new_buffer_id, new_framebuffer);
|
|
||||||
|
|
||||||
// put some interesting colors into the new_framebuffer
|
|
||||||
renderGradient(new_framebuffer, window_size);
|
|
||||||
|
|
||||||
// blit some characters
|
|
||||||
renderText(new_framebuffer, window_size, .{ @intCast(scrollpos[0]), @intCast(scrollpos[1]) }, "Hello, World!");
|
|
||||||
|
|
||||||
try conn.send(
|
|
||||||
wayland.core.ShmPool.Request,
|
|
||||||
wl_shm_pool_id,
|
|
||||||
.{ .create_buffer = .{
|
|
||||||
.new_id = new_buffer_id,
|
|
||||||
.offset = @intCast(@intFromPtr(new_framebuffer.ptr) - @intFromPtr(pool_bytes.ptr)),
|
|
||||||
.width = @intCast(window_size[0]),
|
|
||||||
.height = @intCast(window_size[1]),
|
|
||||||
.stride = @as(i32, @intCast(window_size[0])) * @sizeOf([4]u8),
|
|
||||||
.format = .argb8888,
|
|
||||||
} },
|
|
||||||
);
|
|
||||||
|
|
||||||
try conn.send(
|
|
||||||
wayland.core.Surface.Request,
|
|
||||||
surface_id,
|
|
||||||
.{ .attach = .{
|
|
||||||
.buffer = new_buffer_id,
|
|
||||||
.x = 0,
|
|
||||||
.y = 0,
|
|
||||||
} },
|
|
||||||
);
|
|
||||||
|
|
||||||
try conn.send(
|
|
||||||
wayland.core.Surface.Request,
|
|
||||||
surface_id,
|
|
||||||
.{ .damage = .{
|
|
||||||
.x = 0,
|
|
||||||
.y = 0,
|
|
||||||
.width = std.math.maxInt(i32),
|
|
||||||
.height = std.math.maxInt(i32),
|
|
||||||
} },
|
|
||||||
);
|
|
||||||
|
|
||||||
// commit the configuration
|
|
||||||
try conn.send(
|
|
||||||
wayland.core.Surface.Request,
|
|
||||||
surface_id,
|
|
||||||
wayland.core.Surface.Request.commit,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
} else if (header.object_id == xdg_toplevel_id) {
|
|
||||||
const event = try wayland.deserialize(wayland.xdg.Toplevel.Event, header, body);
|
|
||||||
switch (event) {
|
|
||||||
.configure => |conf| {
|
|
||||||
std.debug.print("<- xdg_toplevel@{} configure <{}, {}> {any}\n", .{ header.object_id, conf.width, conf.height, conf.states });
|
|
||||||
window_size = .{
|
|
||||||
@intCast(conf.width),
|
|
||||||
@intCast(conf.height),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
.close => running = false,
|
|
||||||
else => |tag| std.debug.print("<- xdg_toplevel@{} {s} {}\n", .{ header.object_id, @tagName(tag), event }),
|
|
||||||
}
|
|
||||||
} else if (header.object_id == xdg_wm_base_id) {
|
|
||||||
const event = try wayland.deserialize(wayland.xdg.WmBase.Event, header, body);
|
|
||||||
switch (event) {
|
|
||||||
.ping => |ping| {
|
|
||||||
try conn.send(
|
|
||||||
wayland.xdg.WmBase.Request,
|
|
||||||
xdg_wm_base_id,
|
|
||||||
.{ .pong = .{
|
|
||||||
.serial = ping.serial,
|
|
||||||
} },
|
|
||||||
);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
} else if (header.object_id == wl_touch_id) {
|
|
||||||
const event = try wayland.deserialize(wayland.core.Touch.Event, header, body);
|
|
||||||
std.debug.print("<- wl_touch@{}\n", .{event});
|
|
||||||
event: {
|
|
||||||
switch (event) {
|
|
||||||
.down => |down| {
|
|
||||||
if (down.id != 0) break :event;
|
|
||||||
touchstart = .{ @intCast(down.x), @intCast(down.y) };
|
|
||||||
},
|
|
||||||
.motion => |motion| {
|
|
||||||
if (motion.id != 0) break :event;
|
|
||||||
if (touchstart) |start| {
|
|
||||||
scrollpos[0] = motion.x - start[0];
|
|
||||||
scrollpos[1] = motion.y - start[1];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.up => |up| {
|
|
||||||
if (up.id != 0) break :event;
|
|
||||||
touchstart = null;
|
|
||||||
},
|
|
||||||
.frame => {
|
|
||||||
const new_buffer_id = id_pool.create();
|
|
||||||
const new_framebuffer = try pool_alloc.alloc(Pixel, window_size[0] * window_size[1]);
|
|
||||||
try framebuffers.put(new_buffer_id, new_framebuffer);
|
|
||||||
|
|
||||||
// put some interesting colors into the new_framebuffer
|
|
||||||
renderGradient(new_framebuffer, window_size);
|
|
||||||
|
|
||||||
// blit some characters
|
|
||||||
renderText(new_framebuffer, window_size, .{ @intCast(@divTrunc(scrollpos[0], 100)), @intCast(@divTrunc(scrollpos[1], 100)) }, "Hello, World!");
|
|
||||||
|
|
||||||
try conn.send(
|
|
||||||
wayland.core.ShmPool.Request,
|
|
||||||
wl_shm_pool_id,
|
|
||||||
.{ .create_buffer = .{
|
|
||||||
.new_id = new_buffer_id,
|
|
||||||
.offset = @intCast(@intFromPtr(new_framebuffer.ptr) - @intFromPtr(pool_bytes.ptr)),
|
|
||||||
.width = @intCast(window_size[0]),
|
|
||||||
.height = @intCast(window_size[1]),
|
|
||||||
.stride = @as(i32, @intCast(window_size[0])) * @sizeOf([4]u8),
|
|
||||||
.format = .argb8888,
|
|
||||||
} },
|
|
||||||
);
|
|
||||||
|
|
||||||
try conn.send(
|
|
||||||
wayland.core.Surface.Request,
|
|
||||||
surface_id,
|
|
||||||
.{ .attach = .{
|
|
||||||
.buffer = new_buffer_id,
|
|
||||||
.x = 0,
|
|
||||||
.y = 0,
|
|
||||||
} },
|
|
||||||
);
|
|
||||||
|
|
||||||
try conn.send(
|
|
||||||
wayland.core.Surface.Request,
|
|
||||||
surface_id,
|
|
||||||
.{ .damage = .{
|
|
||||||
.x = 0,
|
|
||||||
.y = 0,
|
|
||||||
.width = std.math.maxInt(i32),
|
|
||||||
.height = std.math.maxInt(i32),
|
|
||||||
} },
|
|
||||||
);
|
|
||||||
|
|
||||||
// commit the configuration
|
|
||||||
try conn.send(
|
|
||||||
wayland.core.Surface.Request,
|
|
||||||
surface_id,
|
|
||||||
wayland.core.Surface.Request.commit,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
else => {},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (header.object_id == wl_keyboard_id) {
|
|
||||||
const event = try wayland.deserialize(wayland.core.Keyboard.Event, header, body);
|
|
||||||
switch (event) {
|
|
||||||
.keymap => |keymap| {
|
|
||||||
const fd = conn.fd_queue.orderedRemove(0);
|
|
||||||
std.debug.print("keymap format={}, size={}, fd={}\n", .{
|
|
||||||
keymap.format,
|
|
||||||
keymap.size,
|
|
||||||
fd,
|
|
||||||
});
|
|
||||||
const mem = try std.os.mmap(
|
|
||||||
null,
|
|
||||||
keymap.size,
|
|
||||||
std.os.PROT.READ,
|
|
||||||
std.os.MAP.PRIVATE,
|
|
||||||
fd,
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
std.debug.print("---START xkb file---\n{s}\n---END xkb file---\n", .{mem});
|
|
||||||
},
|
|
||||||
.modifiers => |mods| {
|
|
||||||
std.debug.print("mod event: {}\n", .{mods});
|
|
||||||
},
|
|
||||||
.key => |key| {
|
|
||||||
std.debug.print("key event: {}\n", .{key});
|
|
||||||
const new_buffer_id, const new_framebuffer = try getFramebuffer(&framebuffers, &id_pool, pool_alloc, window_size);
|
|
||||||
|
|
||||||
// put some interesting colors into the new_framebuffer
|
|
||||||
renderGradient(new_framebuffer, window_size);
|
|
||||||
|
|
||||||
// blit some characters
|
|
||||||
renderText(new_framebuffer, window_size, .{ 10, 10 }, "Hello, World!");
|
|
||||||
|
|
||||||
try conn.send(
|
|
||||||
wayland.core.ShmPool.Request,
|
|
||||||
wl_shm_pool_id,
|
|
||||||
.{ .create_buffer = .{
|
|
||||||
.new_id = new_buffer_id,
|
|
||||||
.offset = @intCast(@intFromPtr(new_framebuffer.ptr) - @intFromPtr(pool_bytes.ptr)),
|
|
||||||
.width = @intCast(window_size[0]),
|
|
||||||
.height = @intCast(window_size[1]),
|
|
||||||
.stride = @as(i32, @intCast(window_size[0])) * @sizeOf([4]u8),
|
|
||||||
.format = .argb8888,
|
|
||||||
} },
|
|
||||||
);
|
|
||||||
|
|
||||||
try conn.send(
|
|
||||||
wayland.core.Surface.Request,
|
|
||||||
surface_id,
|
|
||||||
.{ .attach = .{
|
|
||||||
.buffer = new_buffer_id,
|
|
||||||
.x = 0,
|
|
||||||
.y = 0,
|
|
||||||
} },
|
|
||||||
);
|
|
||||||
|
|
||||||
try conn.send(
|
|
||||||
wayland.core.Surface.Request,
|
|
||||||
surface_id,
|
|
||||||
.{ .damage = .{
|
|
||||||
.x = 0,
|
|
||||||
.y = 0,
|
|
||||||
.width = std.math.maxInt(i32),
|
|
||||||
.height = std.math.maxInt(i32),
|
|
||||||
} },
|
|
||||||
);
|
|
||||||
|
|
||||||
// commit the configuration
|
|
||||||
try conn.send(
|
|
||||||
wayland.core.Surface.Request,
|
|
||||||
surface_id,
|
|
||||||
wayland.core.Surface.Request.commit,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
else => {
|
|
||||||
std.debug.print("<- wl_keyboard@{}\n", .{event});
|
|
||||||
},
|
|
||||||
}
|
|
||||||
} else if (framebuffers.get(header.object_id)) |framebuffer_slice| {
|
|
||||||
const event = try wayland.deserialize(wayland.core.Buffer.Event, header, body);
|
|
||||||
switch (event) {
|
|
||||||
.release => {
|
|
||||||
_ = framebuffers.remove(header.object_id);
|
|
||||||
pool_alloc.free(framebuffer_slice);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
} else if (header.object_id == DISPLAY_ID) {
|
|
||||||
const event = try wayland.deserialize(wayland.core.Display.Event, header, body);
|
|
||||||
switch (event) {
|
|
||||||
.@"error" => |err| std.debug.print("<- error({}): {} {s}\n", .{ err.object_id, err.code, err.message }),
|
|
||||||
.delete_id => |id| id_pool.destroy(id.id),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
std.debug.print("{} {x} \"{}\"\n", .{ header.object_id, header.size_and_opcode.opcode, std.zig.fmtEscapes(std.mem.sliceAsBytes(body)) });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn getFramebuffer(framebuffers: *std.AutoHashMap(u32, []Pixel), id_pool: *wayland.IdPool, pool_alloc: std.mem.Allocator, fb_size: [2]u32) !struct { u32, []Pixel } {
|
|
||||||
const new_buffer_id = id_pool.create();
|
|
||||||
const new_framebuffer = try pool_alloc.alloc(Pixel, fb_size[0] * fb_size[1]);
|
|
||||||
try framebuffers.put(new_buffer_id, new_framebuffer);
|
|
||||||
return .{ new_buffer_id, new_framebuffer };
|
|
||||||
}
|
|
||||||
|
|
||||||
fn renderGradient(framebuffer: []Pixel, fb_size: [2]u32) void {
|
|
||||||
for (0..fb_size[1]) |y| {
|
|
||||||
const row = framebuffer[y * fb_size[0] .. (y + 1) * fb_size[0]];
|
|
||||||
for (row, 0..fb_size[0]) |*pixel, x| {
|
|
||||||
pixel.* = .{
|
|
||||||
@truncate(x),
|
|
||||||
@truncate(y),
|
|
||||||
0x00,
|
|
||||||
0xFF,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn textWidth(str: []const u8) usize {
|
|
||||||
return std.unicode.utf8CountCodepoints(str) catch 0; // incorrect, but I'm going with it
|
|
||||||
}
|
|
||||||
|
|
||||||
fn renderText(framebuffer: []Pixel, fb_size: [2]u32, pos: [2]usize, str: []const u8) void {
|
|
||||||
const left, const top = pos;
|
|
||||||
const bot = @min(top + 8, fb_size[1]);
|
|
||||||
const right = @min(left + textWidth(str) * 8, fb_size[0]);
|
|
||||||
|
|
||||||
for (top..bot) |y| {
|
|
||||||
const row = framebuffer[y * fb_size[0] .. (y + 1) * fb_size[0]];
|
|
||||||
for (row[left..right], left..right) |*pixel, x| {
|
|
||||||
const col = ((x - left) / 8);
|
|
||||||
const which_char = str[col];
|
|
||||||
if (!std.ascii.isPrint(which_char)) continue;
|
|
||||||
const char = font8x8.font8x8_basic[which_char];
|
|
||||||
const line = char[(y - top) % 8];
|
|
||||||
if ((line >> @intCast((x - left) % 8)) & 0x1 != 0) {
|
|
||||||
pixel.* = toPixel(Theme.foreground);
|
|
||||||
} else {
|
|
||||||
pixel.* = toPixel(Theme.background);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
188
src/root.zig
188
src/root.zig
|
@ -407,78 +407,6 @@ pub const IdPool = struct {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn registerGlobals(alloc: std.mem.Allocator, id_pool: *IdPool, socket: std.net.Stream, comptime T: []const type) ![T.len]?u32 {
|
|
||||||
const Item = struct { version: u32, index: u32 };
|
|
||||||
const Pair = struct { []const u8, Item };
|
|
||||||
comptime var kvs_list: []const Pair = &[_]Pair{};
|
|
||||||
inline for (T, 0..) |t, i| {
|
|
||||||
kvs_list = kvs_list ++ &[_]Pair{.{ t.INTERFACE, .{ .version = t.VERSION, .index = i } }};
|
|
||||||
}
|
|
||||||
const map = std.ComptimeStringMap(Item, kvs_list);
|
|
||||||
|
|
||||||
const registry_id = id_pool.create();
|
|
||||||
{
|
|
||||||
var buffer: [5]u32 = undefined;
|
|
||||||
const message = try serialize(core.Display.Request, &buffer, 1, .{ .get_registry = .{ .registry = registry_id } });
|
|
||||||
try socket.writeAll(std.mem.sliceAsBytes(message));
|
|
||||||
}
|
|
||||||
|
|
||||||
const registry_done_id = id_pool.create();
|
|
||||||
{
|
|
||||||
var buffer: [5]u32 = undefined;
|
|
||||||
const message = try serialize(core.Display.Request, &buffer, 1, .{ .sync = .{ .callback = registry_done_id } });
|
|
||||||
try socket.writeAll(std.mem.sliceAsBytes(message));
|
|
||||||
}
|
|
||||||
|
|
||||||
var ids: [T.len]?u32 = [_]?u32{null} ** T.len;
|
|
||||||
var message_buffer = std.ArrayList(u32).init(alloc);
|
|
||||||
defer message_buffer.deinit();
|
|
||||||
while (true) {
|
|
||||||
var header: Header = undefined;
|
|
||||||
const header_bytes_read = try socket.readAll(std.mem.asBytes(&header));
|
|
||||||
if (header_bytes_read < @sizeOf(Header)) break;
|
|
||||||
|
|
||||||
try message_buffer.resize((header.size_and_opcode.size - @sizeOf(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 == registry_id) {
|
|
||||||
const event = try deserialize(core.Registry.Event, header, message_buffer.items);
|
|
||||||
switch (event) {
|
|
||||||
.global => |global| {
|
|
||||||
var buffer: [20]u32 = undefined;
|
|
||||||
if (map.get(global.interface)) |item| {
|
|
||||||
if (global.version < item.version) {
|
|
||||||
// TODO: Add diagnostics API
|
|
||||||
return error.OutdatedCompositorProtocol;
|
|
||||||
}
|
|
||||||
const new_id = id_pool.create();
|
|
||||||
ids[item.index] = new_id;
|
|
||||||
const message = try serialize(core.Registry.Request, &buffer, registry_id, .{ .bind = .{
|
|
||||||
.name = global.name,
|
|
||||||
.interface = global.interface,
|
|
||||||
.version = item.version,
|
|
||||||
.new_id = new_id,
|
|
||||||
} });
|
|
||||||
try socket.writeAll(std.mem.sliceAsBytes(message));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.global_remove => {},
|
|
||||||
}
|
|
||||||
} else if (header.object_id == registry_done_id) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
std.log.info("{} {x} \"{}\"", .{
|
|
||||||
header.object_id,
|
|
||||||
header.size_and_opcode.opcode,
|
|
||||||
std.zig.fmtEscapes(std.mem.sliceAsBytes(message_buffer.items)),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ids;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cmsg(comptime T: type) type {
|
fn cmsg(comptime T: type) type {
|
||||||
const padding_size = (@sizeOf(T) + @sizeOf(c_long) - 1) & ~(@as(usize, @sizeOf(c_long)) - 1);
|
const padding_size = (@sizeOf(T) + @sizeOf(c_long) - 1) & ~(@as(usize, @sizeOf(c_long)) - 1);
|
||||||
return extern struct {
|
return extern struct {
|
||||||
|
@ -496,6 +424,7 @@ pub const Conn = struct {
|
||||||
recv_buffer: []u32,
|
recv_buffer: []u32,
|
||||||
fd_queue: std.ArrayListUnmanaged(std.os.fd_t),
|
fd_queue: std.ArrayListUnmanaged(std.os.fd_t),
|
||||||
socket: std.net.Stream,
|
socket: std.net.Stream,
|
||||||
|
id_pool: IdPool,
|
||||||
|
|
||||||
pub fn init(alloc: std.mem.Allocator, display_path: []const u8) !Conn {
|
pub fn init(alloc: std.mem.Allocator, display_path: []const u8) !Conn {
|
||||||
const send_buffer = try alloc.alloc(u32, 16);
|
const send_buffer = try alloc.alloc(u32, 16);
|
||||||
|
@ -506,6 +435,7 @@ pub const Conn = struct {
|
||||||
.recv_buffer = recv_buffer,
|
.recv_buffer = recv_buffer,
|
||||||
.fd_queue = .{},
|
.fd_queue = .{},
|
||||||
.socket = try std.net.connectUnixSocket(display_path),
|
.socket = try std.net.connectUnixSocket(display_path),
|
||||||
|
.id_pool = .{},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -623,24 +553,96 @@ pub const Conn = struct {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// pub const XKBKeymap = struct {
|
pub fn Context(comptime T: []const type) type {
|
||||||
// keycodes: Keycodes,
|
const Item = struct { version: u32, index: u32 };
|
||||||
// types: Types,
|
const Pair = struct { []const u8, Item };
|
||||||
// compatability: Compatability,
|
comptime var kvs_list: []const Pair = &[_]Pair{};
|
||||||
// symbols: Symbols,
|
inline for (T, 0..) |t, i| {
|
||||||
//
|
kvs_list = kvs_list ++ &[_]Pair{.{ t.INTERFACE, .{ .version = t.VERSION, .index = i } }};
|
||||||
// const Keycodes = struct {
|
}
|
||||||
// min: usize,
|
const stringToType = std.ComptimeStringMap(Item, kvs_list);
|
||||||
// max: usize,
|
|
||||||
// map: std.AutoHashMap(usize, usize),
|
return struct {
|
||||||
// indicators: std.StringHashMap(usize),
|
conn: *Conn,
|
||||||
// };
|
global_ids: [T.len]?u32,
|
||||||
//
|
|
||||||
// const ISOKEY = [4]u8;
|
pub fn init(conn: *Conn) !@This() {
|
||||||
//
|
var ctx = @This(){
|
||||||
// const Types = struct {};
|
.conn = conn,
|
||||||
// const Compatability = struct {};
|
.global_ids = [_]?u32{null} ** T.len,
|
||||||
// const Symbols = struct {};
|
};
|
||||||
//
|
try ctx.registerGlobals();
|
||||||
// pub fn parse() {}
|
return ctx;
|
||||||
// };
|
}
|
||||||
|
|
||||||
|
pub fn getGlobal(ctx: *@This(), comptime G: type) !G {
|
||||||
|
if (G == core.Display) return .{ .id = 1, .conn = ctx.conn };
|
||||||
|
const g = stringToType.get(G.INTERFACE) orelse return error.NoSuchGlobal;
|
||||||
|
const id = ctx.global_ids[g.index] orelse return error.NotAGlobal;
|
||||||
|
return G.init(ctx.conn, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn registerGlobals(ctx: *@This()) !void {
|
||||||
|
// ![T.len]?u32 {
|
||||||
|
const registry_id = ctx.conn.id_pool.create();
|
||||||
|
{
|
||||||
|
var buffer: [5]u32 = undefined;
|
||||||
|
const message = try serialize(core.Display.Request, &buffer, 1, .{ .get_registry = .{ .registry = registry_id } });
|
||||||
|
try ctx.conn.socket.writeAll(std.mem.sliceAsBytes(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
const registry_done_id = ctx.conn.id_pool.create();
|
||||||
|
{
|
||||||
|
var buffer: [5]u32 = undefined;
|
||||||
|
const message = try serialize(core.Display.Request, &buffer, 1, .{ .sync = .{ .callback = registry_done_id } });
|
||||||
|
try ctx.conn.socket.writeAll(std.mem.sliceAsBytes(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
// var ids: [T.len]?u32 = [_]?u32{null} ** T.len;
|
||||||
|
var message_buffer = std.ArrayList(u32).init(ctx.conn.allocator);
|
||||||
|
defer message_buffer.deinit();
|
||||||
|
while (true) {
|
||||||
|
var header: Header = undefined;
|
||||||
|
const header_bytes_read = try ctx.conn.socket.readAll(std.mem.asBytes(&header));
|
||||||
|
if (header_bytes_read < @sizeOf(Header)) break;
|
||||||
|
|
||||||
|
try message_buffer.resize((header.size_and_opcode.size - @sizeOf(Header)) / @sizeOf(u32));
|
||||||
|
const bytes_read = try ctx.conn.socket.readAll(std.mem.sliceAsBytes(message_buffer.items));
|
||||||
|
message_buffer.shrinkRetainingCapacity(bytes_read / @sizeOf(u32));
|
||||||
|
|
||||||
|
if (header.object_id == registry_id) {
|
||||||
|
const event = try deserialize(core.Registry.Event, header, message_buffer.items);
|
||||||
|
switch (event) {
|
||||||
|
.global => |global| {
|
||||||
|
var buffer: [20]u32 = undefined;
|
||||||
|
if (stringToType.get(global.interface)) |item| {
|
||||||
|
if (global.version < item.version) {
|
||||||
|
// TODO: Add diagnostics API
|
||||||
|
return error.OutdatedCompositorProtocol;
|
||||||
|
}
|
||||||
|
const new_id = ctx.conn.id_pool.create();
|
||||||
|
ctx.global_ids[item.index] = new_id;
|
||||||
|
const message = try serialize(core.Registry.Request, &buffer, registry_id, .{ .bind = .{
|
||||||
|
.name = global.name,
|
||||||
|
.interface = global.interface,
|
||||||
|
.version = item.version,
|
||||||
|
.new_id = new_id,
|
||||||
|
} });
|
||||||
|
try ctx.conn.socket.writeAll(std.mem.sliceAsBytes(message));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.global_remove => {},
|
||||||
|
}
|
||||||
|
} else if (header.object_id == registry_done_id) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
std.log.info("{} {x} \"{}\"", .{
|
||||||
|
header.object_id,
|
||||||
|
header.size_and_opcode.opcode,
|
||||||
|
std.zig.fmtEscapes(std.mem.sliceAsBytes(message_buffer.items)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
59
src/xdg.zig
59
src/xdg.zig
|
@ -1,3 +1,6 @@
|
||||||
|
const core = @import("core.zig");
|
||||||
|
const Conn = @import("root.zig").Conn;
|
||||||
|
|
||||||
pub const WmBase = struct {
|
pub const WmBase = struct {
|
||||||
pub const INTERFACE = "xdg_wm_base";
|
pub const INTERFACE = "xdg_wm_base";
|
||||||
pub const VERSION = 2;
|
pub const VERSION = 2;
|
||||||
|
@ -40,6 +43,26 @@ pub const WmBase = struct {
|
||||||
invalid_positioner,
|
invalid_positioner,
|
||||||
unresponsive,
|
unresponsive,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
conn: *Conn,
|
||||||
|
id: u32,
|
||||||
|
|
||||||
|
pub fn init(conn: *Conn, id: u32) WmBase {
|
||||||
|
return .{ .conn = conn, .id = id };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_xdg_surface(base: WmBase, surface: core.Surface) !Surface {
|
||||||
|
const new_id = base.conn.id_pool.create();
|
||||||
|
try base.conn.send(
|
||||||
|
Request,
|
||||||
|
base.id,
|
||||||
|
.{ .get_xdg_surface = .{
|
||||||
|
.id = new_id,
|
||||||
|
.surface = surface.id,
|
||||||
|
} },
|
||||||
|
);
|
||||||
|
return Surface.init(base.conn, new_id);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Surface = struct {
|
pub const Surface = struct {
|
||||||
|
@ -77,6 +100,35 @@ pub const Surface = struct {
|
||||||
invalid_size,
|
invalid_size,
|
||||||
defunct_role_object,
|
defunct_role_object,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
conn: *Conn,
|
||||||
|
id: u32,
|
||||||
|
|
||||||
|
pub fn init(conn: *Conn, id: u32) Surface {
|
||||||
|
return .{ .conn = conn, .id = id };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_toplevel(surface: Surface) !Toplevel {
|
||||||
|
const new_id = surface.conn.id_pool.create();
|
||||||
|
try surface.conn.send(
|
||||||
|
Request,
|
||||||
|
surface.id,
|
||||||
|
.{ .get_toplevel = .{
|
||||||
|
.id = new_id,
|
||||||
|
} },
|
||||||
|
);
|
||||||
|
return Toplevel.init(surface.conn, new_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ack_configure(surface: Surface, serial: u32) !void {
|
||||||
|
try surface.conn.send(
|
||||||
|
Request,
|
||||||
|
surface.id,
|
||||||
|
.{ .ack_configure = .{
|
||||||
|
.serial = serial,
|
||||||
|
} },
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Toplevel = struct {
|
pub const Toplevel = struct {
|
||||||
|
@ -168,4 +220,11 @@ pub const Toplevel = struct {
|
||||||
defunct_role_object,
|
defunct_role_object,
|
||||||
_,
|
_,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
conn: *Conn,
|
||||||
|
id: u32,
|
||||||
|
|
||||||
|
pub fn init(conn: *Conn, id: u32) Toplevel {
|
||||||
|
return .{ .conn = conn, .id = id };
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue