fix: update win32 gui build for zig-0.15

This commit is contained in:
CJ van den Berg 2025-10-01 17:00:10 +02:00
parent 6da6af22c8
commit f29eac4f6f
Signed by: neurocyte
GPG key ID: 8EB1E1BB660E3FB9
3 changed files with 34 additions and 53 deletions

View file

@ -16,7 +16,6 @@ const win32 = @import("win32").everything;
pub const Cell = @import("tuirenderer").Cell; pub const Cell = @import("tuirenderer").Cell;
pub const StyleBits = @import("tuirenderer").style; pub const StyleBits = @import("tuirenderer").style;
const gui = @import("gui"); const gui = @import("gui");
const DropWriter = gui.DropWriter;
pub const style = StyleBits; pub const style = StyleBits;
pub const styles = @import("tuirenderer").styles; pub const styles = @import("tuirenderer").styles;
@ -38,6 +37,7 @@ pub const Error = error{
BadArrayAllocExtract, BadArrayAllocExtract,
InvalidMapType, InvalidMapType,
InvalidUnion, InvalidUnion,
WriteFailed,
} || std.Thread.SpawnError; } || std.Thread.SpawnError;
pub const panic = messageBoxThenPanic(.{ .title = "Flow Panic" }); pub const panic = messageBoxThenPanic(.{ .title = "Flow Panic" });
@ -49,7 +49,7 @@ fn messageBoxThenPanic(
style: win32.MESSAGEBOX_STYLE = .{ .ICONASTERISK = 1 }, style: win32.MESSAGEBOX_STYLE = .{ .ICONASTERISK = 1 },
// TODO: add option/logic to include the stacktrace in the messagebox // TODO: add option/logic to include the stacktrace in the messagebox
}, },
) std.builtin.PanicFn { ) fn ([]const u8, ?*std.builtin.StackTrace, ?usize) noreturn {
return struct { return struct {
pub fn panic( pub fn panic(
msg: []const u8, msg: []const u8,
@ -59,10 +59,11 @@ fn messageBoxThenPanic(
if (!thread_is_panicing) { if (!thread_is_panicing) {
thread_is_panicing = true; thread_is_panicing = true;
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
const msg_z: [:0]const u8 = if (std.fmt.allocPrintZ( const msg_z: [:0]const u8 = if (std.fmt.allocPrintSentinel(
arena.allocator(), arena.allocator(),
"{s}", "{s}",
.{msg}, .{msg},
0,
)) |msg_z| msg_z else |_| "failed allocate error message"; )) |msg_z| msg_z else |_| "failed allocate error message";
_ = win32.MessageBoxA(null, msg_z, opt.title, opt.style); _ = win32.MessageBoxA(null, msg_z, opt.title, opt.style);
} }
@ -74,6 +75,8 @@ fn messageBoxThenPanic(
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
vx: vaxis.Vaxis, vx: vaxis.Vaxis,
event_buffer: std.Io.Writer.Allocating,
handler_ctx: *anyopaque, handler_ctx: *anyopaque,
dispatch_initialized: *const fn (ctx: *anyopaque) void, dispatch_initialized: *const fn (ctx: *anyopaque) void,
dispatch_input: ?*const fn (ctx: *anyopaque, cbor_msg: []const u8) void = null, dispatch_input: ?*const fn (ctx: *anyopaque, cbor_msg: []const u8) void = null,
@ -84,7 +87,7 @@ dispatch_event: ?*const fn (ctx: *anyopaque, cbor_msg: []const u8) void = null,
thread: ?std.Thread = null, thread: ?std.Thread = null,
hwnd: ?win32.HWND = null, hwnd: ?win32.HWND = null,
title_buf: std.ArrayList(u16), title_buf: std.array_list.Managed(u16),
style_: ?Style = null, style_: ?Style = null,
const global = struct { const global = struct {
@ -120,8 +123,9 @@ pub fn init(
var result: Self = .{ var result: Self = .{
.allocator = allocator, .allocator = allocator,
.vx = try vaxis.init(allocator, opts), .vx = try vaxis.init(allocator, opts),
.event_buffer = .init(allocator),
.handler_ctx = handler_ctx, .handler_ctx = handler_ctx,
.title_buf = std.ArrayList(u16).init(allocator), .title_buf = .init(allocator),
.dispatch_initialized = dispatch_initialized, .dispatch_initialized = dispatch_initialized,
}; };
result.vx.caps.unicode = .unicode; result.vx.caps.unicode = .unicode;
@ -131,31 +135,30 @@ pub fn init(
pub fn deinit(self: *Self) void { pub fn deinit(self: *Self) void {
std.debug.assert(self.thread == null); std.debug.assert(self.thread == null);
var drop_writer = DropWriter{}; var drop: std.Io.Writer.Discarding = .init(&.{});
self.vx.deinit(self.allocator, drop_writer.writer().any()); self.vx.deinit(self.allocator, &drop.writer);
self.title_buf.deinit(); self.title_buf.deinit();
self.event_buffer.deinit();
} }
pub fn run(self: *Self) Error!void { pub fn run(self: *Self) Error!void {
if (self.thread) |_| return; if (self.thread) |_| return;
// dummy resize to fully init vaxis // dummy resize to fully init vaxis
const drop_writer = DropWriter{}; var drop: std.Io.Writer.Discarding = .init(&.{});
self.vx.resize( self.vx.resize(
self.allocator, self.allocator,
drop_writer.writer().any(), &drop.writer,
.{ .rows = 25, .cols = 80, .x_pixel = 0, .y_pixel = 0 }, .{ .rows = 25, .cols = 80, .x_pixel = 0, .y_pixel = 0 },
) catch return error.VaxisResizeError; ) catch return error.VaxisResizeError;
self.thread = try gui.start(); self.thread = try gui.start();
} }
pub fn fmtmsg(buf: []u8, value: anytype) []const u8 { fn fmtmsg(self: *Self, value: anytype) std.Io.Writer.Error![]const u8 {
var fbs = std.io.fixedBufferStream(buf); self.event_buffer.clearRetainingCapacity();
cbor.writeValue(fbs.writer(), value) catch |e| switch (e) { try cbor.writeValue(&self.event_buffer.writer, value);
error.NoSpaceLeft => std.debug.panic("buffer of size {} not big enough", .{buf.len}), return self.event_buffer.written();
};
return buf[0..fbs.pos];
} }
pub fn render(self: *Self) error{}!void { pub fn render(self: *Self) error{}!void {
@ -216,8 +219,7 @@ pub fn process_renderer_event(self: *Self, msg: []const u8) Error!void {
cbor.extract(&args.text), cbor.extract(&args.text),
cbor.extract(&args.mods), cbor.extract(&args.mods),
})) { })) {
var buf: [300]u8 = undefined; const cbor_msg = try self.fmtmsg(.{
const cbor_msg = fmtmsg(&buf, .{
"I", "I",
args.kind, args.kind,
args.codepoint, args.codepoint,
@ -240,8 +242,8 @@ pub fn process_renderer_event(self: *Self, msg: []const u8) Error!void {
cbor.extract(&args.pixel_width), cbor.extract(&args.pixel_width),
cbor.extract(&args.pixel_height), cbor.extract(&args.pixel_height),
})) { })) {
var drop_writer = DropWriter{}; var drop: std.Io.Writer.Discarding = .init(&.{});
self.vx.resize(self.allocator, drop_writer.writer().any(), .{ self.vx.resize(self.allocator, &drop.writer, .{
.rows = @intCast(args.cell_height), .rows = @intCast(args.cell_height),
.cols = @intCast(args.cell_width), .cols = @intCast(args.cell_width),
.x_pixel = @intCast(args.pixel_width), .x_pixel = @intCast(args.pixel_width),
@ -249,8 +251,7 @@ pub fn process_renderer_event(self: *Self, msg: []const u8) Error!void {
}) catch |err| std.debug.panic("resize failed with {s}", .{@errorName(err)}); }) catch |err| std.debug.panic("resize failed with {s}", .{@errorName(err)});
self.vx.queueRefresh(); self.vx.queueRefresh();
{ {
var buf: [200]u8 = undefined; if (self.dispatch_event) |f| f(self.handler_ctx, try self.fmtmsg(.{"resize"}));
if (self.dispatch_event) |f| f(self.handler_ctx, fmtmsg(&buf, .{"resize"}));
} }
return; return;
} }
@ -265,12 +266,11 @@ pub fn process_renderer_event(self: *Self, msg: []const u8) Error!void {
cbor.extract(&args.xoffset), cbor.extract(&args.xoffset),
cbor.extract(&args.yoffset), cbor.extract(&args.yoffset),
})) { })) {
var buf: [200]u8 = undefined;
if (self.dispatch_mouse) |f| f( if (self.dispatch_mouse) |f| f(
self.handler_ctx, self.handler_ctx,
@intCast(args.row), @intCast(args.row),
@intCast(args.col), @intCast(args.col),
fmtmsg(&buf, .{ try self.fmtmsg(.{
"M", "M",
args.col, args.col,
args.row, args.row,
@ -299,12 +299,11 @@ pub fn process_renderer_event(self: *Self, msg: []const u8) Error!void {
cbor.extract(&args.pos.xoffset), cbor.extract(&args.pos.xoffset),
cbor.extract(&args.pos.yoffset), cbor.extract(&args.pos.yoffset),
})) { })) {
var buf: [200]u8 = undefined;
if (self.dispatch_mouse) |f| f( if (self.dispatch_mouse) |f| f(
self.handler_ctx, self.handler_ctx,
@intCast(args.pos.row), @intCast(args.pos.row),
@intCast(args.pos.col), @intCast(args.pos.col),
fmtmsg(&buf, .{ try self.fmtmsg(.{
"B", "B",
args.button.press, args.button.press,
args.button.id, args.button.id,
@ -332,12 +331,11 @@ pub fn process_renderer_event(self: *Self, msg: []const u8) Error!void {
cbor.extract(&args.pos.xoffset), cbor.extract(&args.pos.xoffset),
cbor.extract(&args.pos.yoffset), cbor.extract(&args.pos.yoffset),
})) { })) {
var buf: [200]u8 = undefined;
if (self.dispatch_mouse_drag) |f| f( if (self.dispatch_mouse_drag) |f| f(
self.handler_ctx, self.handler_ctx,
@intCast(args.pos.row), @intCast(args.pos.row),
@intCast(args.pos.col), @intCast(args.pos.col),
fmtmsg(&buf, .{ try self.fmtmsg(.{
"D", "D",
input.event.press, input.event.press,
args.button_id, args.button_id,
@ -386,8 +384,8 @@ fn update_window_title(self: *Self) void {
const title = self.title_buf.toOwnedSliceSentinel(0) catch @panic("OOM:update_window_title"); const title = self.title_buf.toOwnedSliceSentinel(0) catch @panic("OOM:update_window_title");
if (win32.SetWindowTextW(hwnd, title) == 0) { if (win32.SetWindowTextW(hwnd, title) == 0) {
std.log.warn("SetWindowText failed, error={}", .{win32.GetLastError()}); std.log.warn("SetWindowText failed, error={f}", .{win32.GetLastError()});
self.title_buf = std.ArrayList(u16).fromOwnedSlice(self.allocator, title); self.title_buf = .fromOwnedSlice(self.allocator, title);
} else { } else {
self.allocator.free(title); self.allocator.free(title);
} }

View file

@ -42,7 +42,7 @@ pub const Font = struct {
&text_format_single, &text_format_single,
); );
if (hr < 0) std.debug.panic( if (hr < 0) std.debug.panic(
"CreateTextFormat '{}' height {d} failed, hresult=0x{x}", "CreateTextFormat '{f}' height {d} failed, hresult=0x{x}",
.{ std.unicode.fmtUtf16Le(face.slice()), size, @as(u32, @bitCast(hr)) }, .{ std.unicode.fmtUtf16Le(face.slice()), size, @as(u32, @bitCast(hr)) },
); );
} }
@ -61,7 +61,7 @@ pub const Font = struct {
&text_format_double, &text_format_double,
); );
if (hr < 0) std.debug.panic( if (hr < 0) std.debug.panic(
"CreateTextFormat '{}' height {d} failed, hresult=0x{x}", "CreateTextFormat '{f}' height {d} failed, hresult=0x{x}",
.{ std.unicode.fmtUtf16Le(face.slice()), size, @as(u32, @bitCast(hr)) }, .{ std.unicode.fmtUtf16Le(face.slice()), size, @as(u32, @bitCast(hr)) },
); );
} }

View file

@ -43,18 +43,6 @@ const WM_APP_RESET_FONTFACE_RESULT = 0x0101f996;
const WM_APP_GET_FONTFACES_RESULT = 0x07e228f5; const WM_APP_GET_FONTFACES_RESULT = 0x07e228f5;
const WM_APP_UPDATE_SCREEN_RESULT = 0x3add213b; const WM_APP_UPDATE_SCREEN_RESULT = 0x3add213b;
pub const DropWriter = struct {
pub const WriteError = error{};
pub const Writer = std.io.Writer(DropWriter, WriteError, write);
pub fn writer(self: DropWriter) Writer {
return .{ .context = self };
}
pub fn write(self: DropWriter, bytes: []const u8) WriteError!usize {
_ = self;
return bytes.len;
}
};
fn oom(e: error{OutOfMemory}) noreturn { fn oom(e: error{OutOfMemory}) noreturn {
@panic(@errorName(e)); @panic(@errorName(e));
} }
@ -266,7 +254,7 @@ fn calcWindowPlacement(
var info: win32.MONITORINFO = undefined; var info: win32.MONITORINFO = undefined;
info.cbSize = @sizeOf(win32.MONITORINFO); info.cbSize = @sizeOf(win32.MONITORINFO);
if (0 == win32.GetMonitorInfoW(monitor, &info)) { if (0 == win32.GetMonitorInfoW(monitor, &info)) {
std.log.warn("GetMonitorInfo failed, error={}", .{win32.GetLastError()}); std.log.warn("GetMonitorInfo failed, error={f}", .{win32.GetLastError()});
return result; return result;
} }
break :blk info.rcWork; break :blk info.rcWork;
@ -333,7 +321,7 @@ fn entry(pid: thespian.pid) !void {
}, },
win32.MONITOR_DEFAULTTOPRIMARY, win32.MONITOR_DEFAULTTOPRIMARY,
) orelse { ) orelse {
std.log.warn("MonitorFromPoint failed, error={}", .{win32.GetLastError()}); std.log.warn("MonitorFromPoint failed, error={f}", .{win32.GetLastError()});
break :blk null; break :blk null;
}; };
}; };
@ -423,7 +411,7 @@ fn entry(pid: thespian.pid) !void {
@sizeOf(@TypeOf(dark_value)), @sizeOf(@TypeOf(dark_value)),
); );
if (hr < 0) std.log.warn( if (hr < 0) std.log.warn(
"DwmSetWindowAttribute for dark={} failed, error={}", "DwmSetWindowAttribute for dark={} failed, error={f}",
.{ dark_value, win32.GetLastError() }, .{ dark_value, win32.GetLastError() },
); );
} }
@ -826,7 +814,7 @@ fn sendKey(
} }
if (unicode_result == 0) { if (unicode_result == 0) {
std.log.warn("unknown virtual key {} (0x{x})", .{ winkey, winkey.vk }); std.log.warn("unknown virtual key {f} (0x{x})", .{ winkey, winkey.vk });
return; return;
} }
for (char_buf[0..@intCast(unicode_result)]) |codepoint| { for (char_buf[0..@intCast(unicode_result)]) |codepoint| {
@ -861,12 +849,8 @@ const WinKey = struct {
} }
pub fn format( pub fn format(
self: WinKey, self: WinKey,
comptime fmt: []const u8,
options: std.fmt.FormatOptions,
writer: anytype, writer: anytype,
) !void { ) !void {
_ = fmt;
_ = options;
const e_suffix: []const u8 = if (self.extended) "e" else ""; const e_suffix: []const u8 = if (self.extended) "e" else "";
try writer.print("{}{s}", .{ self.vk, e_suffix }); try writer.print("{}{s}", .{ self.vk, e_suffix });
} }
@ -1008,7 +992,7 @@ fn WndProc(
msg: u32, msg: u32,
wparam: win32.WPARAM, wparam: win32.WPARAM,
lparam: win32.LPARAM, lparam: win32.LPARAM,
) callconv(std.os.windows.WINAPI) win32.LRESULT { ) callconv(.winapi) win32.LRESULT {
const frame = tracy.initZone(@src(), .{ .name = "gui WndProc" }); const frame = tracy.initZone(@src(), .{ .name = "gui WndProc" });
defer frame.deinit(); defer frame.deinit();
var msg_node: windowmsg.MessageNode = undefined; var msg_node: windowmsg.MessageNode = undefined;
@ -1291,7 +1275,6 @@ fn WndProc(
.cursor_row = screen.cursor_row, .cursor_row = screen.cursor_row,
.cursor_col = screen.cursor_col, .cursor_col = screen.cursor_col,
.cursor_vis = screen.cursor_vis, .cursor_vis = screen.cursor_vis,
.unicode = undefined,
.width_method = undefined, .width_method = undefined,
.mouse_shape = screen.mouse_shape, .mouse_shape = screen.mouse_shape,
.cursor_shape = undefined, .cursor_shape = undefined,