diff --git a/src/main.zig b/src/main.zig index c06dfc4..8794ec6 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,6 +1,7 @@ const std = @import("std"); const wayland = @import("root.zig"); const freetype = @import("freetype"); +const harfbuzz = @import("harfbuzz"); const font_assets = @import("font-assets"); const Conn = wayland.Conn; @@ -129,9 +130,10 @@ pub fn main() !void { } } - 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; + std.debug.assert(app.state == .run); + const pool = &app.state.run.pool; + const width = app.state.run.width; + const height = app.state.run.height; // render const canvas = try pool.getFramebuffer(.{ width, height }); @@ -183,18 +185,13 @@ const App = struct { 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 { + run: struct { width: u32, height: u32, pool: Pool, keyboard: wayland.core.Keyboard, - pointer: wayland.core.Pointer, + pointer: ?wayland.core.Pointer = null, + touch: ?wayland.core.Touch = null, mouse: struct { x: f32, y: f32, @@ -214,6 +211,12 @@ const App = struct { app.callbacks.deinit(); } + fn close(app: *App) void { + std.debug.assert(app.state == .run); + app.state.run.pool.deinit(); + app.state = .close; + } + fn checkInit(app: *App) !void { std.debug.assert(app.state == .init); const init = app.state.init; @@ -223,34 +226,26 @@ const App = struct { 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"); + app.state = .{ .run = .{ + .width = init.toplevel_config.?.width, + .height = init.toplevel_config.?.height, + .pool = try Pool.init(app.ally, app.shm), + .keyboard = init.keyboard.?, + .mouse = .{ .x = 0, .y = 0 }, + } }; + + try app.callbacks.put(app.state.run.keyboard.id, keyboardHandler); + 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); + + if (init.touch) |touch| { + app.state.run.touch = touch; + try app.callbacks.put(touch.id, touchHandler); + } + if (init.pointer) |pointer| { + app.state.run.pointer = pointer; + try app.callbacks.put(pointer.id, pointerHandler); } } }; @@ -328,7 +323,7 @@ fn displayHandler(app: *App, header: wayland.Header, body: []const u32) !void { const Pool = struct { fd: std.os.fd_t, shm: wayland.core.ShmPool, - mem: []u8, + mem: []align(4096) u8, file_length: usize, allocationTable: std.AutoHashMap(u32, Buffer), const Buffer = struct { @@ -365,6 +360,12 @@ const Pool = struct { }; } + pub fn deinit(pool: *Pool) void { + pool.allocationTable.deinit(); + std.os.munmap(pool.mem); + std.os.close(pool.fd); + } + fn getFramebuffer(pool: *Pool, size: [2]u32) !Canvas { var iter = pool.allocationTable.iterator(); var first_offset: usize = std.math.maxInt(usize); @@ -467,14 +468,28 @@ const Canvas = struct { const row = fb[y * width .. (y + 1) * width]; for (left..right, 0..) |x, a| { const pixel = &row[x]; - const intensity = buffer[i * cols + a]; + const intensity: u16 = buffer[i * cols + a]; if (intensity != 0) { pixel.* = .{ - intensity, - intensity, - intensity, + @intCast(intensity), + @intCast(intensity), + @intCast(intensity), 0xFF, }; + + // TODO: properly implement blending + // const over_alpha = intensity; + // const under_alpha = pixel[3]; + // const blended_alpha = over_alpha +| under_alpha *| (255 -| over_alpha); + // const color1: u16 = intensity * over_alpha + pixel[0] *| under_alpha *| (255 -| over_alpha); + // const color2: u16 = intensity * over_alpha + pixel[1] *| under_alpha *| (255 -| over_alpha); + // const color3: u16 = intensity * over_alpha + pixel[2] *| under_alpha *| (255 -| over_alpha); + // pixel.* = .{ + // @intCast(color1 / 255), + // @intCast(color2 / 255), + // @intCast(color3 / 255), + // @intCast(blended_alpha / 255), + // }; } } } @@ -516,13 +531,12 @@ fn toplevelHandler(app: *App, header: wayland.Header, body: []const u32) !void { 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); - } + std.debug.assert(app.state == .run); + app.state.run.width = @intCast(width); + app.state.run.height = @intCast(height); + }, + .close => { + app.close(); }, else => { std.log.info("toplevel event: {}", .{event}); @@ -535,9 +549,11 @@ fn surfaceDesktopHandler(app: *App, header: wayland.Header, body: []const u32) ! 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; + + std.debug.assert(app.state == .run); + const pool = &app.state.run.pool; + const width = app.state.run.width; + const height = app.state.run.height; // render const canvas = try pool.getFramebuffer(.{ width, height }); @@ -549,17 +565,27 @@ fn surfaceDesktopHandler(app: *App, header: wayland.Header, body: []const u32) ! } } -fn pointerDesktopHandler(app: *App, header: wayland.Header, body: []const u32) !void { +fn touchHandler(app: *App, header: wayland.Header, body: []const u32) !void { + const event = try wayland.deserialize(wayland.core.Touch.Event, header, body); + _ = app; + switch (event) { + else => { + std.log.info("touch event: {}", .{event}); + }, + } +} + +fn pointerHandler(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); + app.state.run.mouse.x = @floatFromInt(enter.surface_x); + app.state.run.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); + app.state.run.mouse.x = @floatFromInt(motion.surface_x); + app.state.run.mouse.y = @floatFromInt(motion.surface_y); }, else => { std.log.info("pointer event: {}", .{event}); @@ -575,7 +601,7 @@ fn pointerDesktopHandler(app: *App, header: wayland.Header, body: []const u32) ! } } -fn keyboardDesktopHandler(app: *App, header: wayland.Header, body: []const u32) !void { +fn keyboardHandler(app: *App, header: wayland.Header, body: []const u32) !void { const event = try wayland.deserialize(wayland.core.Keyboard.Event, header, body); _ = app; switch (event) { @@ -596,6 +622,6 @@ fn keyboardDesktopHandler(app: *App, header: wayland.Header, body: []const u32) 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; + const pool = &app.state.run.pool; try pool.freeFramebuffer(header.object_id); }