Handle termbox2 errors

Signed-off-by: AnErrupTion <anerruption@disroot.org>
This commit is contained in:
AnErrupTion
2026-05-17 13:26:46 +02:00
parent 05c1d4bece
commit 4c066ce564
17 changed files with 114 additions and 90 deletions

View File

@@ -14,8 +14,8 @@ pub fn init(ch: u32, fg: u32, bg: u32) Cell {
};
}
pub fn put(self: Cell, x: usize, y: usize) void {
pub fn put(self: Cell, x: usize, y: usize) !void {
if (self.ch == 0) return;
TerminalBuffer.setCell(x, y, self);
try TerminalBuffer.setCell(x, y, self);
}

View File

@@ -103,24 +103,39 @@ pub fn init(
random: Random,
) !TerminalBuffer {
// Initialize termbox
_ = termbox.tb_init();
if (termbox.tb_init() != 0) return error.TermboxInitFailed;
if (options.full_color) {
_ = termbox.tb_set_output_mode(termbox.TB_OUTPUT_TRUECOLOR);
try log_file.info(io, "tui", "termbox2 set to 24-bit color output mode", .{});
if (termbox.tb_set_output_mode(termbox.TB_OUTPUT_TRUECOLOR) != 0) {
return error.TermboxSetOutputModeFailed;
}
try log_file.info(
io,
"tui",
"termbox2 set to 24-bit color output mode",
.{},
);
} else {
try log_file.info(io, "tui", "termbox2 set to eight-color output mode", .{});
try log_file.info(
io,
"tui",
"termbox2 set to eight-color output mode",
.{},
);
}
_ = termbox.tb_clear();
// Let's take some precautions here and clear the back buffer as well
try clearBackBuffer();
try clearScreen(true);
const width: usize = @intCast(termbox.tb_width());
const height: usize = @intCast(termbox.tb_height());
const width = getWidth();
const height = getHeight();
try log_file.info(io, "tui", "screen resolution is {d}x{d}", .{ width, height });
try log_file.info(
io,
"tui",
"screen resolution is {d}x{d}",
.{ width, height },
);
return .{
.log_file = log_file,
@@ -163,7 +178,7 @@ pub fn init(
pub fn deinit(self: *TerminalBuffer) void {
self.keybinds.deinit();
TerminalBuffer.shutdown();
TerminalBuffer.shutdown() catch {};
}
pub fn runEventLoop(
@@ -238,7 +253,7 @@ pub fn runEventLoop(
}
}
TerminalBuffer.presentBuffer();
try TerminalBuffer.presentBuffer();
}
if (inactivity_event_fn) |inactivity_fn| {
@@ -338,31 +353,35 @@ pub fn getHeight() usize {
return @intCast(termbox.tb_height());
}
pub fn setCursor(x: usize, y: usize) void {
_ = termbox.tb_set_cursor(@intCast(x), @intCast(y));
pub fn setCursor(x: usize, y: usize) !void {
if (termbox.tb_set_cursor(@intCast(x), @intCast(y)) != 0) {
return error.TermboxSetCursorFailed;
}
}
pub fn clearScreen(clear_back_buffer: bool) !void {
_ = termbox.tb_clear();
if (termbox.tb_clear() != 0) return error.TermboxClearFailed;
if (clear_back_buffer) try clearBackBuffer();
}
pub fn shutdown() void {
_ = termbox.tb_shutdown();
pub fn shutdown() !void {
if (termbox.tb_shutdown() != 0) return error.TermboxShutdownFailed;
}
pub fn presentBuffer() void {
_ = termbox.tb_present();
pub fn presentBuffer() !void {
if (termbox.tb_present() != 0) return error.TermboxPresentFailed;
}
pub fn getCell(x: usize, y: usize) ?Cell {
var maybe_cell: ?*termbox.tb_cell = undefined;
_ = termbox.tb_get_cell(
if (termbox.tb_get_cell(
@intCast(x),
@intCast(y),
1,
&maybe_cell,
);
) != 0) {
return null;
}
if (maybe_cell) |cell| {
return Cell.init(cell.ch, cell.fg, cell.bg);
@@ -371,29 +390,31 @@ pub fn getCell(x: usize, y: usize) ?Cell {
return null;
}
pub fn setCell(x: usize, y: usize, cell: Cell) void {
_ = termbox.tb_set_cell(
pub fn setCell(x: usize, y: usize, cell: Cell) !void {
if (termbox.tb_set_cell(
@intCast(x),
@intCast(y),
cell.ch,
cell.fg,
cell.bg,
);
) != 0) {
return error.TermboxSetCellFailed;
}
}
pub fn setCellBoundsChecked(self: *TerminalBuffer, x: isize, y: isize, cell: Cell) void {
pub fn setCellBoundsChecked(self: *TerminalBuffer, x: isize, y: isize, cell: Cell) !void {
if (0 <= x and x < self.width and 0 <= y and y < self.height) {
cell.put(@intCast(x), @intCast(y));
try cell.put(@intCast(x), @intCast(y));
}
}
pub fn reclaim(self: TerminalBuffer) !void {
if (self.termios) |termios| {
// Take back control of the TTY
_ = termbox.tb_init();
if (termbox.tb_init() != 0) return error.TermboxReinitFailed;
if (self.full_color) {
_ = termbox.tb_set_output_mode(termbox.TB_OUTPUT_TRUECOLOR);
if (self.full_color and termbox.tb_set_output_mode(termbox.TB_OUTPUT_TRUECOLOR) != 0) {
return error.TermboxSetOutputModeFailed;
}
try std.posix.tcsetattr(std.posix.STDIN_FILENO, .FLUSH, termios);
@@ -464,14 +485,14 @@ pub fn drawText(
y: usize,
fg: u32,
bg: u32,
) void {
const yc: c_int = @intCast(y);
) !void {
const utf8view = std.unicode.Utf8View.init(text) catch return;
var utf8 = utf8view.iterator();
var i: c_int = @intCast(x);
while (utf8.nextCodepoint()) |codepoint| : (i += termbox.tb_wcwidth(codepoint)) {
_ = termbox.tb_set_cell(i, yc, codepoint, fg, bg);
var i = x;
while (utf8.nextCodepoint()) |codepoint| : (i += @intCast(termbox.tb_wcwidth(codepoint))) {
const cell = Cell.init(codepoint, fg, bg);
try cell.put(i, y);
}
}
@@ -482,15 +503,16 @@ pub fn drawConfinedText(
max_length: usize,
fg: u32,
bg: u32,
) void {
const yc: c_int = @intCast(y);
) !void {
const utf8view = std.unicode.Utf8View.init(text) catch return;
var utf8 = utf8view.iterator();
var i: c_int = @intCast(x);
while (utf8.nextCodepoint()) |codepoint| : (i += termbox.tb_wcwidth(codepoint)) {
if (i - @as(c_int, @intCast(x)) >= max_length) break;
_ = termbox.tb_set_cell(i, yc, codepoint, fg, bg);
var i = x;
while (utf8.nextCodepoint()) |codepoint| : (i += @intCast(termbox.tb_wcwidth(codepoint))) {
if (i - x >= max_length) break;
const cell = Cell.init(codepoint, fg, bg);
try cell.put(i, y);
}
}
@@ -501,9 +523,9 @@ pub fn drawCharMultiple(
length: usize,
fg: u32,
bg: u32,
) void {
) !void {
const cell = Cell.init(char, fg, bg);
for (0..length) |xx| cell.put(x + xx, y);
for (0..length) |xx| try cell.put(x + xx, y);
}
// Every codepoint is assumed to have a width of 1.
@@ -521,6 +543,8 @@ pub fn strWidth(str: []const u8) usize {
}
fn clearBackBuffer() !void {
if (termbox.global.initialized == 0) return;
// Clear the TTY because termbox2 doesn't seem to do it properly
const capability = termbox.global.caps[termbox.TB_CAP_CLEAR_SCREEN];
const capability_slice = std.mem.span(capability);

View File

@@ -207,7 +207,7 @@ fn alphaBlit(x: usize, y: usize, tb_width: usize, tb_height: usize, cells: [CHAR
for (0..CHAR_HEIGHT) |yy| {
for (0..CHAR_WIDTH) |xx| {
const cell = cells[yy * CHAR_WIDTH + xx];
cell.put(x + xx, y + yy);
cell.put(x + xx, y + yy) catch {};
}
}
}

View File

@@ -129,29 +129,29 @@ fn draw(self: *Box) void {
self.bg,
);
left_up.put(self.left_pos.x - 1, self.left_pos.y - 1);
right_up.put(self.right_pos.x, self.left_pos.y - 1);
left_down.put(self.left_pos.x - 1, self.right_pos.y);
right_down.put(self.right_pos.x, self.right_pos.y);
left_up.put(self.left_pos.x - 1, self.left_pos.y - 1) catch {};
right_up.put(self.right_pos.x, self.left_pos.y - 1) catch {};
left_down.put(self.left_pos.x - 1, self.right_pos.y) catch {};
right_down.put(self.right_pos.x, self.right_pos.y) catch {};
for (0..self.width) |i| {
top.put(self.left_pos.x + i, self.left_pos.y - 1);
bottom.put(self.left_pos.x + i, self.right_pos.y);
top.put(self.left_pos.x + i, self.left_pos.y - 1) catch {};
bottom.put(self.left_pos.x + i, self.right_pos.y) catch {};
}
top.ch = self.buffer.box_chars.left;
bottom.ch = self.buffer.box_chars.right;
for (0..self.height) |i| {
top.put(self.left_pos.x - 1, self.left_pos.y + i);
bottom.put(self.right_pos.x, self.left_pos.y + i);
top.put(self.left_pos.x - 1, self.left_pos.y + i) catch {};
bottom.put(self.right_pos.x, self.left_pos.y + i) catch {};
}
}
if (self.blank_box) {
for (0..self.height) |y| {
for (0..self.width) |x| {
self.buffer.blank_cell.put(self.left_pos.x + x, self.left_pos.y + y);
self.buffer.blank_cell.put(self.left_pos.x + x, self.left_pos.y + y) catch {};
}
}
}
@@ -164,7 +164,7 @@ fn draw(self: *Box) void {
self.width,
self.title_fg,
self.bg,
);
) catch {};
}
if (self.bottom_title) |title| {
@@ -175,7 +175,7 @@ fn draw(self: *Box) void {
self.width,
self.title_fg,
self.bg,
);
) catch {};
}
}

View File

@@ -117,7 +117,7 @@ fn draw(self: *Label) void {
width,
self.fg,
self.bg,
);
) catch {};
return;
}
@@ -127,7 +127,7 @@ fn draw(self: *Label) void {
self.component_pos.y,
self.fg,
self.bg,
);
) catch {};
}
fn update(self: *Label, ctx: *anyopaque) !void {

View File

@@ -131,14 +131,14 @@ pub fn handle(self: *Text, maybe_key: ?keyboard.Key) !void {
}
if (self.masked and self.maybe_mask == null) {
TerminalBuffer.setCursor(
try TerminalBuffer.setCursor(
self.component_pos.x,
self.component_pos.y,
);
return;
}
TerminalBuffer.setCursor(
try TerminalBuffer.setCursor(
self.component_pos.x + (self.cursor - self.visible_start),
self.component_pos.y,
);
@@ -159,7 +159,7 @@ fn draw(self: *Text) void {
length,
self.fg,
self.bg,
);
) catch {};
}
return;
}
@@ -182,7 +182,7 @@ fn draw(self: *Text) void {
self.component_pos.y,
self.fg,
self.bg,
);
) catch {};
}
fn goLeft(ptr: *anyopaque) !bool {

View File

@@ -105,8 +105,8 @@ pub fn CyclableLabel(comptime ItemType: type, comptime ChangeItemType: type) typ
self.current = self.list.items.len - 1;
}
pub fn handle(self: *Self, _: ?keyboard.Key) void {
TerminalBuffer.setCursor(
pub fn handle(self: *Self, _: ?keyboard.Key) !void {
try TerminalBuffer.setCursor(
self.component_pos.x + self.cursor + 2,
self.component_pos.y,
);
@@ -119,11 +119,11 @@ pub fn CyclableLabel(comptime ItemType: type, comptime ChangeItemType: type) typ
var left_arrow = Cell.init('<', self.fg, self.bg);
var right_arrow = Cell.init('>', self.fg, self.bg);
left_arrow.put(self.component_pos.x, self.component_pos.y);
left_arrow.put(self.component_pos.x, self.component_pos.y) catch {};
right_arrow.put(
self.component_pos.x + self.width - 1,
self.component_pos.y,
);
) catch {};
const current_item = self.list.items[self.current];
const x = self.component_pos.x + 2;