Skip to content

Commit

Permalink
win32 gui: rework startup/hwnd sync
Browse files Browse the repository at this point in the history
  • Loading branch information
marler8997 authored and neurocyte committed Jan 7, 2025
1 parent ff7bdee commit 337b6ce
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 115 deletions.
3 changes: 2 additions & 1 deletion src/keybind/builtin/emacs.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@
"on_match_failure": "ignore",
"press": [
["ctrl+h ctrl+a", "open_help"],
["ctrl+x ctrl+f", "open_recent"],
["ctrl+x ctrl+f", "open_file"],
["ctrl+x b", "open_recent"],
["alt+x", "open_command_palette"],
["ctrl+x ctrl+c", "quit"]
]
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/vaxis/renderer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ logger: log.Logger,

loop: Loop,

pub fn init(allocator: std.mem.Allocator, handler_ctx: *anyopaque, no_alternate: bool) !Self {
pub fn init(allocator: std.mem.Allocator, handler_ctx: *anyopaque, no_alternate: bool, _: *const fn (ctx: *anyopaque) void) !Self {
const opts: vaxis.Vaxis.Options = .{
.kitty_keyboard_flags = .{
.disambiguate = true,
Expand Down
60 changes: 47 additions & 13 deletions src/renderer/win32/renderer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,17 @@ allocator: std.mem.Allocator,
vx: vaxis.Vaxis,

handler_ctx: *anyopaque,
dispatch_initialized: *const fn (ctx: *anyopaque) void,
dispatch_input: ?*const fn (ctx: *anyopaque, cbor_msg: []const u8) void = null,
dispatch_mouse: ?*const fn (ctx: *anyopaque, y: c_int, x: c_int, cbor_msg: []const u8) void = null,
dispatch_mouse_drag: ?*const fn (ctx: *anyopaque, y: c_int, x: c_int, cbor_msg: []const u8) void = null,
dispatch_event: ?*const fn (ctx: *anyopaque, cbor_msg: []const u8) void = null,

thread: ?std.Thread = null,

hwnd: ?win32.HWND = null,
title_buf: std.ArrayList(u16),
style: ?Style = null,

const global = struct {
var init_called: bool = false;
Expand All @@ -44,6 +47,7 @@ pub fn init(
allocator: std.mem.Allocator,
handler_ctx: *anyopaque,
no_alternate: bool,
dispatch_initialized: *const fn (ctx: *anyopaque) void,
) !Self {
std.debug.assert(!global.init_called);
global.init_called = true;
Expand All @@ -66,6 +70,7 @@ pub fn init(
.vx = try vaxis.init(allocator, opts),
.handler_ctx = handler_ctx,
.title_buf = std.ArrayList(u16).init(allocator),
.dispatch_initialized = dispatch_initialized,
};
result.vx.caps.unicode = .unicode;
result.vx.screen.width_method = .unicode;
Expand Down Expand Up @@ -122,9 +127,13 @@ pub fn fmtmsg(buf: []u8, value: anytype) []const u8 {

pub fn render(self: *Self) error{}!void {
_ = gui.updateScreen(&self.vx.screen);
if (self.hwnd) |hwnd| win32.invalidateHwnd(hwnd);
}
pub fn stop(self: *Self) void {
gui.stop();
// this is guaranteed because stop won't be called until after
// the window is created and we call dispatch_initialized
const hwnd = self.hwnd orelse unreachable;
gui.stop(hwnd);
if (self.thread) |thread| thread.join();
}

Expand Down Expand Up @@ -207,8 +216,6 @@ pub fn process_renderer_event(self: *Self, msg: []const u8) !void {
var buf: [200]u8 = undefined;
if (self.dispatch_event) |f| f(self.handler_ctx, fmtmsg(&buf, .{"resize"}));
}
if (self.title_buf.items.len > 0)
self.set_terminal_title_internal();
return;
}
}
Expand Down Expand Up @@ -308,30 +315,57 @@ pub fn process_renderer_event(self: *Self, msg: []const u8) !void {
return;
}
}
{
var hwnd: usize = undefined;
if (try cbor.match(msg, .{
cbor.any,
"WindowCreated",
cbor.extract(&hwnd),
})) {
std.debug.assert(self.hwnd == null);
self.hwnd = @ptrFromInt(hwnd);
self.dispatch_initialized(self.handler_ctx);
self.update_window_title();
self.update_window_style();
return;
}
}
return error.UnexpectedRendererEvent;
}

pub fn set_terminal_title(self: *Self, text: []const u8) void {
self.title_buf.clearRetainingCapacity();
std.unicode.utf8ToUtf16LeArrayList(&self.title_buf, text) catch {
std.log.err("title is invalid UTF-8", .{});
return;
};
self.set_terminal_title_internal();
self.update_window_title();
}

fn set_terminal_title_internal(self: *Self) void {
const title = self.title_buf.toOwnedSliceSentinel(0) catch @panic("OOM:set_terminal_title");
gui.set_window_title(title) catch {
// leave self.title_buf to try again later
fn update_window_title(self: *Self) void {
if (self.title_buf.items.len == 0) return;

// keep the title buf around if the window isn't created yet
const hwnd = self.hwnd orelse return;

const title = self.title_buf.toOwnedSliceSentinel(0) catch @panic("OOM:update_window_title");
if (win32.SetWindowTextW(hwnd, title) == 0) {
std.log.warn("SetWindowText failed with {}", .{win32.GetLastError().fmt()});
self.title_buf = std.ArrayList(u16).fromOwnedSlice(self.allocator, title);
return;
};
self.allocator.free(title);
} else {
self.allocator.free(title);
}
}

pub fn set_terminal_style(self: *Self, style_: Style) void {
_ = self;
if (style_.bg) |color| gui.set_window_background(@intCast(color.color));
self.style = style_;
self.update_window_style();
}
fn update_window_style(self: *Self) void {
const hwnd = self.hwnd orelse return;
if (self.style) |style_| {
if (style_.bg) |color| gui.set_window_background(hwnd, @intCast(color.color));
}
}

pub fn set_terminal_cursor_color(self: *Self, color: Color) void {
Expand Down
17 changes: 13 additions & 4 deletions src/tui/tui.zig
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ fn init(allocator: Allocator) !*Self {
self.* = .{
.allocator = allocator,
.config = conf,
.rdr = try renderer.init(allocator, self, tp.env.get().is("no-alternate")),
.rdr = try renderer.init(allocator, self, tp.env.get().is("no-alternate"), dispatch_initialized),
.frame_time = frame_time,
.frame_clock = frame_clock,
.frame_clock_running = true,
Expand All @@ -115,7 +115,9 @@ fn init(allocator: Allocator) !*Self {
.message_filters = MessageFilter.List.init(allocator),
.input_listeners = EventHandler.List.init(allocator),
.logger = log.logger("tui"),
.init_timer = try tp.timeout.init_ms(init_delay, tp.message.fmt(.{"init"})),
.init_timer = if (build_options.gui) null else try tp.timeout.init_ms(init_delay, tp.message.fmt(
.{"init"},
)),
.theme = theme,
.no_sleep = tp.env.get().is("no-sleep"),
};
Expand Down Expand Up @@ -339,7 +341,7 @@ fn receive_safe(self: *Self, from: tp.pid_ref, m: tp.message) !void {
if (self.init_timer) |*timer| {
timer.deinit();
self.init_timer = null;
} else {
} else if (!build_options.gui) {
return tp.unexpected(m);
}
return;
Expand Down Expand Up @@ -446,6 +448,13 @@ fn dispatch_flush_input_event(self: *Self) !void {
if (mode.event_handler) |eh| try eh.send(tp.self_pid(), try tp.message.fmtbuf(&buf, .{"F"}));
}

fn dispatch_initialized(ctx: *anyopaque) void {
_ = ctx;
tp.self_pid().send(.{"init"}) catch |e| switch (e) {
error.Exit => {}, // safe to ignore
};
}

fn dispatch_input(ctx: *anyopaque, cbor_msg: []const u8) void {
const self: *Self = @ptrCast(@alignCast(ctx));
const m: tp.message = .{ .buf = cbor_msg };
Expand Down Expand Up @@ -1109,7 +1118,7 @@ pub const fallbacks: []const FallBack = &[_]FallBack{
};

fn set_terminal_style(self: *Self) void {
if (self.config.enable_terminal_color_scheme) {
if (build_options.gui or self.config.enable_terminal_color_scheme) {
self.rdr.set_terminal_style(self.theme.editor);
self.rdr.set_terminal_cursor_color(self.theme.editor_cursor.bg.?);
}
Expand Down
Loading

0 comments on commit 337b6ce

Please sign in to comment.