From 1db780c7a7016658260df31ae63852985709608d Mon Sep 17 00:00:00 2001 From: AnErrupTion Date: Sun, 8 Feb 2026 22:18:00 +0100 Subject: [PATCH] Better handle screen resizes Signed-off-by: AnErrupTion --- src/main.zig | 68 +++++++++++++++++--------------------- src/tui/TerminalBuffer.zig | 14 +++++--- 2 files changed, 39 insertions(+), 43 deletions(-) diff --git a/src/main.zig b/src/main.zig index f7e5777..f8dbcbd 100644 --- a/src/main.zig +++ b/src/main.zig @@ -856,35 +856,37 @@ pub fn main() !void { } while (run) { - // If there's no input or there's an animation, a resolution change needs to be checked - if (!state.update or state.animate or config.bigclock != .none or config.clock != null) { - if (!state.update) std.Thread.sleep(std.time.ns_per_ms * 100); + if (state.resolution_changed) { + state.buffer.width = TerminalBuffer.getWidthStatic(); + state.buffer.height = TerminalBuffer.getHeightStatic(); - // Required to update tb_width() and tb_height() - const new_dimensions = TerminalBuffer.presentBufferStatic(); - const width = new_dimensions.width; - const height = new_dimensions.height; + try log_file.info("tui", "screen resolution updated to {d}x{d}", .{ state.buffer.width, state.buffer.height }); - if (width != state.buffer.width or height != state.buffer.height) { - // If it did change, then update the cell buffer, reallocate the current animation's buffers, and force a draw update - try log_file.info("tui", "screen resolution updated to {d}x{d}", .{ width, height }); + if (state.animation.*) |*a| a.realloc() catch |err| { + try info_line.addMessage(lang.err_alloc, config.error_bg, config.error_fg); + try log_file.err("tui", "failed to reallocate animation buffers: {s}", .{@errorName(err)}); + }; - state.buffer.width = width; - state.buffer.height = height; + positionComponents(&state); - if (state.animation.*) |*a| a.realloc() catch |err| { - try info_line.addMessage(lang.err_alloc, config.error_bg, config.error_fg); - try log_file.err("tui", "failed to reallocate animation buffers: {s}", .{@errorName(err)}); - }; - - state.update = true; - state.resolution_changed = true; - } + state.update = true; + state.resolution_changed = false; } if (state.update) { try updateComponents(&state); - if (!try drawUi(&log_file, &state)) continue; + + switch (state.active_input) { + .info_line => state.info_line.label.handle(null, state.insert_mode), + .session => state.session.label.handle(null, state.insert_mode), + .login => state.login.label.handle(null, state.insert_mode), + .password => state.password.handle(null, state.insert_mode) catch |err| { + try state.info_line.addMessage(state.lang.err_alloc, state.config.error_bg, state.config.error_fg); + try log_file.err("tui", "failed to handle password input: {s}", .{@errorName(err)}); + }, + } + + if (!try drawUi(&state)) continue; } var timeout: i32 = -1; @@ -949,7 +951,12 @@ pub fn main() !void { state.update = timeout != -1; - if (event_error < 0 or event.type != termbox.TB_EVENT_KEY) continue; + if (event_error < 0) continue; + } + + if (event.type == termbox.TB_EVENT_RESIZE) { + state.resolution_changed = true; + continue; } // Input of some kind was detected, so reset the inactivity timer @@ -1236,7 +1243,7 @@ fn updateComponents(state: *UiState) !void { } } -fn drawUi(log_file: *LogFile, state: *UiState) !bool { +fn drawUi(state: *UiState) !bool { // If the user entered a wrong password 10 times in a row, play a cascade animation, else update normally if (state.config.auth_fails > 0 and state.auth_fails >= state.config.auth_fails) { std.Thread.sleep(std.time.ns_per_ms * 10); @@ -1260,21 +1267,6 @@ fn drawUi(log_file: *LogFile, state: *UiState) !bool { state.box.draw(); - if (state.resolution_changed) { - positionComponents(state); - state.resolution_changed = false; - } - - switch (state.active_input) { - .info_line => state.info_line.label.handle(null, state.insert_mode), - .session => state.session.label.handle(null, state.insert_mode), - .login => state.login.label.handle(null, state.insert_mode), - .password => state.password.handle(null, state.insert_mode) catch |err| { - try state.info_line.addMessage(state.lang.err_alloc, state.config.error_bg, state.config.error_fg); - try log_file.err("tui", "failed to handle password input: {s}", .{@errorName(err)}); - }, - } - if (state.config.clock != null) state.clock_label.draw(); state.session_specifier_label.draw(); diff --git a/src/tui/TerminalBuffer.zig b/src/tui/TerminalBuffer.zig index 7f62d14..391fc60 100644 --- a/src/tui/TerminalBuffer.zig +++ b/src/tui/TerminalBuffer.zig @@ -133,6 +133,14 @@ pub fn init(options: InitOptions, log_file: *LogFile, random: Random) !TerminalB }; } +pub fn getWidthStatic() usize { + return @intCast(termbox.tb_width()); +} + +pub fn getHeightStatic() usize { + return @intCast(termbox.tb_height()); +} + pub fn setCursorStatic(x: usize, y: usize) void { _ = termbox.tb_set_cursor(@intCast(x), @intCast(y)); } @@ -146,12 +154,8 @@ pub fn shutdownStatic() void { _ = termbox.tb_shutdown(); } -pub fn presentBufferStatic() struct { width: usize, height: usize } { +pub fn presentBufferStatic() void { _ = termbox.tb_present(); - return .{ - .width = @intCast(termbox.tb_width()), - .height = @intCast(termbox.tb_height()), - }; } pub fn reclaim(self: TerminalBuffer) !void {