const std = @import("std"); // const vk = @import("vk"); // const c = @import("../c.zig"); // const Window = @import("../au.zig").Window; const Self = @This(); const Window = @import("Window.zig"); const c = Window.c; alloc: std.mem.Allocator, events: std.ArrayListUnmanaged(Event) = .{}, // todo bounded array? drops: std.ArrayListUnmanaged([][]const u8) = .{}, // todo bounded array? pub fn init(alloc: std.mem.Allocator) Self { return .{ .alloc = alloc, }; } pub fn deinit(self: *Self) void { self.clear(); self.events.deinit(self.alloc); self.drops.deinit(self.alloc); } pub fn connect(self: *Self, handle: *c.GLFWwindow) void { // todo somehow prevent double-connect? c.glfwSetWindowUserPointer(handle, self); _ = c.glfwSetWindowPosCallback(handle, onWindowPos); _ = c.glfwSetWindowSizeCallback(handle, onWindowSize); _ = c.glfwSetWindowCloseCallback(handle, onWindowClose); _ = c.glfwSetWindowRefreshCallback(handle, onWindowRefresh); _ = c.glfwSetWindowFocusCallback(handle, onWindowFocus); _ = c.glfwSetWindowIconifyCallback(handle, onWindowIconify); _ = c.glfwSetWindowMaximizeCallback(handle, onWindowMaximize); _ = c.glfwSetFramebufferSizeCallback(handle, onFramebufferSize); _ = c.glfwSetWindowContentScaleCallback(handle, onWindowContentScale); _ = c.glfwSetMouseButtonCallback(handle, onMouseButton); _ = c.glfwSetCursorPosCallback(handle, onCursorPos); _ = c.glfwSetCursorEnterCallback(handle, onCursorEnter); _ = c.glfwSetScrollCallback(handle, onScroll); _ = c.glfwSetKeyCallback(handle, onKey); _ = c.glfwSetCharModsCallback(handle, onCharMods); _ = c.glfwSetDropCallback(handle, onDrop); } pub fn disconnect(_: *Self, handle: *c.GLFWwindow) void { // todo somehow prevent double-disconnect? c.glfwSetWindowUserPointer(handle, null); _ = c.glfwSetWindowPosCallback(handle, null); _ = c.glfwSetWindowSizeCallback(handle, null); _ = c.glfwSetWindowCloseCallback(handle, null); _ = c.glfwSetWindowRefreshCallback(handle, null); _ = c.glfwSetWindowFocusCallback(handle, null); _ = c.glfwSetWindowIconifyCallback(handle, null); _ = c.glfwSetWindowMaximizeCallback(handle, null); _ = c.glfwSetFramebufferSizeCallback(handle, null); _ = c.glfwSetWindowContentScaleCallback(handle, null); _ = c.glfwSetMouseButtonCallback(handle, null); _ = c.glfwSetCursorPosCallback(handle, null); _ = c.glfwSetCursorEnterCallback(handle, null); _ = c.glfwSetScrollCallback(handle, null); _ = c.glfwSetKeyCallback(handle, null); _ = c.glfwSetCharModsCallback(handle, null); _ = c.glfwSetDropCallback(handle, null); } pub fn clear(self: *Self) void { for (self.drops.items) |drop| { for (drop) |path| { self.alloc.free(path); } self.alloc.free(drop); } self.drops.clearAndFree(self.alloc); self.events.clearRetainingCapacity(); } fn getBus(handle: ?*c.GLFWwindow) *Self { return @alignCast(@ptrCast(c.glfwGetWindowUserPointer(handle))); } pub const Event = union(enum) { const WindowPos = struct { x: i32, y: i32 }; const WindowSize = struct { x: i32, y: i32 }; const WindowClose = struct {}; const WindowRefresh = struct {}; const WindowFocus = struct { focused: bool }; const WindowIconify = struct { iconified: bool }; const WindowMaximize = struct { maximized: bool }; const FramebufferSize = struct { width: u32, height: u32 }; const WindowContentScale = struct { x: f32, y: f32 }; const MouseButton = struct { button: c_int, // todo enum action: c_int, // todo enum mods: c_int, // todo bitmask }; const CursorPos = struct { x: f64, y: f64 }; const CursorEnter = struct { entered: bool }; const Scroll = struct { dx: f64, dy: f64 }; const Key = struct { key: c_int, // todo enum scan: c_int, // todo ??? action: c_int, // todo enum mods: c_int, // todo bitmask }; const Char = struct { code: u21, }; const CharMods = struct { code: u21, mods: c_int, // todo bitmask }; const Drop = struct { paths: []const []const u8, }; windowPos: WindowPos, windowSize: WindowSize, windowClose: WindowClose, windowRefresh: WindowRefresh, windowFocus: WindowFocus, windowIconify: WindowIconify, windowMaximize: WindowMaximize, framebufferSize: FramebufferSize, windowContentScale: WindowContentScale, mouseButton: MouseButton, cursorPos: CursorPos, cursorEnter: CursorEnter, scroll: Scroll, key: Key, char: Char, charMods: CharMods, drop: Drop, }; fn onWindowPos(handle: ?*c.GLFWwindow, x: c_int, y: c_int) callconv(.C) void { const bus = getBus(handle); bus.events.append(bus.alloc, .{ .windowPos = .{ .x = @intCast(x), .y = @intCast(y), }, }) catch unreachable; // todo circular queue; warn } fn onWindowSize(handle: ?*c.GLFWwindow, x: c_int, y: c_int) callconv(.C) void { const bus = getBus(handle); bus.events.append(bus.alloc, .{ .windowSize = .{ .x = @intCast(x), .y = @intCast(y), }, }) catch unreachable; // todo circular queue; warn } fn onWindowClose(handle: ?*c.GLFWwindow) callconv(.C) void { const bus = getBus(handle); bus.events.append(bus.alloc, .{ .windowClose = .{}, }) catch unreachable; // todo circular queue; warn } fn onWindowRefresh(handle: ?*c.GLFWwindow) callconv(.C) void { const bus = getBus(handle); bus.events.append(bus.alloc, .{ .windowRefresh = .{}, }) catch unreachable; // todo circular queue; warn } fn onWindowFocus(handle: ?*c.GLFWwindow, focused: c_int) callconv(.C) void { const bus = getBus(handle); bus.events.append(bus.alloc, .{ .windowFocus = .{ .focused = focused == c.GLFW_TRUE, }, }) catch unreachable; // todo circular queue; warn } fn onWindowIconify(handle: ?*c.GLFWwindow, iconified: c_int) callconv(.C) void { const bus = getBus(handle); bus.events.append(bus.alloc, .{ .windowIconify = .{ .iconified = iconified == c.GLFW_TRUE, }, }) catch unreachable; // todo circular queue; warn } fn onWindowMaximize(handle: ?*c.GLFWwindow, maximized: c_int) callconv(.C) void { const bus = getBus(handle); bus.events.append(bus.alloc, .{ .windowMaximize = .{ .maximized = maximized == c.GLFW_TRUE, }, }) catch unreachable; // todo circular queue; warn } fn onFramebufferSize(handle: ?*c.GLFWwindow, width: c_int, height: c_int) callconv(.C) void { const bus = getBus(handle); bus.events.append(bus.alloc, .{ .framebufferSize = .{ .width = @intCast(width), .height = @intCast(height), }, }) catch unreachable; // todo circular queue; warn } fn onWindowContentScale(handle: ?*c.GLFWwindow, x: f32, y: f32) callconv(.C) void { const bus = getBus(handle); bus.events.append(bus.alloc, .{ .windowContentScale = .{ .x = x, .y = y, }, }) catch unreachable; // todo circular queue; warn } fn onMouseButton(handle: ?*c.GLFWwindow, button: c_int, action: c_int, mods: c_int) callconv(.C) void { const bus = getBus(handle); bus.events.append(bus.alloc, .{ .mouseButton = .{ .button = button, .action = action, .mods = mods, }, }) catch unreachable; // todo circular queue; warn } fn onCursorPos(handle: ?*c.GLFWwindow, x: f64, y: f64) callconv(.C) void { const bus = getBus(handle); bus.events.append(bus.alloc, .{ .cursorPos = .{ .x = x, .y = y, }, }) catch unreachable; // todo circular queue; warn } fn onCursorEnter(handle: ?*c.GLFWwindow, entered: c_int) callconv(.C) void { const bus = getBus(handle); bus.events.append(bus.alloc, .{ .cursorEnter = .{ .entered = entered == c.GLFW_TRUE, }, }) catch unreachable; // todo circular queue; warn } fn onScroll(handle: ?*c.GLFWwindow, dx: f64, dy: f64) callconv(.C) void { const bus = getBus(handle); bus.events.append(bus.alloc, .{ .scroll = .{ .dx = dx, .dy = dy, }, }) catch unreachable; // todo circular queue; warn } fn onKey(handle: ?*c.GLFWwindow, key: c_int, scan: c_int, action: c_int, mods: c_int) callconv(.C) void { const bus = getBus(handle); bus.events.append(bus.alloc, .{ .key = .{ .key = key, .scan = scan, .action = action, .mods = mods, }, }) catch unreachable; // todo circular queue; warn } fn onCharMods(handle: ?*c.GLFWwindow, code: c_uint, mods: c_int) callconv(.C) void { const bus = getBus(handle); bus.events.append(bus.alloc, .{ .charMods = .{ .code = @intCast(code), .mods = mods, }, }) catch unreachable; // todo circular queue; warn } fn onDrop(handle: ?*c.GLFWwindow, count: c_int, paths: [*c][*c]const u8) callconv(.C) void { const bus = getBus(handle); const drops = bus.alloc.alloc([]const u8, @intCast(count)) catch unreachable; // todo warn for (drops, paths) |*dst, src| { dst.* = bus.alloc.dupe(u8, std.mem.sliceTo(src, 0)) catch unreachable; // todo warn } bus.drops.append(bus.alloc, drops) catch unreachable; // todo warn bus.events.append(bus.alloc, .{ .drop = .{ .paths = drops }, }) catch unreachable; // todo circular queue; warn }