From 51c5c3ee0bcb4d7e109f480f92f5e34cd5995e16 Mon Sep 17 00:00:00 2001 From: AnErrupTion Date: Wed, 29 Apr 2026 22:52:58 +0200 Subject: [PATCH 01/10] Fix waitpid() being interrupted by SIGCHLD Signed-off-by: AnErrupTion --- src/main.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.zig b/src/main.zig index 53400df..382e5f3 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1541,7 +1541,7 @@ fn authenticate(ptr: *anyopaque) !bool { const tty_control_transfer_act = std.posix.Sigaction{ .handler = .{ .handler = &ttyControlTransferSignalHandler }, .mask = std.posix.sigemptyset(), - .flags = 0, + .flags = std.posix.SA.RESTART, // For waitpid() }; std.posix.sigaction(std.posix.SIG.CHLD, &tty_control_transfer_act, null); From 15cd0c4779b083b75347b0d5d92956679dd10e45 Mon Sep 17 00:00:00 2001 From: AnErrupTion Date: Thu, 30 Apr 2026 14:38:56 +0200 Subject: [PATCH 02/10] Use SIGINT instead of SIGCHILD for TTY control transfer Signed-off-by: AnErrupTion --- src/auth.zig | 2 +- src/main.zig | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/auth.zig b/src/auth.zig index d191d55..87ddc09 100644 --- a/src/auth.zig +++ b/src/auth.zig @@ -201,7 +201,7 @@ fn startSession( // Signal to the session process to give up control on the TTY try log_file.info(io, "auth/sys", "releasing tty", .{}); - std.posix.kill(options.session_pid, std.posix.SIG.CHLD) catch return error.TtyControlTransferFailed; + std.posix.kill(options.session_pid, std.posix.SIG.INT) catch return error.TtyControlTransferFailed; // Execute what the user requested switch (current_environment.display_server) { diff --git a/src/main.zig b/src/main.zig index 382e5f3..81c44b4 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1541,9 +1541,9 @@ fn authenticate(ptr: *anyopaque) !bool { const tty_control_transfer_act = std.posix.Sigaction{ .handler = .{ .handler = &ttyControlTransferSignalHandler }, .mask = std.posix.sigemptyset(), - .flags = std.posix.SA.RESTART, // For waitpid() + .flags = 0, }; - std.posix.sigaction(std.posix.SIG.CHLD, &tty_control_transfer_act, null); + std.posix.sigaction(std.posix.SIG.INT, &tty_control_transfer_act, null); try state.log_file.reinit(state.io); From 807f6d249a1494c1c20949d82a9409497d067a54 Mon Sep 17 00:00:00 2001 From: AnErrupTion Date: Thu, 30 Apr 2026 22:48:29 +0200 Subject: [PATCH 03/10] Remove further & all @cImport() usage in interop Signed-off-by: AnErrupTion --- ly-core/build.zig | 8 ++++++++ ly-core/src/interop.zig | 18 ++++-------------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/ly-core/build.zig b/ly-core/build.zig index 614404e..dc722b5 100644 --- a/ly-core/build.zig +++ b/ly-core/build.zig @@ -36,6 +36,14 @@ pub fn build(b: *std.Build) void { addCImport(b, mod, translate_c, target, optimize, "system_time", "#include "); addCImport(b, mod, translate_c, target, optimize, "time", "#include "); + if (target.result.os.tag == .linux) { + addCImport(b, mod, translate_c, target, optimize, "kd", "#include "); + addCImport(b, mod, translate_c, target, optimize, "vt", "#include "); + } else if (target.result.os.tag == .freebsd) { + addCImport(b, mod, translate_c, target, optimize, "kbio", "#include "); + addCImport(b, mod, translate_c, target, optimize, "consio", "#include "); + } + const mod_tests = b.addTest(.{ .root_module = mod, }); diff --git a/ly-core/src/interop.zig b/ly-core/src/interop.zig index 5b2b954..f23583c 100644 --- a/ly-core/src/interop.zig +++ b/ly-core/src/interop.zig @@ -31,13 +31,8 @@ pub const UsernameEntry = struct { fn PlatformStruct() type { return switch (builtin.os.tag) { .linux => struct { - pub const kd = @cImport({ - @cInclude("sys/kd.h"); - }); - - pub const vt = @cImport({ - @cInclude("sys/vt.h"); - }); + pub const kd = @import("kd"); + pub const vt = @import("vt"); pub const LedState = c_char; pub const get_led_state = kd.KDGKBLED; @@ -197,13 +192,8 @@ fn PlatformStruct() type { } }, .freebsd => struct { - pub const kbio = @cImport({ - @cInclude("sys/kbio.h"); - }); - - pub const consio = @cImport({ - @cInclude("sys/consio.h"); - }); + pub const kbio = @import("kbio"); + pub const consio = @import("consio"); pub const LedState = c_int; pub const get_led_state = kbio.KDGETLED; From 5905e054c587df65f9e4559f33595de1bfccaaae Mon Sep 17 00:00:00 2001 From: AnErrupTion Date: Fri, 1 May 2026 07:47:48 +0200 Subject: [PATCH 04/10] Start Ly v1.5.0 development cycle Signed-off-by: AnErrupTion --- build.zig | 2 +- build.zig.zon | 2 +- ly-core/build.zig.zon | 2 +- ly-ui/build.zig.zon | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build.zig b/build.zig index 2aeac26..0e626d7 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 = 5, .patch = 0 }; var dest_directory: []const u8 = undefined; var config_directory: []const u8 = undefined; diff --git a/build.zig.zon b/build.zig.zon index 63e8c32..3c091cb 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -1,6 +1,6 @@ .{ .name = .ly, - .version = "1.4.0", + .version = "1.5.0", .fingerprint = 0xa148ffcc5dc2cb59, .minimum_zig_version = "0.16.0", .dependencies = .{ diff --git a/ly-core/build.zig.zon b/ly-core/build.zig.zon index a389405..b40c8f8 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.1.0", .fingerprint = 0xddda7afda795472, .minimum_zig_version = "0.16.0", .dependencies = .{ diff --git a/ly-ui/build.zig.zon b/ly-ui/build.zig.zon index 598cba0..2a7e175 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.1.0", .fingerprint = 0x8d11bf85a74ec803, .minimum_zig_version = "0.16.0", .dependencies = .{ From 3869bfd2f95acc4cd7dcc08675155047da1d4676 Mon Sep 17 00:00:00 2001 From: AnErrupTion Date: Fri, 1 May 2026 17:40:04 +0200 Subject: [PATCH 05/10] Add config validation argument (closes #969) Signed-off-by: AnErrupTion --- readme.md | 6 ++++++ src/main.zig | 27 ++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index aa23db8..78ebffc 100644 --- a/readme.md +++ b/readme.md @@ -226,6 +226,12 @@ You can, of course, still select the init system of your choice when using this You can find all the configuration in `/etc/ly/config.ini`. The file is fully commented, and includes the default values. +You may also check the validity of your configuration file (i.e. if there are any errors in it) with the following command: + +``` +$ ly --validate-config /etc/ly/config.ini +``` + ## Controls Use the Up/Down arrow keys to change the current field, and the Left/Right arrow keys to scroll through the different fields (whether it be the info line, the desktop environment, or the username). The info line is where messages and errors are displayed. diff --git a/src/main.zig b/src/main.zig index 81c44b4..6373751 100644 --- a/src/main.zig +++ b/src/main.zig @@ -172,7 +172,8 @@ pub fn main(init: std.process.Init) !void { \\-h, --help Shows all commands. \\-v, --version Shows the version of Ly. \\-c, --config Overrides the default configuration path. Example: --config /usr/share/ly - \\--use-kmscon-vt Use KMSCON instead of kernel VT + \\--use-kmscon-vt Uses KMSCON instead of the kernel VT. + \\--validate-config Validates the given configuration file. ); var diag = clap.Diagnostic{}; @@ -211,6 +212,30 @@ pub fn main(init: std.process.Init) !void { } if (res.args.config) |path| config_parent_path = path; if (res.args.@"use-kmscon-vt" != 0) state.use_kmscon_vt = true; + if (res.args.@"validate-config") |path| { + var parser = try IniParser(Config).init( + state.allocator, + state.io, + path, + migrator.configFieldHandler, + ); + defer parser.deinit(); + + for (parser.errors.items) |err| { + std.log.err( + "failed to convert value '{s}' of option '{s}' to type '{s}': {s}", + .{ err.value, err.key, err.type_name, err.error_name }, + ); + } + + if (parser.maybe_load_error) |err| { + std.log.err("failed to load config file: {s}", .{@errorName(err)}); + std.process.exit(1); + } + + std.log.info("no errors detected!", .{}); + std.process.exit(0); + } } // Load configuration file From 79eebd8ee0a1a8e9a958679605f81620c611ecb4 Mon Sep 17 00:00:00 2001 From: AnErrupTion Date: Fri, 1 May 2026 17:43:28 +0200 Subject: [PATCH 06/10] Prefer std.log instead of stderr directly Signed-off-by: AnErrupTion --- src/main.zig | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/main.zig b/src/main.zig index 6373751..ce222db 100644 --- a/src/main.zig +++ b/src/main.zig @@ -146,12 +146,10 @@ pub fn main(init: std.process.Init) !void { // If we can't shutdown or restart due to an error, we print it to standard error. If that fails, just bail out if (shutdown) { const shutdown_error = std.process.replace(state.io, .{ .argv = &[_][]const u8{ "/bin/sh", "-c", shutdown_cmd } }); - stderr.print("error: couldn't shutdown: {s}\n", .{@errorName(shutdown_error)}) catch std.process.exit(1); - stderr.flush() catch std.process.exit(1); + std.log.err("couldn't shutdown: {s}", .{@errorName(shutdown_error)}); } else if (restart) { const restart_error = std.process.replace(state.io, .{ .argv = &[_][]const u8{ "/bin/sh", "-c", restart_cmd } }); - stderr.print("error: couldn't restart: {s}\n", .{@errorName(restart_error)}) catch std.process.exit(1); - stderr.flush() catch std.process.exit(1); + std.log.err("couldn't restart: {s}", .{@errorName(restart_error)}); } else { // The user has quit Ly using Ctrl+C if (commands_allocated) { @@ -201,13 +199,11 @@ pub fn main(init: std.process.Init) !void { if (res.args.help != 0) { try clap.help(stderr, clap.Help, ¶ms, .{}); - _ = try stderr.write("Note: if you want to configure Ly, please check the config file, which is located at " ++ build_options.config_directory ++ "/ly/config.ini.\n"); - try stderr.flush(); + std.log.info("note: if you want to configure Ly, please check the config file, which is located at " ++ build_options.config_directory ++ "/ly/config.ini.", .{}); std.process.exit(0); } if (res.args.version != 0) { - _ = try stderr.write("Ly version " ++ build_options.version ++ "\n"); - try stderr.flush(); + std.log.info("ly version " ++ build_options.version, .{}); std.process.exit(0); } if (res.args.config) |path| config_parent_path = path; From fdf241bed53baf386a6023785c29b0cbd591fb34 Mon Sep 17 00:00:00 2001 From: MartorSkull Date: Fri, 1 May 2026 20:09:34 +0200 Subject: [PATCH 07/10] Add option to move the box relative to the screen size (#964) ## What are the changes about? Added a new option in the configuration file for moving the box relative to the screen size. ``` box_h_position = 0.5 box_v_position = 0.5 ``` The big clock is centered relative to the box. In the cases where it would be outside of the screen, it moves the box to fit in the screen. ## What existing issue does this resolve? Add more options for personalization ## Examples Normal usage: ``` box_h_position = 0.15 box_v_position = 0.35 ``` ![image](/attachments/6595dfa9-aade-45f4-887c-e5db7f8d5a89) Clock would be outside of the screen vertically: ``` box_h_position = 0.15 box_v_position = -1.0 ``` ![image](/attachments/0d6bdcc4-e9dd-4671-a65d-b8b9f063ffb6) Clock would be outside of the screen horizontally and vertically: ``` box_h_position = -1.0 box_v_position = -1.0 input_len = 3 ``` ![image](/attachments/630b07fd-b400-4e71-8a67-1baf3a6700a0) Clock would be outside of the screen horizontally and vertically on the bottom left of the screen: ``` box_h_position = 2.0 box_v_position = 2.0 input_len = 3 ``` ![image](/attachments/28902967-11a8-4c02-a4c9-1b92f9a728ee) ## What existing issue does this resolve? _Replace this with a reference to an existing issue, or N/A if there is none_ ## Pre-requisites - [x] I have tested & confirmed the changes work locally - [x] I have run `zig fmt` throughout my changes Co-authored-by: AnErrupTion Reviewed-on: https://codeberg.org/fairyglade/ly/pulls/964 Reviewed-by: AnErrupTion --- res/config.ini | 8 ++++++++ src/config/Config.zig | 2 ++ src/main.zig | 38 ++++++++++++++++++++++++++------------ 3 files changed, 36 insertions(+), 12 deletions(-) diff --git a/res/config.ini b/res/config.ini index 86f44b4..c2d885c 100644 --- a/res/config.ini +++ b/res/config.ini @@ -97,6 +97,14 @@ blank_box = true # Border foreground color id border_fg = 0x00FFFFFF +# Relative horizontal position from the end of the screen +# default: 0.5 +box_position_h = 0.5 + +# Relative vertical position from the bottom of the screen +# default: 0.4 +box_position_v = 0.4 + # Title to show at the top of the main box # If set to null, none will be shown box_title = null diff --git a/src/config/Config.zig b/src/config/Config.zig index 2233cb4..9efaaf7 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -23,6 +23,8 @@ bigclock_12hr: bool = false, bigclock_seconds: bool = false, blank_box: bool = true, border_fg: u32 = 0x00FFFFFF, +box_position_h: f32 = 0.5, +box_position_v: f32 = 0.4, box_title: ?[]const u8 = null, brightness_down_cmd: [:0]const u8 = build_options.prefix_directory ++ "/bin/brightnessctl -q -n s 10%-", brightness_down_key: ?[]const u8 = "F5", diff --git a/src/main.zig b/src/main.zig index ce222db..35239d7 100644 --- a/src/main.zig +++ b/src/main.zig @@ -2046,22 +2046,36 @@ fn positionWidgets(ptr: *anyopaque) !void { .childrenPosition() .removeX(TerminalBuffer.strWidth(state.lang.numlock) + TerminalBuffer.strWidth(state.lang.capslock) + 1)); - state.box.positionXY(TerminalBuffer.START_POSITION - .addX((state.buffer.width - @min(state.buffer.width - 2, state.box.width)) / 2) - .addY((state.buffer.height - @min(state.buffer.height - 2, state.box.height)) / 2)); + var bb_height = state.box.height; + var bb_width = state.box.width; + const clock_text_len = TerminalBuffer.strWidth(state.bigclock_label.text) * (BigLabel.CHAR_WIDTH + 1); if (state.config.bigclock != .none) { - const half_width = state.buffer.width / 2; - const half_label_width = (TerminalBuffer.strWidth(state.bigclock_label.text) * (BigLabel.CHAR_WIDTH + 1)) / 2; - const half_height = (if (state.buffer.height > state.box.height) state.buffer.height - state.box.height else state.buffer.height) / 2; - - state.bigclock_label.positionXY(TerminalBuffer.START_POSITION - .addX(half_width) - .removeXIf(half_label_width, half_width > half_label_width) - .addY(half_height) - .removeYIf(BigLabel.CHAR_HEIGHT + 2, half_height > BigLabel.CHAR_HEIGHT + 2)); + bb_height += BigLabel.CHAR_HEIGHT + 2; + bb_width = @max(bb_width, clock_text_len); } + const max_v_position: f32 = @floatFromInt(state.buffer.height - bb_height - 1); + const max_h_position: f32 = @floatFromInt(state.buffer.width - bb_width - 1); + + bb_height = @min(bb_height, state.buffer.height - 2); + bb_width = @min(bb_width, state.buffer.width - 2); + + const v_space: f32 = @floatFromInt(state.buffer.height - bb_height); + const v_position: usize = @intFromFloat(std.math.clamp(v_space * state.config.box_position_v, 1.0, max_v_position)); + const h_space: f32 = @floatFromInt(state.buffer.width - bb_width); + const h_position: usize = @intFromFloat(std.math.clamp(h_space * state.config.box_position_h, 1.0, max_h_position)); + + if (state.config.bigclock != .none) { + state.bigclock_label.positionXY(TerminalBuffer.START_POSITION + .addX(h_position + (bb_width - clock_text_len) / 2) + .addY(v_position)); + } + + state.box.positionXY(TerminalBuffer.START_POSITION + .addX(h_position + (bb_width - state.box.width) / 2) + .addY(v_position + (bb_height - state.box.height))); + state.info_line.label.positionY(state.box .childrenPosition()); From c50af66407b3005dd72979a9c62b9a81cefa3682 Mon Sep 17 00:00:00 2001 From: AnErrupTion Date: Fri, 1 May 2026 20:54:54 +0200 Subject: [PATCH 08/10] Fix log file race condition Signed-off-by: AnErrupTion --- src/auth.zig | 8 ++++++++ 1 file changed, 8 insertions(+) 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, From 864f5f289244f35890875a313c056df1ae775c0b Mon Sep 17 00:00:00 2001 From: AnErrupTion Date: Fri, 1 May 2026 21:51:27 +0200 Subject: [PATCH 09/10] Implement syslog functionality (closes # Signed-off-by: AnErrupTion --- ly-core/src/LogFile.zig | 85 +++++++++++++++++++++++++++++------------ res/config.ini | 1 + src/config/Config.zig | 2 +- 3 files changed, 62 insertions(+), 26 deletions(-) diff --git a/ly-core/src/LogFile.zig b/ly-core/src/LogFile.zig index f60b153..192f338 100644 --- a/ly-core/src/LogFile.zig +++ b/ly-core/src/LogFile.zig @@ -3,50 +3,85 @@ const interop = @import("interop.zig"); const LogFile = @This(); -path: []const u8, +maybe_path: ?[]const u8, could_open_log_file: bool = undefined, -file: std.Io.File = undefined, +maybe_file: ?std.Io.File = null, buffer: []u8, -file_writer: std.Io.File.Writer = undefined, +maybe_file_writer: ?std.Io.File.Writer = null, + +pub fn init(io: std.Io, path: ?[]const u8, buffer: []u8) !LogFile { + var log_file = LogFile{ + .maybe_path = path, + .buffer = buffer, + }; + + if (path) |p| { + log_file.could_open_log_file = try openLogFile(io, p, &log_file); + } else { + std.posix.system.openlog("ly", 0, 0); + log_file.could_open_log_file = true; + } -pub fn init(io: std.Io, path: []const u8, buffer: []u8) !LogFile { - var log_file = LogFile{ .path = path, .buffer = buffer }; - log_file.could_open_log_file = try openLogFile(io, path, &log_file); return log_file; } pub fn reinit(self: *LogFile, io: std.Io) !void { - self.could_open_log_file = try openLogFile(io, self.path, self); + if (self.maybe_path) |path| { + self.could_open_log_file = try openLogFile(io, path, self); + } else { + std.posix.system.openlog("ly", 0, 0); + self.could_open_log_file = true; + } } pub fn deinit(self: *LogFile, io: std.Io) void { - self.file.close(io); + if (self.maybe_file) |file| { + file.close(io); + } else { + std.posix.system.closelog(); + } } pub fn info(self: *LogFile, io: std.Io, category: []const u8, comptime message: []const u8, args: anytype) !void { - var buffer: [128:0]u8 = undefined; - const time = interop.timeAsString(io, &buffer, "%Y-%m-%d %H:%M:%S"); + if (self.maybe_file_writer) |*writer| { + var buffer: [128:0]u8 = undefined; + const time = interop.timeAsString(io, &buffer, "%Y-%m-%d %H:%M:%S"); - try self.file_writer.interface.print("{s} [info/{s}] ", .{ time, category }); - try self.file_writer.interface.print(message, args); - try self.file_writer.interface.writeByte('\n'); - try self.file_writer.interface.flush(); + try writer.interface.print("{s} [info/{s}] ", .{ time, category }); + try writer.interface.print(message, args); + try writer.interface.writeByte('\n'); + try writer.interface.flush(); + } else { + var buffer: [1024]u8 = undefined; + const slice = try std.fmt.bufPrint(&buffer, message, args); + const msg = try std.fmt.bufPrintZ(buffer[slice.len..], "[info/{s}] {s}", .{ category, slice }); + + std.posix.system.syslog(std.posix.LOG.INFO, msg.ptr); + } } pub fn err(self: *LogFile, io: std.Io, category: []const u8, comptime message: []const u8, args: anytype) !void { - var buffer: [128:0]u8 = undefined; - const time = interop.timeAsString(io, &buffer, "%Y-%m-%d %H:%M:%S"); + if (self.maybe_file_writer) |*writer| { + var buffer: [128:0]u8 = undefined; + const time = interop.timeAsString(io, &buffer, "%Y-%m-%d %H:%M:%S"); - try self.file_writer.interface.print("{s} [err/{s}] ", .{ time, category }); - try self.file_writer.interface.print(message, args); - try self.file_writer.interface.writeByte('\n'); - try self.file_writer.interface.flush(); + try writer.interface.print("{s} [err/{s}] ", .{ time, category }); + try writer.interface.print(message, args); + try writer.interface.writeByte('\n'); + try writer.interface.flush(); + } else { + var buffer: [1024]u8 = undefined; + const slice = try std.fmt.bufPrint(&buffer, message, args); + const msg = try std.fmt.bufPrintZ(buffer[slice.len..], "[info/{s}] {s}", .{ category, slice }); + + std.posix.system.syslog(std.posix.LOG.ERR, msg.ptr); + } } fn openLogFile(io: std.Io, path: []const u8, log_file: *LogFile) !bool { var could_open_log_file = true; open_log_file: { - log_file.file = std.Io.Dir.cwd().openFile(io, path, .{ .mode = .write_only }) catch std.Io.Dir.cwd().createFile(io, path, .{ .permissions = .fromMode(0o666) }) catch { + log_file.maybe_file = std.Io.Dir.cwd().openFile(io, path, .{ .mode = .write_only }) catch std.Io.Dir.cwd().createFile(io, path, .{ .permissions = .fromMode(0o666) }) catch { // If we could neither open an existing log file nor create a new // one, abort. could_open_log_file = false; @@ -55,17 +90,17 @@ fn openLogFile(io: std.Io, path: []const u8, log_file: *LogFile) !bool { } if (!could_open_log_file) { - log_file.file = try std.Io.Dir.openFileAbsolute(io, "/dev/null", .{ .mode = .write_only }); + log_file.maybe_file = try std.Io.Dir.openFileAbsolute(io, "/dev/null", .{ .mode = .write_only }); } - var log_file_writer = log_file.file.writer(io, log_file.buffer); + var log_file_writer = log_file.maybe_file.?.writer(io, log_file.buffer); // Seek to the end of the log file if (could_open_log_file) { - const stat = try log_file.file.stat(io); + const stat = try log_file.maybe_file.?.stat(io); try log_file_writer.seekTo(stat.size); } - log_file.file_writer = log_file_writer; + log_file.maybe_file_writer = log_file_writer; return could_open_log_file; } diff --git a/res/config.ini b/res/config.ini index c2d885c..a290773 100644 --- a/res/config.ini +++ b/res/config.ini @@ -299,6 +299,7 @@ login_defs_path = /etc/login.defs logout_cmd = null # General log file path +# If null, syslog will be used instead ly_log = /var/log/ly.log # Main box horizontal margin diff --git a/src/config/Config.zig b/src/config/Config.zig index 9efaaf7..a592faa 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -74,7 +74,7 @@ lang: []const u8 = "en", login_cmd: ?[]const u8 = null, login_defs_path: []const u8 = "/etc/login.defs", logout_cmd: ?[]const u8 = null, -ly_log: []const u8 = "/var/log/ly.log", +ly_log: ?[]const u8 = "/var/log/ly.log", margin_box_h: u8 = 2, margin_box_v: u8 = 1, numlock: bool = false, From 4db9295102ac43d054c4e12f067429c5104f6e19 Mon Sep 17 00:00:00 2001 From: AnErrupTion Date: Sun, 3 May 2026 20:05:44 +0200 Subject: [PATCH 10/10] Fix building without X11 Signed-off-by: AnErrupTion --- build.zig | 6 +++++- ly-core/build.zig | 5 ++++- ly-ui/build.zig | 7 ++++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/build.zig b/build.zig index 0e626d7..45a548b 100644 --- a/build.zig +++ b/build.zig @@ -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/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-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", .{