feat: implement framebuffer allocator
parent
adadca6827
commit
f22a9ac2a9
78
src/core.zig
78
src/core.zig
|
@ -160,7 +160,7 @@ pub const ShmPool = struct {
|
|||
return .{ .conn = conn, .id = id };
|
||||
}
|
||||
|
||||
pub fn create_buffer(shm_pool: ShmPool, offset: i32, width: i32, height: i32, stride: i32, format: Shm.Format) u32 {
|
||||
pub fn create_buffer(shm_pool: ShmPool, offset: i32, width: i32, height: i32, stride: i32, format: Shm.Format) !Buffer {
|
||||
const new_id = shm_pool.conn.id_pool.create();
|
||||
try shm_pool.conn.send(
|
||||
Request,
|
||||
|
@ -174,7 +174,7 @@ pub const ShmPool = struct {
|
|||
.format = format,
|
||||
} },
|
||||
);
|
||||
return Surface.init(shm_pool.conn, new_id);
|
||||
return Buffer.init(shm_pool.conn, new_id);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -216,7 +216,7 @@ pub const Shm = struct {
|
|||
return .{ .conn = conn, .id = id };
|
||||
}
|
||||
|
||||
pub fn create_pool(shm: *const Shm, pool_fd: u32, size: u32) ShmPool {
|
||||
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,
|
||||
|
@ -284,6 +284,31 @@ pub const Surface = struct {
|
|||
return .{ .conn = conn, .id = id };
|
||||
}
|
||||
|
||||
pub fn attach(surface: Surface, buffer: Buffer, x: i32, y: i32) !void {
|
||||
try surface.conn.send(
|
||||
Request,
|
||||
surface.id,
|
||||
.{ .attach = .{
|
||||
.buffer = buffer.id,
|
||||
.x = x,
|
||||
.y = y,
|
||||
} },
|
||||
);
|
||||
}
|
||||
|
||||
pub fn damage(surface: Surface, x: i32, y: i32, width: i32, height: i32) !void {
|
||||
try surface.conn.send(
|
||||
Request,
|
||||
surface.id,
|
||||
.{ .damage = .{
|
||||
.x = x,
|
||||
.y = y,
|
||||
.width = width,
|
||||
.height = height,
|
||||
} },
|
||||
);
|
||||
}
|
||||
|
||||
pub fn commit(surface: Surface) !void {
|
||||
try surface.conn.send(
|
||||
Request,
|
||||
|
@ -301,6 +326,13 @@ pub const Buffer = struct {
|
|||
pub const Event = union(enum) {
|
||||
release: void,
|
||||
};
|
||||
|
||||
conn: *Conn,
|
||||
id: u32,
|
||||
|
||||
pub fn init(conn: *Conn, id: u32) Buffer {
|
||||
return .{ .conn = conn, .id = id };
|
||||
}
|
||||
};
|
||||
|
||||
pub const Seat = struct {
|
||||
|
@ -344,6 +376,40 @@ pub const Seat = struct {
|
|||
pub fn init(conn: *Conn, id: u32) Seat {
|
||||
return .{ .conn = conn, .id = id };
|
||||
}
|
||||
|
||||
pub fn get_pointer(seat: Seat) !Pointer {
|
||||
const new_id = seat.conn.id_pool.create();
|
||||
try seat.conn.send(
|
||||
Request,
|
||||
seat.id,
|
||||
.{ .get_pointer = .{
|
||||
.new_id = new_id,
|
||||
} },
|
||||
);
|
||||
return Pointer.init(seat.conn, new_id);
|
||||
}
|
||||
pub fn get_keyboard(seat: Seat) !Keyboard {
|
||||
const new_id = seat.conn.id_pool.create();
|
||||
try seat.conn.send(
|
||||
Request,
|
||||
seat.id,
|
||||
.{ .get_keyboard = .{
|
||||
.new_id = new_id,
|
||||
} },
|
||||
);
|
||||
return Keyboard.init(seat.conn, new_id);
|
||||
}
|
||||
pub fn get_touch(seat: Seat) !Touch {
|
||||
const new_id = seat.conn.id_pool.create();
|
||||
try seat.conn.send(
|
||||
Request,
|
||||
seat.id,
|
||||
.{ .get_touch = .{
|
||||
.new_id = new_id,
|
||||
} },
|
||||
);
|
||||
return Touch.init(seat.conn, new_id);
|
||||
}
|
||||
};
|
||||
|
||||
pub const Pointer = struct {
|
||||
|
@ -435,7 +501,7 @@ pub const Pointer = struct {
|
|||
conn: *Conn,
|
||||
id: u32,
|
||||
|
||||
pub fn init(conn: *Conn, id: u32) Seat {
|
||||
pub fn init(conn: *Conn, id: u32) Pointer {
|
||||
return .{ .conn = conn, .id = id };
|
||||
}
|
||||
};
|
||||
|
@ -492,7 +558,7 @@ pub const Keyboard = struct {
|
|||
conn: *Conn,
|
||||
id: u32,
|
||||
|
||||
pub fn init(conn: *Conn, id: u32) Seat {
|
||||
pub fn init(conn: *Conn, id: u32) Keyboard {
|
||||
return .{ .conn = conn, .id = id };
|
||||
}
|
||||
};
|
||||
|
@ -538,7 +604,7 @@ pub const Touch = struct {
|
|||
conn: *Conn,
|
||||
id: u32,
|
||||
|
||||
pub fn init(conn: *Conn, id: u32) Seat {
|
||||
pub fn init(conn: *Conn, id: u32) Touch {
|
||||
return .{ .conn = conn, .id = id };
|
||||
}
|
||||
};
|
||||
|
|
501
src/main.zig
501
src/main.zig
|
@ -63,6 +63,7 @@ pub fn main() !void {
|
|||
var conn = try Conn.init(gpa, display_path);
|
||||
defer conn.deinit();
|
||||
|
||||
// Register all globals
|
||||
var ctx = try Context.init(&conn);
|
||||
|
||||
const compositor = try ctx.getGlobal(wayland.core.Compositor);
|
||||
|
@ -75,58 +76,468 @@ pub fn main() !void {
|
|||
try surface.commit();
|
||||
|
||||
const display = try ctx.getGlobal(wayland.core.Display);
|
||||
const registry_done = try display.sync();
|
||||
|
||||
const shm = try ctx.getGlobal(wayland.core.Shm);
|
||||
const seat = try ctx.getGlobal(wayland.core.Seat);
|
||||
|
||||
var done = false;
|
||||
var surface_configured = false;
|
||||
var seat_capabilties: ?wayland.core.Seat.Capability = null;
|
||||
while (!done or !surface_configured) {
|
||||
var app = App{
|
||||
.conn = &conn,
|
||||
.ctx = &ctx,
|
||||
.ally = gpa,
|
||||
.callbacks = std.AutoHashMap(u32, App.Callback).init(gpa),
|
||||
.state = .{ .init = .{} },
|
||||
.display = display,
|
||||
.shm = shm,
|
||||
.xdg_wmbase = xdg_wm_base,
|
||||
.surface = surface,
|
||||
.xdg_surface = xdg_surface,
|
||||
.xdg_toplevel = xdg_toplevel,
|
||||
};
|
||||
defer app.deinit();
|
||||
|
||||
try app.callbacks.put(seat.id, seatInitHandler);
|
||||
try app.callbacks.put(xdg_toplevel.id, toplevelInitHandler);
|
||||
try app.callbacks.put(xdg_surface.id, surfaceInitHandler);
|
||||
try app.callbacks.put(display.id, displayHandler);
|
||||
|
||||
while (app.state == .init) {
|
||||
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 xdg_surface.ack_configure(conf.serial);
|
||||
surface_configured = true;
|
||||
},
|
||||
}
|
||||
} else if (header.object_id == xdg_toplevel.id) {
|
||||
const event = try wayland.deserialize(wayland.xdg.Toplevel.Event, header, body);
|
||||
std.debug.print("<- {}\n", .{event});
|
||||
} else if (header.object_id == registry_done) {
|
||||
done = true;
|
||||
} else if (header.object_id == shm.id) {
|
||||
const event = try wayland.deserialize(wayland.core.Shm.Event, header, body);
|
||||
switch (event) {
|
||||
.format => |format| std.debug.print("<- format {} {}\n", .{ format.format, std.zig.fmtEscapes(std.mem.asBytes(&format.format)) }),
|
||||
}
|
||||
} else if (header.object_id == seat.id) {
|
||||
const event = try wayland.deserialize(wayland.core.Seat.Event, header, body);
|
||||
switch (event) {
|
||||
.capabilities => |capabilities| {
|
||||
const cap: wayland.core.Seat.Capability = @bitCast(capabilities.capability);
|
||||
std.debug.print("<- wl_seat.capabilties = {}\n", .{cap});
|
||||
seat_capabilties = cap;
|
||||
},
|
||||
.name => |name| {
|
||||
std.debug.print("<- wl_seat.name = {s}\n", .{name.name});
|
||||
},
|
||||
}
|
||||
} 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| {
|
||||
std.debug.print("id {} deleted\n", .{id});
|
||||
conn.id_pool.destroy(id.id);
|
||||
},
|
||||
}
|
||||
if (app.callbacks.get(header.object_id)) |callback| {
|
||||
try callback(&app, header, body);
|
||||
} else {
|
||||
std.debug.print("{} {x} \"{}\"\n", .{ header.object_id, header.size_and_opcode.opcode, std.zig.fmtEscapes(std.mem.sliceAsBytes(body)) });
|
||||
const typename = if (ctx.getGlobalObjectName(header.object_id)) |name|
|
||||
name
|
||||
else
|
||||
"UNKNOWN";
|
||||
std.debug.print("{} ({s}) {x} \"{}\"\n", .{
|
||||
header.object_id,
|
||||
typename,
|
||||
header.size_and_opcode.opcode,
|
||||
std.zig.fmtEscapes(std.mem.sliceAsBytes(body)),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const pool = if (app.state == .run_mobile) &app.state.run_mobile.pool else &app.state.run_desktop.pool;
|
||||
const width = if (app.state == .run_mobile) app.state.run_mobile.width else app.state.run_desktop.width;
|
||||
const height = if (app.state == .run_mobile) app.state.run_mobile.height else app.state.run_desktop.height;
|
||||
|
||||
// render
|
||||
const canvas = try pool.getFramebuffer(.{ width, height });
|
||||
canvas.renderGradient();
|
||||
try canvas.attach(surface);
|
||||
try app.callbacks.put(canvas.buffer.id, bufferHandler);
|
||||
|
||||
while (app.state != .close) {
|
||||
const header, const body = try conn.recv();
|
||||
|
||||
if (app.callbacks.get(header.object_id)) |callback| {
|
||||
try callback(&app, header, body);
|
||||
} else {
|
||||
const typename = if (ctx.getGlobalObjectName(header.object_id)) |name|
|
||||
name
|
||||
else
|
||||
"UNKNOWN";
|
||||
std.debug.print("{} ({s}) {x} \"{}\"\n", .{
|
||||
header.object_id,
|
||||
typename,
|
||||
header.size_and_opcode.opcode,
|
||||
std.zig.fmtEscapes(std.mem.sliceAsBytes(body)),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const App = struct {
|
||||
conn: *Conn,
|
||||
ctx: *Context,
|
||||
ally: std.mem.Allocator,
|
||||
callbacks: std.AutoHashMap(u32, Callback),
|
||||
|
||||
display: wayland.core.Display,
|
||||
shm: wayland.core.Shm,
|
||||
surface: wayland.core.Surface,
|
||||
xdg_wmbase: wayland.xdg.WmBase,
|
||||
xdg_surface: wayland.xdg.Surface,
|
||||
xdg_toplevel: wayland.xdg.Toplevel,
|
||||
|
||||
state: union(enum) {
|
||||
init: struct {
|
||||
toplevel_config: ?SurfaceConfiguration = null,
|
||||
surface_configured: bool = false,
|
||||
seat_capabilities: ?wayland.core.Seat.Capability = null,
|
||||
pointer: ?wayland.core.Pointer = null,
|
||||
keyboard: ?wayland.core.Keyboard = null,
|
||||
touch: ?wayland.core.Touch = null,
|
||||
},
|
||||
run_mobile: struct {
|
||||
width: u32,
|
||||
height: u32,
|
||||
pool: Pool,
|
||||
touch: wayland.core.Touch,
|
||||
},
|
||||
run_desktop: struct {
|
||||
width: u32,
|
||||
height: u32,
|
||||
pool: Pool,
|
||||
keyboard: wayland.core.Keyboard,
|
||||
pointer: wayland.core.Pointer,
|
||||
mouse: struct {
|
||||
x: f32,
|
||||
y: f32,
|
||||
},
|
||||
},
|
||||
close,
|
||||
},
|
||||
|
||||
const SurfaceConfiguration = struct {
|
||||
width: u32,
|
||||
height: u32,
|
||||
};
|
||||
|
||||
const Callback = *const fn (*App, wayland.Header, []const u32) anyerror!void;
|
||||
|
||||
fn deinit(app: *App) void {
|
||||
app.callbacks.deinit();
|
||||
}
|
||||
|
||||
fn checkInit(app: *App) !void {
|
||||
std.debug.assert(app.state == .init);
|
||||
const init = app.state.init;
|
||||
if (!init.surface_configured) return;
|
||||
if (init.seat_capabilities == null) return;
|
||||
|
||||
app.callbacks.clearRetainingCapacity();
|
||||
try app.callbacks.put(app.display.id, displayHandler);
|
||||
|
||||
if (init.touch != null and init.keyboard == null) {
|
||||
// mobile
|
||||
app.state = .{ .run_mobile = .{
|
||||
.width = init.toplevel_config.?.width,
|
||||
.height = init.toplevel_config.?.height,
|
||||
.pool = try Pool.init(app.ally, app.shm),
|
||||
.touch = init.touch.?,
|
||||
} };
|
||||
try app.callbacks.put(app.xdg_wmbase.id, wmbaseHandler);
|
||||
try app.callbacks.put(app.xdg_toplevel.id, toplevelHandler);
|
||||
// try app.callbacks.put(app.state.run_desktop.touch.id, touchMobileHandler);
|
||||
} else if (init.keyboard != null and init.pointer != null) {
|
||||
// desktop
|
||||
app.state = .{ .run_desktop = .{
|
||||
.width = init.toplevel_config.?.width,
|
||||
.height = init.toplevel_config.?.height,
|
||||
.pool = try Pool.init(app.ally, app.shm),
|
||||
.keyboard = init.keyboard.?,
|
||||
.pointer = init.pointer.?,
|
||||
.mouse = .{ .x = 0, .y = 0 },
|
||||
} };
|
||||
try app.callbacks.put(app.state.run_desktop.pointer.id, pointerDesktopHandler);
|
||||
try app.callbacks.put(app.state.run_desktop.keyboard.id, keyboardDesktopHandler);
|
||||
try app.callbacks.put(app.xdg_surface.id, surfaceDesktopHandler);
|
||||
try app.callbacks.put(app.xdg_wmbase.id, wmbaseHandler);
|
||||
try app.callbacks.put(app.xdg_toplevel.id, toplevelHandler);
|
||||
} else {
|
||||
@panic("no keyboard or touch");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fn surfaceInitHandler(app: *App, header: wayland.Header, body: []const u32) !void {
|
||||
const event = try wayland.deserialize(wayland.xdg.Surface.Event, header, body);
|
||||
switch (event) {
|
||||
.configure => |conf| {
|
||||
try app.xdg_surface.ack_configure(conf.serial);
|
||||
std.debug.assert(app.state.init.toplevel_config != null);
|
||||
app.state.init.surface_configured = true;
|
||||
try app.checkInit();
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn toplevelInitHandler(app: *App, header: wayland.Header, body: []const u32) !void {
|
||||
const event = try wayland.deserialize(wayland.xdg.Toplevel.Event, header, body);
|
||||
switch (event) {
|
||||
.configure => |conf| {
|
||||
var width = conf.width;
|
||||
var height = conf.height;
|
||||
if (conf.width == 0) {
|
||||
width = 128;
|
||||
height = 128;
|
||||
}
|
||||
app.state.init.toplevel_config = .{
|
||||
.width = @intCast(width),
|
||||
.height = @intCast(height),
|
||||
};
|
||||
},
|
||||
else => {
|
||||
std.log.info("toplevel event: {}", .{event});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn seatInitHandler(app: *App, header: wayland.Header, body: []const u32) !void {
|
||||
const event = try wayland.deserialize(wayland.core.Seat.Event, header, body);
|
||||
const seat = wayland.core.Seat.init(app.conn, header.object_id); // TODO: pass into cb
|
||||
switch (event) {
|
||||
.capabilities => |capabilities| {
|
||||
const caps: wayland.core.Seat.Capability = @bitCast(capabilities.capability);
|
||||
app.state.init.seat_capabilities = caps;
|
||||
|
||||
if (caps.pointer) {
|
||||
app.state.init.pointer = try seat.get_pointer();
|
||||
}
|
||||
if (caps.touch) {
|
||||
app.state.init.touch = try seat.get_touch();
|
||||
}
|
||||
if (caps.keyboard) {
|
||||
app.state.init.keyboard = try seat.get_keyboard();
|
||||
}
|
||||
|
||||
try app.checkInit();
|
||||
},
|
||||
.name => |name| {
|
||||
std.debug.print("<- wl_seat.name = {s}\n", .{name.name});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn displayHandler(app: *App, header: wayland.Header, body: []const u32) !void {
|
||||
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| {
|
||||
std.debug.print("id {} deleted\n", .{id});
|
||||
app.conn.id_pool.destroy(id.id);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const Pool = struct {
|
||||
fd: std.os.fd_t,
|
||||
shm: wayland.core.ShmPool,
|
||||
mem: []u8,
|
||||
file_length: usize,
|
||||
allocationTable: std.AutoHashMap(u32, Buffer),
|
||||
const Buffer = struct {
|
||||
offset: usize,
|
||||
len: usize,
|
||||
width: usize = 0,
|
||||
height: usize = 0,
|
||||
};
|
||||
|
||||
// Memory to store 4k screen pixels
|
||||
// const UPPER_BOUND = 33_177_600;
|
||||
// Memory to store 8k screen pixels
|
||||
// const UPPER_BOUND = 132_710_400;
|
||||
|
||||
const UPPER_BOUND = (7680 * 4320 * 4);
|
||||
|
||||
fn init(allocator: std.mem.Allocator, shm: wayland.core.Shm) !Pool {
|
||||
const pool_fd_1 = try std.os.memfd_create("my-wayland-framebuffer-1", 0);
|
||||
const pool_bytes_1 = try std.os.mmap(
|
||||
null,
|
||||
UPPER_BOUND,
|
||||
std.os.PROT.READ | std.os.PROT.WRITE,
|
||||
std.os.MAP.SHARED,
|
||||
pool_fd_1,
|
||||
0,
|
||||
);
|
||||
const shm1 = try shm.create_pool(@intCast(pool_fd_1), @intCast(pool_bytes_1.len));
|
||||
return Pool{
|
||||
.fd = pool_fd_1,
|
||||
.shm = shm1,
|
||||
.mem = pool_bytes_1,
|
||||
.file_length = 0,
|
||||
.allocationTable = std.AutoHashMap(u32, Buffer).init(allocator),
|
||||
};
|
||||
}
|
||||
|
||||
fn getFramebuffer(pool: *Pool, size: [2]u32) !Canvas {
|
||||
var iter = pool.allocationTable.iterator();
|
||||
var first_offset: usize = std.math.maxInt(usize);
|
||||
var total_len: usize = 0;
|
||||
while (iter.next()) |entry| {
|
||||
const offset = entry.value_ptr.offset;
|
||||
const len = entry.value_ptr.len;
|
||||
total_len += len;
|
||||
if (offset < first_offset) {
|
||||
if (first_offset != std.math.maxInt(usize)) {
|
||||
total_len += first_offset - offset;
|
||||
}
|
||||
first_offset = offset;
|
||||
}
|
||||
}
|
||||
const pixel_count = size[0] * size[1];
|
||||
const byte_count = pixel_count * @sizeOf(Pixel);
|
||||
var alloc_offset: usize = 0;
|
||||
if (byte_count < first_offset) {
|
||||
alloc_offset = 0;
|
||||
} else {
|
||||
alloc_offset = first_offset + total_len;
|
||||
}
|
||||
const final_offset = alloc_offset + byte_count;
|
||||
if (final_offset > pool.file_length) {
|
||||
try std.os.ftruncate(pool.fd, final_offset);
|
||||
pool.file_length = final_offset;
|
||||
}
|
||||
|
||||
const buffer = try pool.shm.create_buffer(
|
||||
@intCast(alloc_offset),
|
||||
@intCast(size[0]),
|
||||
@intCast(size[1]),
|
||||
@intCast(size[0] * @sizeOf(Pixel)),
|
||||
.argb8888,
|
||||
);
|
||||
|
||||
try pool.allocationTable.put(buffer.id, .{
|
||||
.offset = alloc_offset,
|
||||
.len = byte_count,
|
||||
.width = size[0],
|
||||
.height = size[1],
|
||||
});
|
||||
|
||||
return .{
|
||||
.pool = pool,
|
||||
.buffer = buffer,
|
||||
.fb = @as([*]Pixel, @ptrCast(pool.mem[alloc_offset..].ptr))[0..pixel_count],
|
||||
.size = size,
|
||||
};
|
||||
}
|
||||
|
||||
fn freeFramebuffer(pool: *Pool, buffer_id: u32) !void {
|
||||
std.debug.assert(pool.allocationTable.remove(buffer_id));
|
||||
}
|
||||
};
|
||||
|
||||
const Canvas = struct {
|
||||
pool: *Pool,
|
||||
fb: []Pixel,
|
||||
buffer: wayland.core.Buffer,
|
||||
size: [2]u32,
|
||||
|
||||
fn attach(canvas: Canvas, surface: wayland.core.Surface) !void {
|
||||
try surface.attach(canvas.buffer, 0, 0);
|
||||
try surface.damage(0, 0, std.math.maxInt(i32), std.math.maxInt(i32));
|
||||
try surface.commit();
|
||||
}
|
||||
|
||||
fn renderGradient(canvas: Canvas) void {
|
||||
const fb = canvas.fb;
|
||||
const width = canvas.size[0];
|
||||
const height = canvas.size[1];
|
||||
for (0..height) |y| {
|
||||
const row = fb[y * width .. (y + 1) * width];
|
||||
for (row, 0..width) |*pixel, x| {
|
||||
pixel.* = .{
|
||||
@truncate(x),
|
||||
@truncate(y),
|
||||
0x00,
|
||||
0xFF,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fn wmbaseHandler(app: *App, header: wayland.Header, body: []const u32) !void {
|
||||
const event = try wayland.deserialize(wayland.xdg.WmBase.Event, header, body);
|
||||
switch (event) {
|
||||
.ping => |ping| {
|
||||
try app.xdg_wmbase.pong(ping.serial);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn toplevelHandler(app: *App, header: wayland.Header, body: []const u32) !void {
|
||||
const event = try wayland.deserialize(wayland.xdg.Toplevel.Event, header, body);
|
||||
switch (event) {
|
||||
.configure => |conf| {
|
||||
var width = conf.width;
|
||||
var height = conf.height;
|
||||
if (conf.width == 0) {
|
||||
width = 128;
|
||||
height = 128;
|
||||
}
|
||||
if (app.state == .run_mobile) {
|
||||
app.state.run_mobile.width = @intCast(width);
|
||||
app.state.run_mobile.height = @intCast(height);
|
||||
} else {
|
||||
app.state.run_desktop.width = @intCast(width);
|
||||
app.state.run_desktop.height = @intCast(height);
|
||||
}
|
||||
},
|
||||
else => {
|
||||
std.log.info("toplevel event: {}", .{event});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn surfaceDesktopHandler(app: *App, header: wayland.Header, body: []const u32) !void {
|
||||
const event = try wayland.deserialize(wayland.xdg.Surface.Event, header, body);
|
||||
switch (event) {
|
||||
.configure => |conf| {
|
||||
try app.xdg_surface.ack_configure(conf.serial);
|
||||
const pool = if (app.state == .run_mobile) &app.state.run_mobile.pool else &app.state.run_desktop.pool;
|
||||
const width = if (app.state == .run_mobile) app.state.run_mobile.width else app.state.run_desktop.width;
|
||||
const height = if (app.state == .run_mobile) app.state.run_mobile.height else app.state.run_desktop.height;
|
||||
|
||||
// render
|
||||
const canvas = try pool.getFramebuffer(.{ width, height });
|
||||
canvas.renderGradient();
|
||||
try canvas.attach(app.surface);
|
||||
try app.callbacks.put(canvas.buffer.id, bufferHandler);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn pointerDesktopHandler(app: *App, header: wayland.Header, body: []const u32) !void {
|
||||
const event = try wayland.deserialize(wayland.core.Pointer.Event, header, body);
|
||||
switch (event) {
|
||||
.enter => |enter| {
|
||||
app.state.run_desktop.mouse.x = @floatFromInt(enter.surface_x);
|
||||
app.state.run_desktop.mouse.y = @floatFromInt(enter.surface_y);
|
||||
},
|
||||
.leave => |_| {},
|
||||
.motion => |motion| {
|
||||
app.state.run_desktop.mouse.x = @floatFromInt(motion.surface_x);
|
||||
app.state.run_desktop.mouse.y = @floatFromInt(motion.surface_y);
|
||||
},
|
||||
else => {
|
||||
std.log.info("pointer event: {}", .{event});
|
||||
},
|
||||
// .button => |button| { _ = button; },
|
||||
// .axis => |axis| { _ = axis;},
|
||||
// .frame => {},
|
||||
// .axis_source => |axis_source| { _ = axis_source; },
|
||||
// .axis_stop => |axis_stop| { _ = axis_stop; },
|
||||
// .axis_discrete => |axis_discrete| { _ = axis_discrete; },
|
||||
// .axis_value120 => |axis_value120| { _ = axis_value120; },
|
||||
// .axis_relative_direction => |axis_relative_direction| {_ = axis_relative_direction; },
|
||||
}
|
||||
}
|
||||
|
||||
fn keyboardDesktopHandler(app: *App, header: wayland.Header, body: []const u32) !void {
|
||||
const event = try wayland.deserialize(wayland.core.Keyboard.Event, header, body);
|
||||
_ = app;
|
||||
switch (event) {
|
||||
else => {
|
||||
std.log.info("keyboard event: {}", .{event});
|
||||
},
|
||||
// .button => |button| { _ = button; },
|
||||
// .axis => |axis| { _ = axis;},
|
||||
// .frame => {},
|
||||
// .axis_source => |axis_source| { _ = axis_source; },
|
||||
// .axis_stop => |axis_stop| { _ = axis_stop; },
|
||||
// .axis_discrete => |axis_discrete| { _ = axis_discrete; },
|
||||
// .axis_value120 => |axis_value120| { _ = axis_value120; },
|
||||
// .axis_relative_direction => |axis_relative_direction| {_ = axis_relative_direction; },
|
||||
}
|
||||
}
|
||||
|
||||
fn bufferHandler(app: *App, header: wayland.Header, body: []const u32) !void {
|
||||
const event = try wayland.deserialize(wayland.core.Buffer.Event, header, body);
|
||||
std.debug.assert(event == .release);
|
||||
const pool = if (app.state == .run_mobile) &app.state.run_mobile.pool else &app.state.run_desktop.pool;
|
||||
try pool.freeFramebuffer(header.object_id);
|
||||
}
|
||||
|
|
15
src/root.zig
15
src/root.zig
|
@ -557,8 +557,10 @@ pub fn Context(comptime T: []const type) type {
|
|||
const Item = struct { version: u32, index: u32 };
|
||||
const Pair = struct { []const u8, Item };
|
||||
comptime var kvs_list: []const Pair = &[_]Pair{};
|
||||
comptime var name_list: []const []const u8 = &[_][]const u8{};
|
||||
inline for (T, 0..) |t, i| {
|
||||
kvs_list = kvs_list ++ &[_]Pair{.{ t.INTERFACE, .{ .version = t.VERSION, .index = i } }};
|
||||
name_list = name_list ++ &[_][]const u8{t.INTERFACE};
|
||||
}
|
||||
const stringToType = std.ComptimeStringMap(Item, kvs_list);
|
||||
|
||||
|
@ -566,6 +568,8 @@ pub fn Context(comptime T: []const type) type {
|
|||
conn: *Conn,
|
||||
global_ids: [T.len]?u32,
|
||||
|
||||
const global_names = name_list;
|
||||
|
||||
pub fn init(conn: *Conn) !@This() {
|
||||
var ctx = @This(){
|
||||
.conn = conn,
|
||||
|
@ -575,6 +579,14 @@ pub fn Context(comptime T: []const type) type {
|
|||
return ctx;
|
||||
}
|
||||
|
||||
pub fn getGlobalObjectName(ctx: *@This(), id: u32) ?[]const u8 {
|
||||
for (ctx.global_ids, 0..) |gid_opt, i| {
|
||||
const gid = gid_opt orelse continue;
|
||||
if (gid == id) return global_names[i];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -598,7 +610,6 @@ pub fn Context(comptime T: []const type) type {
|
|||
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) {
|
||||
|
@ -636,7 +647,7 @@ pub fn Context(comptime T: []const type) type {
|
|||
} else if (header.object_id == registry_done_id) {
|
||||
break;
|
||||
} else {
|
||||
std.log.info("{} {x} \"{}\"", .{
|
||||
std.log.info("registerGlobals: {} {x} \"{}\"", .{
|
||||
header.object_id,
|
||||
header.size_and_opcode.opcode,
|
||||
std.zig.fmtEscapes(std.mem.sliceAsBytes(message_buffer.items)),
|
||||
|
|
|
@ -63,6 +63,14 @@ pub const WmBase = struct {
|
|||
);
|
||||
return Surface.init(base.conn, new_id);
|
||||
}
|
||||
|
||||
pub fn pong(base: WmBase, serial: u32) !void {
|
||||
try base.conn.send(
|
||||
Request,
|
||||
base.id,
|
||||
.{ .pong = .{ .serial = serial } },
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
pub const Surface = struct {
|
||||
|
|
Loading…
Reference in New Issue