diff --git a/build.zig b/build.zig index 2aeac26..fb0d07d 100644 --- a/build.zig +++ b/build.zig @@ -23,7 +23,7 @@ comptime { } } -const ly_version = std.SemanticVersion{ .major = 1, .minor = 4, .patch = 0 }; +const ly_version = std.SemanticVersion{ .major = 1, .minor = 4, .patch = 1 }; var dest_directory: []const u8 = undefined; var config_directory: []const u8 = undefined; @@ -72,7 +72,11 @@ pub fn build(b: *std.Build) !void { .use_llvm = true, }); - const ly_ui = b.dependency("ly_ui", .{ .target = target, .optimize = optimize }); + const ly_ui = b.dependency("ly_ui", .{ + .target = target, + .optimize = optimize, + .enable_x11_support = enable_x11_support, + }); exe.root_module.addImport("ly-ui", ly_ui.module("ly-ui")); exe.root_module.addOptions("build_options", build_options); diff --git a/build.zig.zon b/build.zig.zon index 63e8c32..2f4c1be 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -1,6 +1,6 @@ .{ .name = .ly, - .version = "1.4.0", + .version = "1.4.1", .fingerprint = 0xa148ffcc5dc2cb59, .minimum_zig_version = "0.16.0", .dependencies = .{ diff --git a/ly-core/build.zig b/ly-core/build.zig index dc722b5..f6574de 100644 --- a/ly-core/build.zig +++ b/ly-core/build.zig @@ -4,6 +4,7 @@ const Translator = @import("translate_c").Translator; pub fn build(b: *std.Build) void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); + const enable_x11_support = b.option(bool, "enable_x11_support", "Enable X11 support") orelse true; const mod = b.addModule("ly-core", .{ .root_source_file = b.path("src/root.zig"), .target = target, @@ -20,7 +21,9 @@ pub fn build(b: *std.Build) void { addCImport(b, mod, translate_c, target, optimize, "pam", "#include "); addCImport(b, mod, translate_c, target, optimize, "utmp", "#include "); - addCImport(b, mod, translate_c, target, optimize, "xcb", "#include "); + if (enable_x11_support) { + addCImport(b, mod, translate_c, target, optimize, "xcb", "#include "); + } if (target.result.os.tag == .freebsd) { addCImport(b, mod, translate_c, target, optimize, "pwd", \\#include diff --git a/ly-core/build.zig.zon b/ly-core/build.zig.zon index a389405..8998484 100644 --- a/ly-core/build.zig.zon +++ b/ly-core/build.zig.zon @@ -1,6 +1,6 @@ .{ .name = .ly_core, - .version = "1.0.0", + .version = "1.0.1", .fingerprint = 0xddda7afda795472, .minimum_zig_version = "0.16.0", .dependencies = .{ diff --git a/ly-ui/build.zig b/ly-ui/build.zig index a7a3051..7397873 100644 --- a/ly-ui/build.zig +++ b/ly-ui/build.zig @@ -4,13 +4,18 @@ const Translator = @import("translate_c").Translator; pub fn build(b: *std.Build) void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); + const enable_x11_support = b.option(bool, "enable_x11_support", "Enable X11 support") orelse true; const mod = b.addModule("ly-ui", .{ .root_source_file = b.path("src/root.zig"), .target = target, .optimize = optimize, }); - const ly_core = b.dependency("ly_core", .{ .target = target, .optimize = optimize }); + const ly_core = b.dependency("ly_core", .{ + .target = target, + .optimize = optimize, + .enable_x11_support = enable_x11_support, + }); mod.addImport("ly-core", ly_core.module("ly-core")); const termbox_dep = b.dependency("termbox2", .{ diff --git a/ly-ui/build.zig.zon b/ly-ui/build.zig.zon index 598cba0..2ec2741 100644 --- a/ly-ui/build.zig.zon +++ b/ly-ui/build.zig.zon @@ -1,6 +1,6 @@ .{ .name = .ly_ui, - .version = "1.0.0", + .version = "1.0.1", .fingerprint = 0x8d11bf85a74ec803, .minimum_zig_version = "0.16.0", .dependencies = .{ diff --git a/ly-ui/src/TerminalBuffer.zig b/ly-ui/src/TerminalBuffer.zig index 565593b..1fd9999 100644 --- a/ly-ui/src/TerminalBuffer.zig +++ b/ly-ui/src/TerminalBuffer.zig @@ -381,6 +381,12 @@ pub fn setCell(x: usize, y: usize, 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)); + } +} + pub fn reclaim(self: TerminalBuffer) !void { if (self.termios) |termios| { // Take back control of the TTY diff --git a/ly-ui/src/keyboard.zig b/ly-ui/src/keyboard.zig index 2e6e0e2..a90148b 100644 --- a/ly-ui/src/keyboard.zig +++ b/ly-ui/src/keyboard.zig @@ -171,6 +171,7 @@ pub fn getKeyList(allocator: Allocator, tb_event: termbox.tb_event) !KeyList { const code = if (tb_event.ch == 0 and tb_event.key < 128) tb_event.key else tb_event.ch; switch (code) { + // Non-standard control codes 0 => { key.ctrl = true; key.@"2" = true; @@ -342,7 +343,9 @@ pub fn getKeyList(allocator: Allocator, tb_event: termbox.tb_event) !KeyList { key = std.mem.zeroes(Key); key._ = true; }, + // Standard ASCII characters 32 => { + key = std.mem.zeroes(Key); key.@" " = true; }, 33 => { @@ -370,6 +373,7 @@ pub fn getKeyList(allocator: Allocator, tb_event: termbox.tb_event) !KeyList { key.@"&" = true; }, 39 => { + key = std.mem.zeroes(Key); key.@"'" = true; }, 40 => { @@ -389,74 +393,86 @@ pub fn getKeyList(allocator: Allocator, tb_event: termbox.tb_event) !KeyList { key.@"+" = true; }, 44 => { + key = std.mem.zeroes(Key); key.@"," = true; }, 45 => { + key = std.mem.zeroes(Key); key.@"-" = true; }, 46 => { + key = std.mem.zeroes(Key); key.@"." = true; }, 47 => { + key = std.mem.zeroes(Key); key.@"/" = true; }, 48 => { + key = std.mem.zeroes(Key); key.@"0" = true; }, 49 => { + key = std.mem.zeroes(Key); key.@"1" = true; }, 50 => { + key = std.mem.zeroes(Key); key.@"2" = true; }, 51 => { + key = std.mem.zeroes(Key); key.@"3" = true; }, 52 => { + key = std.mem.zeroes(Key); key.@"4" = true; }, 53 => { + key = std.mem.zeroes(Key); key.@"5" = true; }, 54 => { + key = std.mem.zeroes(Key); key.@"6" = true; }, 55 => { + key = std.mem.zeroes(Key); key.@"7" = true; }, 56 => { + key = std.mem.zeroes(Key); key.@"8" = true; }, 57 => { + key = std.mem.zeroes(Key); key.@"9" = true; }, 58 => { - key.shift = true; + key = std.mem.zeroes(Key); key.@":" = true; }, 59 => { + key = std.mem.zeroes(Key); key.@";" = true; }, 60 => { - key.shift = true; + key = std.mem.zeroes(Key); key.@"<" = true; }, 61 => { + key = std.mem.zeroes(Key); key.@"=" = true; }, 62 => { - key.shift = true; + key = std.mem.zeroes(Key); key.@">" = true; }, 63 => { - key.shift = true; + key = std.mem.zeroes(Key); key.@"?" = true; }, 64 => { - key.shift = true; - key.@"2" = true; - try keys.append(allocator, key); - key = std.mem.zeroes(Key); key.@"@" = true; }, @@ -565,12 +581,15 @@ pub fn getKeyList(allocator: Allocator, tb_event: termbox.tb_event) !KeyList { key.z = true; }, 91 => { + key = std.mem.zeroes(Key); key.@"[" = true; }, 92 => { + key = std.mem.zeroes(Key); key.@"\\" = true; }, 93 => { + key = std.mem.zeroes(Key); key.@"]" = true; }, 94 => { @@ -578,14 +597,11 @@ pub fn getKeyList(allocator: Allocator, tb_event: termbox.tb_event) !KeyList { key.@"^" = true; }, 95 => { - key.shift = true; - key.@"-" = true; - try keys.append(allocator, key); - key = std.mem.zeroes(Key); key._ = true; }, 96 => { + key = std.mem.zeroes(Key); key.@"`" = true; }, 97 => { @@ -667,34 +683,21 @@ pub fn getKeyList(allocator: Allocator, tb_event: termbox.tb_event) !KeyList { key.z = true; }, 123 => { - key.shift = true; key.@"{" = true; }, 124 => { - key.shift = true; - key.@"\\" = true; - try keys.append(allocator, key); - key = std.mem.zeroes(Key); key.@"|" = true; }, 125 => { - key.shift = true; + key = std.mem.zeroes(Key); key.@"}" = true; }, 126 => { - key.shift = true; - key.@"`" = true; - try keys.append(allocator, key); - key = std.mem.zeroes(Key); key.@"~" = true; }, 127 => { - key.ctrl = true; - key.@"8" = true; - try keys.append(allocator, key); - key = std.mem.zeroes(Key); key.backspace = true; }, diff --git a/res/ly-kmsconvt@.service b/res/ly-kmsconvt@.service index 3e7d1fd..80eb1da 100644 --- a/res/ly-kmsconvt@.service +++ b/res/ly-kmsconvt@.service @@ -5,7 +5,7 @@ After=kmsconvt@%i.service Conflicts=kmsconvt@%i.service [Service] -ExecStart=$PREFIX_DIRECTORY/bin/kmscon --font-engine unifont --vt=%I --seats=seat0 --login -- $PREFIX_DIRECTORY/bin/ly --use-kmscon-vt +ExecStart=$PREFIX_DIRECTORY/bin/kmscon --font-engine unifont --vt=%I --seats=seat0 --login -- $PREFIX_DIRECTORY/bin/$EXECUTABLE_NAME --use-kmscon-vt StandardInput=tty UtmpIdentifier=%I TTYPath=/dev/%I diff --git a/src/animations/DurFile.zig b/src/animations/DurFile.zig index c20c2d2..7e56520 100644 --- a/src/animations/DurFile.zig +++ b/src/animations/DurFile.zig @@ -311,7 +311,6 @@ io: std.Io, terminal_buffer: *TerminalBuffer, dur_movie: DurFormat, frames: usize, -frame_size: UVec2, start_pos: IVec2, full_color: bool, animate: *bool, @@ -324,19 +323,16 @@ offset_alignment: DurOffsetAlignment, offset: IVec2, // if the user has an even number of columns or rows, we will default to the left or higher position (e.g. 4 columns center = .x..) -fn center(v: u32) i64 { - return @intCast((v / 2) + (v % 2)); +fn center(v: i64) i64 { + return @intCast(@divTrunc(v, 2) + @mod(v, 2)); } fn calc_start_position(terminal_buffer: *TerminalBuffer, dur_movie: *DurFormat, offset_alignment: DurOffsetAlignment, offset: IVec2) IVec2 { - const buf_width: u32 = @intCast(terminal_buffer.width); - const buf_height: u32 = @intCast(terminal_buffer.height); + const buf_width: i64 = @intCast(terminal_buffer.width); + const buf_height: i64 = @intCast(terminal_buffer.height); - var movie_width: u32 = @intCast(dur_movie.columns.?); - var movie_height: u32 = @intCast(dur_movie.lines.?); - - if (movie_width > buf_width) movie_width = buf_width; - if (movie_height > buf_height) movie_height = buf_height; + const movie_width: i64 = @intCast(dur_movie.columns.?); + const movie_height: i64 = @intCast(dur_movie.lines.?); const start_pos: IVec2 = switch (offset_alignment) { DurOffsetAlignment.center => .{ center(buf_width) - center(movie_width), center(buf_height) - center(movie_height) }, @@ -353,20 +349,6 @@ fn calc_start_position(terminal_buffer: *TerminalBuffer, dur_movie: *DurFormat, return start_pos + offset; } -fn calc_frame_size(terminal_buffer: *TerminalBuffer, dur_movie: *DurFormat) UVec2 { - const buf_width: u32 = @intCast(terminal_buffer.width); - const buf_height: u32 = @intCast(terminal_buffer.height); - - const movie_width: u32 = @intCast(dur_movie.columns.?); - const movie_height: u32 = @intCast(dur_movie.lines.?); - - // Draw only the needed amount if movie smaller than screen. If movie is bigger, we will just draw entire screen - const frame_width = if (movie_width < buf_width) movie_width else buf_width; - const frame_height = if (movie_height < buf_height) movie_height else buf_height; - - return .{ frame_width, frame_height }; -} - pub fn init( allocator: Allocator, io: std.Io, @@ -405,7 +387,6 @@ pub fn init( const offset: IVec2 = .{ x_offset, y_offset }; const start_pos = calc_start_position(terminal_buffer, &dur_movie, offset_alignment, offset); - const frame_size = calc_frame_size(terminal_buffer, &dur_movie); // Convert dur fps to frames per ms const frame_time: u32 = @trunc(1000 / dur_movie.framerate.?); @@ -418,7 +399,6 @@ pub fn init( .terminal_buffer = terminal_buffer, .frames = 0, .time_previous = std.Io.Timestamp.now(io, .real).toMilliseconds(), - .frame_size = frame_size, .start_pos = start_pos, .full_color = full_color, .animate = animate, @@ -453,9 +433,8 @@ fn deinit(self: *DurFile) void { } fn realloc(self: *DurFile) !void { - // when terminal size changes, we need to recalculate the start_pos and frame_size based on the new size + // when terminal size changes, we need to recalculate the start_pos based on the new size self.start_pos = calc_start_position(self.terminal_buffer, &self.dur_movie, self.offset_alignment, self.offset); - self.frame_size = calc_frame_size(self.terminal_buffer, &self.dur_movie); } fn draw(self: *DurFile) void { @@ -463,24 +442,14 @@ fn draw(self: *DurFile) void { const current_frame = self.dur_movie.frames.items[self.frames]; - const buf_width: u32 = @intCast(self.terminal_buffer.width); - const buf_height: u32 = @intCast(self.terminal_buffer.height); - // y is used as an iterator in the durformat, while cell_y gives us the correct placement for the cell (same for x) - for (0..self.frame_size[VEC_Y]) |y| { - const y_offset_i = @as(i32, @intCast(y)) + self.start_pos[VEC_Y]; - // we skip the pass if it falls outside of the draw window (ensure no int underflow) - const cell_y: u32 = if (y_offset_i >= 0 and y_offset_i < buf_height) @intCast(y_offset_i) else continue; + for (0..@intCast(self.dur_movie.lines.?)) |y| { + const cell_y = @as(i32, @intCast(y)) + self.start_pos[VEC_Y]; var iter = std.unicode.Utf8View.initUnchecked(current_frame.contents[y]).iterator(); - for (0..self.frame_size[VEC_X]) |x| { - const x_offset_i = @as(i32, @intCast(x)) + self.start_pos[VEC_X]; - // skip pass, same as y but also increment the codepoint iter to fetch correct values in later passes - const cell_x: u32 = if (x_offset_i >= 0 and x_offset_i < buf_width) @intCast(x_offset_i) else { - _ = iter.nextCodepoint().?; - continue; - }; + for (0..@intCast(self.dur_movie.columns.?)) |x| { + const cell_x = @as(i32, @intCast(x)) + self.start_pos[VEC_X]; const codepoint: u21 = iter.nextCodepoint().?; const color_map = current_frame.colorMap[x][y]; @@ -498,7 +467,7 @@ fn draw(self: *DurFile) void { const cell = Cell{ .ch = @intCast(codepoint), .fg = fg_color, .bg = bg_color }; - cell.put(cell_x, cell_y); + self.terminal_buffer.setCellBoundsChecked(cell_x, cell_y, cell); } } diff --git a/src/auth.zig b/src/auth.zig index 87ddc09..6a97fff 100644 --- a/src/auth.zig +++ b/src/auth.zig @@ -417,19 +417,27 @@ fn xauth(log_file: *LogFile, allocator: std.mem.Allocator, io: std.Io, display_n const magic_cookie = mcookie(io); + log_file.deinit(io); + const pid = std.posix.system.fork(); if (pid == 0) { + try log_file.reinit(io); + var cmd_buffer: [1024]u8 = undefined; const cmd_str = std.fmt.bufPrintZ(&cmd_buffer, "{s} add {s} . {s}", .{ options.xauth_cmd, display_name, magic_cookie }) catch std.process.exit(1); try log_file.info(io, "auth/x11", "executing: {s} -c {s}", .{ shell, cmd_str }); const args = [_:null]?[*:0]const u8{ shell, "-c", cmd_str }; _ = std.posix.system.execve(shell, &args, std.c.environ); + + log_file.deinit(io); std.process.exit(1); } var status: c_int = undefined; const result = std.posix.system.waitpid(pid, &status, 0); + + try log_file.reinit(io); if (interop.isError(result) or status != 0) { try log_file.err( io, diff --git a/src/main.zig b/src/main.zig index 81c44b4..f9f4a51 100644 --- a/src/main.zig +++ b/src/main.zig @@ -359,7 +359,16 @@ pub fn main(init: std.process.Init) !void { // Initialize terminal buffer try state.log_file.info(state.io, "tui", "initializing terminal buffer", .{}); - state.labels_max_length = @max(TerminalBuffer.strWidth(state.lang.login), TerminalBuffer.strWidth(state.lang.password)); + var labels = [_][]const u8{ + state.lang.login, + state.lang.password, + state.lang.wayland, + state.lang.x11, + state.lang.shell, + state.lang.xinitrc, + state.lang.custom, + }; + state.labels_max_length = maxWidths(&labels); var seed: u64 = undefined; state.io.random(std.mem.asBytes(&seed)); // Get a random seed for the PRNG (used by animations) @@ -1312,6 +1321,16 @@ pub fn main(init: std.process.Init) !void { ); } +fn maxWidths(labels: [][]const u8) usize { + var max_width: usize = 0; + + for (labels) |label| { + max_width = @max(max_width, TerminalBuffer.strWidth(label)); + } + + return max_width; +} + fn uiErrorHandler(err: anyerror, ctx: *anyopaque) anyerror!void { var state: *UiState = @ptrCast(@alignCast(ctx));