Implement custom session support (fixes #757)

Signed-off-by: AnErrupTion <anerruption@disroot.org>
This commit is contained in:
AnErrupTion
2025-07-08 22:39:14 +02:00
parent 48e5369f56
commit 04920e1b1b
27 changed files with 106 additions and 18 deletions

View File

@@ -8,6 +8,7 @@ pub const DesktopEntry = struct {
Exec: []const u8 = "",
Name: [:0]const u8 = "",
DesktopNames: ?[:0]u8 = null,
Terminal: ?bool = null,
};
pub const Entry = struct { @"Desktop Entry": DesktopEntry = .{} };
@@ -19,3 +20,4 @@ xdg_desktop_names: ?[:0]const u8 = null,
cmd: []const u8 = "",
specifier: []const u8 = "",
display_server: DisplayServer = .wayland,
is_terminal: bool = false,

View File

@@ -180,6 +180,7 @@ fn startSession(
const vt = try std.fmt.bufPrint(&vt_buf, "vt{d}", .{options.tty});
try executeX11Cmd(pwd.pw_shell.?, pwd.pw_dir.?, options, current_environment.cmd, vt);
},
.custom => try executeCustomCmd(pwd.pw_shell.?, options, current_environment.is_terminal, current_environment.cmd),
}
}
@@ -201,6 +202,7 @@ fn setXdgEnv(tty_str: [:0]u8, environment: Environment) !void {
.wayland => "wayland",
.shell => "tty",
.xinitrc, .x11 => "x11",
.custom => "unspecified",
}, 0);
// The "/run/user/%d" directory is not available on FreeBSD. It is much
@@ -462,6 +464,22 @@ fn executeX11Cmd(shell: [*:0]const u8, pw_dir: [*:0]const u8, options: AuthOptio
_ = std.c.waitpid(x_pid, &status, 0);
}
fn executeCustomCmd(shell: [*:0]const u8, options: AuthOptions, is_terminal: bool, exec_cmd: []const u8) !void {
var maybe_log_file: ?std.fs.File = null;
if (!is_terminal) {
// For custom desktop entries, the "Terminal" value here determines if
// we redirect standard output & error or not. That is, we redirect only
// if it's equal to false (so if it's not running in a TTY).
maybe_log_file = try redirectStandardStreams(options.session_log, true);
}
defer if (maybe_log_file) |log_file| log_file.close();
var cmd_buffer: [1024]u8 = undefined;
const cmd_str = try std.fmt.bufPrintZ(&cmd_buffer, "{s} {s} {s}", .{ options.setup_cmd, options.login_cmd orelse "", exec_cmd });
const args = [_:null]?[*:0]const u8{ shell, "-c", cmd_str };
return std.posix.execveZ(shell, &args, std.c.environ);
}
fn redirectStandardStreams(session_log: []const u8, create: bool) !std.fs.File {
const log_file = if (create) (try std.fs.cwd().createFile(session_log, .{ .mode = 0o666 })) else (try std.fs.cwd().openFile(session_log, .{ .mode = .read_write }));

View File

@@ -28,6 +28,7 @@ cmatrix_max_codepoint: u16 = 0x7B,
colormix_col1: u32 = 0x00FF0000,
colormix_col2: u32 = 0x000000FF,
colormix_col3: u32 = 0x20000000,
custom_sessions: []const u8 = build_options.config_directory ++ "/ly/custom-sessions",
default_input: Input = .login,
doom_fire_height: u8 = 6,
doom_fire_spread: u8 = 2,

View File

@@ -7,6 +7,7 @@ authenticating: []const u8 = "authenticating...",
brightness_down: []const u8 = "decrease brightness",
brightness_up: []const u8 = "increase brightness",
capslock: []const u8 = "capslock",
custom: []const u8 = "custom",
err_alloc: []const u8 = "failed memory allocation",
err_bounds: []const u8 = "out-of-bounds index",
err_brightness_change: []const u8 = "failed to change brightness",

View File

@@ -11,6 +11,7 @@ pub const DisplayServer = enum {
shell,
xinitrc,
x11,
custom,
};
pub const Input = enum {

View File

@@ -290,10 +290,12 @@ pub fn main() !void {
try info_line.addMessage(hostname, config.bg, config.fg);
}
// Crawl session directories (Wayland, X11 and custom respectively)
var wayland_session_dirs = std.mem.splitScalar(u8, config.waylandsessions, ':');
while (wayland_session_dirs.next()) |dir| {
try crawl(&session, lang, dir, .wayland);
}
if (build_options.enable_x11_support) {
var x_session_dirs = std.mem.splitScalar(u8, config.xsessions, ':');
while (x_session_dirs.next()) |dir| {
@@ -301,6 +303,11 @@ pub fn main() !void {
}
}
var custom_session_dirs = std.mem.splitScalar(u8, config.custom_sessions, ':');
while (custom_session_dirs.next()) |dir| {
try crawl(&session, lang, dir, .custom);
}
var login = Text.init(allocator, &buffer, false, null);
defer login.deinit();
@@ -864,11 +871,7 @@ fn addOtherEnvironment(session: *Session, lang: Lang, display_server: DisplaySer
.xdg_session_desktop = null,
.xdg_desktop_names = null,
.cmd = exec orelse "",
.specifier = switch (display_server) {
.wayland => lang.wayland,
.x11 => lang.x11,
else => lang.other,
},
.specifier = lang.other,
.display_server = display_server,
});
}
@@ -890,40 +893,43 @@ fn crawl(session: *Session, lang: Lang, path: []const u8, display_server: Displa
});
errdefer entry_ini.deinit();
var xdg_session_desktop: []const u8 = undefined;
var maybe_xdg_session_desktop: ?[]const u8 = null;
const maybe_desktop_names = entry_ini.data.@"Desktop Entry".DesktopNames;
if (maybe_desktop_names) |desktop_names| {
xdg_session_desktop = std.mem.sliceTo(desktop_names, ';');
} else {
// if DesktopNames is empty, we'll take the name of the session file
xdg_session_desktop = std.fs.path.stem(item.name);
maybe_xdg_session_desktop = std.mem.sliceTo(desktop_names, ';');
} else if (display_server != .custom) {
// If DesktopNames is empty, and this isn't a custom session entry,
// we'll take the name of the session file
maybe_xdg_session_desktop = std.fs.path.stem(item.name);
}
// Prepare the XDG_CURRENT_DESKTOP environment variable here
const entry = entry_ini.data.@"Desktop Entry";
var xdg_desktop_names: ?[:0]const u8 = null;
var maybe_xdg_desktop_names: ?[:0]const u8 = null;
if (entry.DesktopNames) |desktop_names| {
for (desktop_names) |*c| {
if (c.* == ';') c.* = ':';
}
xdg_desktop_names = desktop_names;
maybe_xdg_desktop_names = desktop_names;
}
const session_desktop = try session.label.allocator.dupeZ(u8, xdg_session_desktop);
errdefer session.label.allocator.free(session_desktop);
const maybe_session_desktop = if (maybe_xdg_session_desktop) |xdg_session_desktop| try session.label.allocator.dupeZ(u8, xdg_session_desktop) else null;
errdefer if (maybe_session_desktop) |session_desktop| session.label.allocator.free(session_desktop);
try session.addEnvironment(.{
.entry_ini = entry_ini,
.name = entry.Name,
.xdg_session_desktop = session_desktop,
.xdg_desktop_names = xdg_desktop_names,
.xdg_session_desktop = maybe_session_desktop,
.xdg_desktop_names = maybe_xdg_desktop_names,
.cmd = entry.Exec,
.specifier = switch (display_server) {
.wayland => lang.wayland,
.x11 => lang.x11,
.custom => lang.custom,
else => lang.other,
},
.display_server = display_server,
.is_terminal = entry.Terminal orelse false,
});
}
}