mirror of
https://github.com/fairyglade/ly.git
synced 2025-12-20 19:24:53 +00:00
Various bug fixes and small features (#606)
* Fix stray cursor, integer overflows and other bugs * check for getenvlist error, shorten code * fix cascade, set info_line before auth, make code clearer and a bug fix * Add option to turn on numlock at startup * Fix setting numlock * Update build.zig * Custom info text * Shift+Tab for previous input * update changelog and res/config * Some fixes * update build.zig * update build.zig again * Fix xauth command for some shells and fix building in ReleaseSafe * Use git describe to get dev version str * revert change to getLockState (it broke the doom animation) * add new ly error messages. Only try to make path for pam/exe during install when dest_directory is defined + print warning on error. * add warning message for workaround
This commit is contained in:
@@ -56,7 +56,7 @@ pub fn draw(self: Doom) void {
|
||||
const source = y * self.terminal_buffer.width + x;
|
||||
const random = (self.terminal_buffer.random.int(u16) % 7) & 3;
|
||||
|
||||
var dest = source - random + 1;
|
||||
var dest = (source - @min(source, random)) + 1;
|
||||
if (self.terminal_buffer.width > dest) dest = 0 else dest -= self.terminal_buffer.width;
|
||||
|
||||
const buffer_source = self.buffer[source];
|
||||
|
||||
@@ -145,15 +145,15 @@ pub fn draw(self: *Matrix) void {
|
||||
var y: u64 = 1;
|
||||
while (y <= self.terminal_buffer.height) : (y += 1) {
|
||||
const dot = self.dots[buf_width * y + x];
|
||||
var fg: u32 = @intCast(termbox.TB_GREEN);
|
||||
var fg: u16 = @intCast(termbox.TB_GREEN);
|
||||
|
||||
if (dot.value == -1 or dot.value == ' ') {
|
||||
termbox.tb_change_cell(@intCast(x), @intCast(y - 1), ' ', fg, termbox.TB_DEFAULT);
|
||||
_ = termbox.tb_set_cell(@intCast(x), @intCast(y - 1), ' ', fg, termbox.TB_DEFAULT);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dot.is_head) fg = @intCast(termbox.TB_WHITE | termbox.TB_BOLD);
|
||||
termbox.tb_change_cell(@intCast(x), @intCast(y - 1), @intCast(dot.value), fg, termbox.TB_DEFAULT);
|
||||
_ = termbox.tb_set_cell(@intCast(x), @intCast(y - 1), @intCast(dot.value), fg, termbox.TB_DEFAULT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
104
src/auth.zig
104
src/auth.zig
@@ -20,10 +20,9 @@ pub fn sessionSignalHandler(i: c_int) callconv(.C) void {
|
||||
if (child_pid > 0) _ = std.c.kill(child_pid, i);
|
||||
}
|
||||
|
||||
pub fn authenticate(config: Config, desktop: Desktop, login: [:0]const u8, password: [:0]const u8) !void {
|
||||
pub fn authenticate(config: Config, current_environment: Desktop.Environment, login: [:0]const u8, password: [:0]const u8) !void {
|
||||
var tty_buffer: [2]u8 = undefined;
|
||||
const tty_str = try std.fmt.bufPrintZ(&tty_buffer, "{d}", .{config.tty});
|
||||
const current_environment = desktop.environments.items[desktop.current];
|
||||
|
||||
// Set the XDG environment variables
|
||||
setXdgSessionEnv(current_environment.display_server);
|
||||
@@ -40,6 +39,7 @@ pub fn authenticate(config: Config, desktop: Desktop, login: [:0]const u8, passw
|
||||
|
||||
var status = interop.pam.pam_start(config.service_name.ptr, null, &conv, &handle);
|
||||
if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status);
|
||||
defer _ = interop.pam.pam_end(handle, status);
|
||||
|
||||
// Do the PAM routine
|
||||
status = interop.pam.pam_authenticate(handle, 0);
|
||||
@@ -50,9 +50,11 @@ pub fn authenticate(config: Config, desktop: Desktop, login: [:0]const u8, passw
|
||||
|
||||
status = interop.pam.pam_setcred(handle, interop.pam.PAM_ESTABLISH_CRED);
|
||||
if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status);
|
||||
defer status = interop.pam.pam_setcred(handle, interop.pam.PAM_DELETE_CRED);
|
||||
|
||||
status = interop.pam.pam_open_session(handle, 0);
|
||||
if (status != interop.pam.PAM_SUCCESS) return pamDiagnose(status);
|
||||
defer status = interop.pam.pam_close_session(handle, 0);
|
||||
|
||||
var pwd: *interop.passwd = undefined;
|
||||
{
|
||||
@@ -81,17 +83,25 @@ pub fn authenticate(config: Config, desktop: Desktop, login: [:0]const u8, passw
|
||||
std.process.exit(0);
|
||||
}
|
||||
|
||||
var entry: Utmp = std.mem.zeroes(Utmp);
|
||||
addUtmpEntry(&entry, pwd.pw_name, child_pid) catch {};
|
||||
var entry = std.mem.zeroes(Utmp);
|
||||
|
||||
// If we receive SIGTERM, forward it to child_pid
|
||||
const act = std.posix.Sigaction{
|
||||
.handler = .{ .handler = &sessionSignalHandler },
|
||||
.mask = std.posix.empty_sigset,
|
||||
.flags = 0,
|
||||
};
|
||||
try std.posix.sigaction(std.posix.SIG.TERM, &act, null);
|
||||
{
|
||||
// If an error occurs here, we can send SIGTERM to the session
|
||||
errdefer cleanup: {
|
||||
_ = std.posix.kill(child_pid, std.posix.SIG.TERM) catch break :cleanup;
|
||||
_ = std.posix.waitpid(child_pid, 0);
|
||||
}
|
||||
|
||||
// If we receive SIGTERM, forward it to child_pid
|
||||
const act = std.posix.Sigaction{
|
||||
.handler = .{ .handler = &sessionSignalHandler },
|
||||
.mask = std.posix.empty_sigset,
|
||||
.flags = 0,
|
||||
};
|
||||
try std.posix.sigaction(std.posix.SIG.TERM, &act, null);
|
||||
|
||||
try addUtmpEntry(&entry, pwd.pw_name, child_pid);
|
||||
}
|
||||
// Wait for the session to stop
|
||||
_ = std.posix.waitpid(child_pid, 0);
|
||||
|
||||
@@ -99,16 +109,6 @@ pub fn authenticate(config: Config, desktop: Desktop, login: [:0]const u8, passw
|
||||
|
||||
try resetTerminal(pwd.pw_shell, config.term_reset_cmd);
|
||||
|
||||
// Close the PAM session
|
||||
status = interop.pam.pam_close_session(handle, 0);
|
||||
if (status != 0) return pamDiagnose(status);
|
||||
|
||||
status = interop.pam.pam_setcred(handle, interop.pam.PAM_DELETE_CRED);
|
||||
if (status != 0) return pamDiagnose(status);
|
||||
|
||||
status = interop.pam.pam_end(handle, status);
|
||||
if (status != 0) return pamDiagnose(status);
|
||||
|
||||
if (shared_err.readError()) |err| return err;
|
||||
}
|
||||
|
||||
@@ -118,8 +118,7 @@ fn startSession(
|
||||
handle: ?*interop.pam.pam_handle,
|
||||
current_environment: Desktop.Environment,
|
||||
) !void {
|
||||
var status: c_int = 0;
|
||||
status = interop.initgroups(pwd.pw_name, pwd.pw_gid);
|
||||
const status = interop.initgroups(pwd.pw_name, pwd.pw_gid);
|
||||
if (status != 0) return error.GroupInitializationFailed;
|
||||
|
||||
std.posix.setgid(pwd.pw_gid) catch return error.SetUserGidFailed;
|
||||
@@ -129,15 +128,11 @@ fn startSession(
|
||||
try initEnv(pwd, config.path);
|
||||
|
||||
// Set the PAM variables
|
||||
const pam_env_vars = interop.pam.pam_getenvlist(handle);
|
||||
const pam_env_vars: ?[*:null]?[*:0]u8 = interop.pam.pam_getenvlist(handle);
|
||||
if (pam_env_vars == null) return error.GetEnvListFailed;
|
||||
|
||||
var index: usize = 0;
|
||||
while (true) : (index += 1) {
|
||||
const pam_env_var = pam_env_vars[index];
|
||||
if (pam_env_var == null) break;
|
||||
|
||||
_ = interop.putenv(pam_env_var);
|
||||
}
|
||||
const env_list = std.mem.span(pam_env_vars.?);
|
||||
for (env_list) |env_var| _ = interop.putenv(env_var.?);
|
||||
|
||||
// Execute what the user requested
|
||||
std.posix.chdirZ(pwd.pw_dir) catch return error.ChangeDirectoryFailed;
|
||||
@@ -156,9 +151,6 @@ fn startSession(
|
||||
}
|
||||
|
||||
fn initEnv(pwd: *interop.passwd, path_env: ?[:0]const u8) !void {
|
||||
const term_env = std.posix.getenv("TERM");
|
||||
|
||||
if (term_env) |term| _ = interop.setenv("TERM", term, 1);
|
||||
_ = interop.setenv("HOME", pwd.pw_dir, 1);
|
||||
_ = interop.setenv("PWD", pwd.pw_dir, 1);
|
||||
_ = interop.setenv("SHELL", pwd.pw_shell, 1);
|
||||
@@ -207,7 +199,7 @@ fn loginConv(
|
||||
|
||||
// Initialise allocated memory to 0
|
||||
// This ensures memory can be freed by pam on success
|
||||
for (response) |*r| r.* = std.mem.zeroes(interop.pam.pam_response);
|
||||
@memset(response, std.mem.zeroes(interop.pam.pam_response));
|
||||
|
||||
var username: ?[:0]u8 = null;
|
||||
var password: ?[:0]u8 = null;
|
||||
@@ -335,7 +327,36 @@ fn createXauthFile(pwd: [:0]const u8) ![:0]const u8 {
|
||||
return xauthority;
|
||||
}
|
||||
|
||||
fn xauth(display_name: [:0]u8, shell: [*:0]const u8, pw_dir: [*:0]const u8, xauth_cmd: []const u8, mcookie_cmd: []const u8) !void {
|
||||
pub fn mcookie(cmd: [:0]const u8) ![32]u8 {
|
||||
const pipe = try std.posix.pipe();
|
||||
defer std.posix.close(pipe[1]);
|
||||
|
||||
const output = std.fs.File{ .handle = pipe[0] };
|
||||
defer output.close();
|
||||
|
||||
const pid = try std.posix.fork();
|
||||
if (pid == 0) {
|
||||
std.posix.close(pipe[0]);
|
||||
|
||||
std.posix.dup2(pipe[1], std.posix.STDOUT_FILENO) catch std.process.exit(1);
|
||||
std.posix.close(pipe[1]);
|
||||
|
||||
const args = [_:null]?[*:0]u8{};
|
||||
std.posix.execveZ(cmd.ptr, &args, std.c.environ) catch {};
|
||||
std.process.exit(1);
|
||||
}
|
||||
|
||||
const result = std.posix.waitpid(pid, 0);
|
||||
|
||||
if (result.status != 0) return error.McookieFailed;
|
||||
|
||||
var buf: [32]u8 = undefined;
|
||||
const len = try output.read(&buf);
|
||||
if (len != 32) return error.McookieFailed;
|
||||
return buf;
|
||||
}
|
||||
|
||||
fn xauth(display_name: [:0]u8, shell: [*:0]const u8, pw_dir: [*:0]const u8, xauth_cmd: []const u8, mcookie_cmd: [:0]const u8) !void {
|
||||
var pwd_buf: [100]u8 = undefined;
|
||||
const pwd = try std.fmt.bufPrintZ(&pwd_buf, "{s}", .{pw_dir});
|
||||
|
||||
@@ -343,16 +364,19 @@ fn xauth(display_name: [:0]u8, shell: [*:0]const u8, pw_dir: [*:0]const u8, xaut
|
||||
_ = interop.setenv("XAUTHORITY", xauthority, 1);
|
||||
_ = interop.setenv("DISPLAY", display_name, 1);
|
||||
|
||||
const mcookie_output = try mcookie(mcookie_cmd);
|
||||
|
||||
const pid = try std.posix.fork();
|
||||
if (pid == 0) {
|
||||
var cmd_buffer: [1024]u8 = undefined;
|
||||
const cmd_str = std.fmt.bufPrintZ(&cmd_buffer, "{s} add {s} . $({s})", .{ xauth_cmd, display_name, mcookie_cmd }) catch std.process.exit(1);
|
||||
const cmd_str = std.fmt.bufPrintZ(&cmd_buffer, "{s} add {s} . {s}", .{ xauth_cmd, display_name, mcookie_output }) catch std.process.exit(1);
|
||||
const args = [_:null]?[*:0]const u8{ shell, "-c", cmd_str };
|
||||
std.posix.execveZ(shell, &args, std.c.environ) catch {};
|
||||
std.process.exit(1);
|
||||
}
|
||||
|
||||
_ = std.posix.waitpid(pid, 0);
|
||||
const status = std.posix.waitpid(pid, 0);
|
||||
if (status.status != 0) return error.XauthFailed;
|
||||
}
|
||||
|
||||
fn executeShellCmd(shell: [*:0]const u8) !void {
|
||||
@@ -388,7 +412,7 @@ fn executeX11Cmd(shell: [*:0]const u8, pw_dir: [*:0]const u8, config: Config, de
|
||||
xcb = interop.xcb.xcb_connect(null, null);
|
||||
ok = interop.xcb.xcb_connection_has_error(xcb);
|
||||
std.posix.kill(pid, 0) catch |e| {
|
||||
if (e == error.ProcessNotFound and ok != 0) return;
|
||||
if (e == error.ProcessNotFound and ok != 0) return error.XcbConnectionFailed;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -428,7 +452,7 @@ fn addUtmpEntry(entry: *Utmp, username: [*:0]const u8, pid: c_int) !void {
|
||||
entry.ut_pid = pid;
|
||||
|
||||
var buf: [4096]u8 = undefined;
|
||||
const ttyname = try std.os.getFdPath(0, &buf);
|
||||
const ttyname = try std.os.getFdPath(std.posix.STDIN_FILENO, &buf);
|
||||
|
||||
var ttyname_buf: [32]u8 = undefined;
|
||||
_ = try std.fmt.bufPrintZ(&ttyname_buf, "{s}", .{ttyname["/dev/".len..]});
|
||||
|
||||
@@ -8,89 +8,89 @@ const termbox = interop.termbox;
|
||||
const X: u32 = if (builtin.os.tag == .linux or builtin.os.tag.isBSD()) 0x2593 else '#';
|
||||
const O: u32 = 0;
|
||||
|
||||
pub const WIDTH: u64 = 5;
|
||||
pub const HEIGHT: u64 = 5;
|
||||
pub const WIDTH = 5;
|
||||
pub const HEIGHT = 5;
|
||||
pub const SIZE = WIDTH * HEIGHT;
|
||||
|
||||
// zig fmt: off
|
||||
const ZERO = [_]u32{
|
||||
const ZERO = [_]u21{
|
||||
X,X,X,X,X,
|
||||
X,X,O,X,X,
|
||||
X,X,O,X,X,
|
||||
X,X,O,X,X,
|
||||
X,X,X,X,X,
|
||||
};
|
||||
const ONE = [_]u32{
|
||||
const ONE = [_]u21{
|
||||
O,O,O,X,X,
|
||||
O,O,O,X,X,
|
||||
O,O,O,X,X,
|
||||
O,O,O,X,X,
|
||||
O,O,O,X,X,
|
||||
};
|
||||
const TWO = [_]u32{
|
||||
const TWO = [_]u21{
|
||||
X,X,X,X,X,
|
||||
O,O,O,X,X,
|
||||
X,X,X,X,X,
|
||||
X,X,O,O,O,
|
||||
X,X,X,X,X,
|
||||
};
|
||||
const THREE = [_]u32{
|
||||
const THREE = [_]u21{
|
||||
X,X,X,X,X,
|
||||
O,O,O,X,X,
|
||||
X,X,X,X,X,
|
||||
O,O,O,X,X,
|
||||
X,X,X,X,X,
|
||||
};
|
||||
const FOUR = [_]u32{
|
||||
const FOUR = [_]u21{
|
||||
X,X,O,X,X,
|
||||
X,X,O,X,X,
|
||||
X,X,X,X,X,
|
||||
O,O,O,X,X,
|
||||
O,O,O,X,X,
|
||||
};
|
||||
const FIVE = [_]u32{
|
||||
const FIVE = [_]u21{
|
||||
X,X,X,X,X,
|
||||
X,X,O,O,O,
|
||||
X,X,X,X,X,
|
||||
O,O,O,X,X,
|
||||
X,X,X,X,X,
|
||||
};
|
||||
const SIX = [_]u32{
|
||||
const SIX = [_]u21{
|
||||
X,X,X,X,X,
|
||||
X,X,O,O,O,
|
||||
X,X,X,X,X,
|
||||
X,X,O,X,X,
|
||||
X,X,X,X,X,
|
||||
};
|
||||
const SEVEN = [_]u32{
|
||||
const SEVEN = [_]u21{
|
||||
X,X,X,X,X,
|
||||
O,O,O,X,X,
|
||||
O,O,O,X,X,
|
||||
O,O,O,X,X,
|
||||
O,O,O,X,X,
|
||||
};
|
||||
const EIGHT = [_]u32{
|
||||
const EIGHT = [_]u21{
|
||||
X,X,X,X,X,
|
||||
X,X,O,X,X,
|
||||
X,X,X,X,X,
|
||||
X,X,O,X,X,
|
||||
X,X,X,X,X,
|
||||
};
|
||||
const NINE = [_]u32{
|
||||
const NINE = [_]u21{
|
||||
X,X,X,X,X,
|
||||
X,X,O,X,X,
|
||||
X,X,X,X,X,
|
||||
O,O,O,X,X,
|
||||
X,X,X,X,X,
|
||||
};
|
||||
const S = [_]u32{
|
||||
const S = [_]u21{
|
||||
O,O,O,O,O,
|
||||
O,O,X,O,O,
|
||||
O,O,O,O,O,
|
||||
O,O,X,O,O,
|
||||
O,O,O,O,O,
|
||||
};
|
||||
const E = [_]u32{
|
||||
const E = [_]u21{
|
||||
O,O,O,O,O,
|
||||
O,O,O,O,O,
|
||||
O,O,O,O,O,
|
||||
@@ -122,7 +122,7 @@ pub fn alphaBlit(buffer: [*]termbox.tb_cell, x: u64, y: u64, tb_width: u64, tb_h
|
||||
}
|
||||
}
|
||||
|
||||
fn toBigNumber(char: u8) []const u32 {
|
||||
fn toBigNumber(char: u8) []const u21 {
|
||||
return switch (char) {
|
||||
'0' => &ZERO,
|
||||
'1' => &ONE,
|
||||
|
||||
@@ -10,6 +10,7 @@ bg: u8 = 0,
|
||||
bigclock: bool = false,
|
||||
blank_box: bool = true,
|
||||
border_fg: u8 = 8,
|
||||
box_title: ?[]const u8 = null,
|
||||
clear_password: bool = false,
|
||||
clock: ?[:0]const u8 = null,
|
||||
console_dev: [:0]const u8 = "/dev/console",
|
||||
@@ -17,6 +18,7 @@ default_input: Input = .login,
|
||||
fg: u8 = 8,
|
||||
hide_borders: bool = false,
|
||||
hide_key_hints: bool = false,
|
||||
initial_info_text: ?[]const u8 = null,
|
||||
input_len: u8 = 34,
|
||||
lang: []const u8 = "en",
|
||||
load: bool = true,
|
||||
@@ -25,8 +27,9 @@ margin_box_v: u8 = 1,
|
||||
max_desktop_len: u8 = 100,
|
||||
max_login_len: u8 = 255,
|
||||
max_password_len: u8 = 255,
|
||||
mcookie_cmd: []const u8 = "/usr/bin/mcookie",
|
||||
mcookie_cmd: [:0]const u8 = "/usr/bin/mcookie",
|
||||
min_refresh_delta: u16 = 5,
|
||||
numlock: bool = false,
|
||||
path: ?[:0]const u8 = "/sbin:/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/sbin",
|
||||
restart_cmd: []const u8 = "/sbin/shutdown -r now",
|
||||
restart_key: []const u8 = "F2",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
authenticating: []const u8 = "authenticating...",
|
||||
capslock: []const u8 = "capslock",
|
||||
err_alloc: []const u8 = "failed memory allocation",
|
||||
err_bounds: []const u8 = "out-of-bounds index",
|
||||
@@ -5,7 +6,9 @@ err_chdir: []const u8 = "failed to open home folder",
|
||||
err_console_dev: []const u8 = "failed to access console",
|
||||
err_dgn_oob: []const u8 = "log message",
|
||||
err_domain: []const u8 = "invalid domain",
|
||||
err_envlist: []const u8 = "failed to get envlist",
|
||||
err_hostname: []const u8 = "failed to get hostname",
|
||||
err_mcookie: []const u8 = "mcookie command failed",
|
||||
err_mlock: []const u8 = "failed to lock password memory",
|
||||
err_null: []const u8 = "null pointer",
|
||||
err_pam: []const u8 = "pam transaction failed",
|
||||
@@ -33,6 +36,8 @@ err_unknown: []const u8 = "an unknown error occurred",
|
||||
err_user_gid: []const u8 = "failed to set user GID",
|
||||
err_user_init: []const u8 = "failed to initialize user",
|
||||
err_user_uid: []const u8 = "failed to set user UID",
|
||||
err_xauth: []const u8 = "xauth command failed",
|
||||
err_xcb_conn: []const u8 = "xcb connection failed",
|
||||
err_xsessions_dir: []const u8 = "failed to find sessions folder",
|
||||
err_xsessions_open: []const u8 = "failed to open sessions folder",
|
||||
insert: []const u8 = "insert",
|
||||
|
||||
@@ -2,9 +2,7 @@ const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
pub const termbox = @cImport({
|
||||
@cInclude("termbox.h");
|
||||
});
|
||||
pub const termbox = @import("termbox2");
|
||||
|
||||
pub const pam = @cImport({
|
||||
@cInclude("security/pam_appl.h");
|
||||
@@ -48,7 +46,9 @@ pub const VT_ACTIVATE: c_int = 0x5606;
|
||||
pub const VT_WAITACTIVE: c_int = 0x5607;
|
||||
|
||||
pub const KDGETLED: c_int = 0x4B31;
|
||||
pub const KDSETLED: c_int = 0x4B32;
|
||||
pub const KDGKBLED: c_int = 0x4B64;
|
||||
pub const KDSKBLED: c_int = 0x4B65;
|
||||
|
||||
pub const LED_NUM: c_int = 0x02;
|
||||
pub const LED_CAP: c_int = 0x04;
|
||||
@@ -106,3 +106,14 @@ pub fn getLockState(console_dev: [:0]const u8) !struct {
|
||||
.capslock = capslock,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn setNumlock(val: bool) !void {
|
||||
var led: c_char = undefined;
|
||||
_ = std.c.ioctl(0, KDGKBLED, &led);
|
||||
|
||||
const numlock = (led & K_NUMLOCK) != 0;
|
||||
if (numlock != val) {
|
||||
const status = std.c.ioctl(std.posix.STDIN_FILENO, KDSKBLED, led ^ K_NUMLOCK);
|
||||
if (status != 0) return error.FailedToSetNumlock;
|
||||
}
|
||||
}
|
||||
|
||||
126
src/main.zig
126
src/main.zig
@@ -33,7 +33,7 @@ pub fn signalHandler(i: c_int) callconv(.C) void {
|
||||
_ = std.c.waitpid(session_pid, &status, 0);
|
||||
}
|
||||
|
||||
termbox.tb_shutdown();
|
||||
_ = termbox.tb_shutdown();
|
||||
std.c.exit(i);
|
||||
}
|
||||
|
||||
@@ -127,8 +127,12 @@ pub fn main() !void {
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize information line with host name
|
||||
get_host_name: {
|
||||
interop.setNumlock(config.numlock) catch {};
|
||||
|
||||
if (config.initial_info_text) |text| {
|
||||
try info_line.setText(text);
|
||||
} else get_host_name: {
|
||||
// Initialize information line with host name
|
||||
var name_buf: [std.posix.HOST_NAME_MAX]u8 = undefined;
|
||||
const hostname = std.posix.gethostname(&name_buf) catch {
|
||||
try info_line.setText(lang.err_hostname);
|
||||
@@ -139,7 +143,7 @@ pub fn main() !void {
|
||||
|
||||
// Initialize termbox
|
||||
_ = termbox.tb_init();
|
||||
defer termbox.tb_shutdown();
|
||||
defer _ = termbox.tb_shutdown();
|
||||
|
||||
const act = std.posix.Sigaction{
|
||||
.handler = .{ .handler = &signalHandler },
|
||||
@@ -148,8 +152,8 @@ pub fn main() !void {
|
||||
};
|
||||
try std.posix.sigaction(std.posix.SIG.TERM, &act, null);
|
||||
|
||||
_ = termbox.tb_select_output_mode(termbox.TB_OUTPUT_NORMAL);
|
||||
termbox.tb_clear();
|
||||
_ = termbox.tb_set_output_mode(termbox.TB_OUTPUT_NORMAL);
|
||||
_ = termbox.tb_clear();
|
||||
|
||||
// Needed to reset termbox after auth
|
||||
const tb_termios = try std.posix.tcgetattr(std.posix.STDIN_FILENO);
|
||||
@@ -252,13 +256,11 @@ pub fn main() !void {
|
||||
|
||||
// Switch to selected TTY if possible
|
||||
open_console_dev: {
|
||||
const fd = std.c.open(config.console_dev, .{ .ACCMODE = .WRONLY });
|
||||
defer _ = std.c.close(fd);
|
||||
|
||||
if (fd < 0) {
|
||||
const fd = std.posix.open(config.console_dev, .{ .ACCMODE = .WRONLY }, 0) catch {
|
||||
try info_line.setText(lang.err_console_dev);
|
||||
break :open_console_dev;
|
||||
}
|
||||
};
|
||||
defer std.posix.close(fd);
|
||||
|
||||
_ = std.c.ioctl(fd, interop.VT_ACTIVATE, config.tty);
|
||||
_ = std.c.ioctl(fd, interop.VT_WAITACTIVE, config.tty);
|
||||
@@ -267,9 +269,9 @@ pub fn main() !void {
|
||||
while (run) {
|
||||
// If there's no input or there's an animation, a resolution change needs to be checked
|
||||
if (!update or config.animation != .none) {
|
||||
if (!update) std.time.sleep(100_000_000);
|
||||
if (!update) std.time.sleep(std.time.ns_per_ms * 100);
|
||||
|
||||
termbox.tb_present(); // Required to update tb_width(), tb_height() and tb_cell_buffer()
|
||||
_ = termbox.tb_present(); // Required to update tb_width(), tb_height() and tb_cell_buffer()
|
||||
|
||||
const width: u64 = @intCast(termbox.tb_width());
|
||||
const height: u64 = @intCast(termbox.tb_height());
|
||||
@@ -305,17 +307,7 @@ pub fn main() !void {
|
||||
if (update) {
|
||||
// If the user entered a wrong password 10 times in a row, play a cascade animation, else update normally
|
||||
if (auth_fails < 10) {
|
||||
switch (active_input) {
|
||||
.session => desktop.handle(null, insert_mode),
|
||||
.login => login.handle(null, insert_mode) catch {
|
||||
try info_line.setText(lang.err_alloc);
|
||||
},
|
||||
.password => password.handle(null, insert_mode) catch {
|
||||
try info_line.setText(lang.err_alloc);
|
||||
},
|
||||
}
|
||||
|
||||
termbox.tb_clear();
|
||||
_ = termbox.tb_clear();
|
||||
|
||||
switch (config.animation) {
|
||||
.none => {},
|
||||
@@ -325,7 +317,7 @@ pub fn main() !void {
|
||||
|
||||
if (config.bigclock and buffer.box_height + (bigclock.HEIGHT + 2) * 2 < buffer.height) draw_big_clock: {
|
||||
const format = "%H:%M";
|
||||
const xo = buffer.width / 2 - (format.len * (bigclock.WIDTH + 1)) / 2;
|
||||
const xo = buffer.width / 2 - @min(buffer.width, (format.len * (bigclock.WIDTH + 1))) / 2;
|
||||
const yo = (buffer.height - buffer.box_height) / 2 - bigclock.HEIGHT - 2;
|
||||
|
||||
var clock_buf: [format.len + 1:0]u8 = undefined;
|
||||
@@ -341,6 +333,25 @@ pub fn main() !void {
|
||||
|
||||
buffer.drawBoxCenter(!config.hide_borders, config.blank_box);
|
||||
|
||||
if (resolution_changed) {
|
||||
const coordinates = buffer.calculateComponentCoordinates();
|
||||
desktop.position(coordinates.x, coordinates.y + 2, coordinates.visible_length);
|
||||
login.position(coordinates.x, coordinates.y + 4, coordinates.visible_length);
|
||||
password.position(coordinates.x, coordinates.y + 6, coordinates.visible_length);
|
||||
|
||||
resolution_changed = false;
|
||||
}
|
||||
|
||||
switch (active_input) {
|
||||
.session => desktop.handle(null, insert_mode),
|
||||
.login => login.handle(null, insert_mode) catch {
|
||||
try info_line.setText(lang.err_alloc);
|
||||
},
|
||||
.password => password.handle(null, insert_mode) catch {
|
||||
try info_line.setText(lang.err_alloc);
|
||||
},
|
||||
}
|
||||
|
||||
if (config.clock) |clock| draw_clock: {
|
||||
var clock_buf: [32:0]u8 = undefined;
|
||||
const clock_str = interop.timeAsString(&clock_buf, clock) catch {
|
||||
@@ -349,7 +360,7 @@ pub fn main() !void {
|
||||
|
||||
if (clock_str.len == 0) return error.FormattedTimeEmpty;
|
||||
|
||||
buffer.drawLabel(clock_str, buffer.width - clock_str.len, 0);
|
||||
buffer.drawLabel(clock_str, buffer.width - @min(buffer.width, clock_str.len), 0);
|
||||
}
|
||||
|
||||
const label_x = buffer.box_x + buffer.margin_box_h;
|
||||
@@ -358,10 +369,7 @@ pub fn main() !void {
|
||||
buffer.drawLabel(lang.login, label_x, label_y + 4);
|
||||
buffer.drawLabel(lang.password, label_x, label_y + 6);
|
||||
|
||||
if (info_line.width > 0 and buffer.box_width > info_line.width) {
|
||||
const x = buffer.box_x + ((buffer.box_width - info_line.width) / 2);
|
||||
buffer.drawLabel(info_line.text, x, label_y);
|
||||
}
|
||||
info_line.draw(buffer);
|
||||
|
||||
if (!config.hide_key_hints) {
|
||||
var length: u64 = 0;
|
||||
@@ -389,9 +397,13 @@ pub fn main() !void {
|
||||
}
|
||||
}
|
||||
|
||||
if (config.box_title) |title| {
|
||||
buffer.drawConfinedLabel(title, buffer.box_x, buffer.box_y - 1, buffer.box_width);
|
||||
}
|
||||
|
||||
if (config.vi_mode) {
|
||||
const label_txt = if (insert_mode) lang.insert else lang.normal;
|
||||
buffer.drawLabel(label_txt, buffer.box_x, buffer.box_y - 1);
|
||||
buffer.drawLabel(label_txt, buffer.box_x, buffer.box_y + buffer.box_height);
|
||||
}
|
||||
|
||||
draw_lock_state: {
|
||||
@@ -400,21 +412,15 @@ pub fn main() !void {
|
||||
break :draw_lock_state;
|
||||
};
|
||||
|
||||
var lock_state_x = buffer.width - lang.numlock.len;
|
||||
var lock_state_x = buffer.width - @min(buffer.width, lang.numlock.len);
|
||||
const lock_state_y: u64 = if (config.clock != null) 1 else 0;
|
||||
|
||||
if (lock_state.numlock) buffer.drawLabel(lang.numlock, lock_state_x, lock_state_y);
|
||||
lock_state_x -= lang.capslock.len + 1;
|
||||
if (lock_state.capslock) buffer.drawLabel(lang.capslock, lock_state_x, lock_state_y);
|
||||
}
|
||||
|
||||
if (resolution_changed) {
|
||||
const coordinates = buffer.calculateComponentCoordinates();
|
||||
desktop.position(coordinates.x, coordinates.y + 2, coordinates.visible_length);
|
||||
login.position(coordinates.x, coordinates.y + 4, coordinates.visible_length);
|
||||
password.position(coordinates.x, coordinates.y + 6, coordinates.visible_length);
|
||||
|
||||
resolution_changed = false;
|
||||
if (lock_state_x >= lang.capslock.len + 1) {
|
||||
lock_state_x -= lang.capslock.len + 1;
|
||||
if (lock_state.capslock) buffer.drawLabel(lang.capslock, lock_state_x, lock_state_y);
|
||||
}
|
||||
}
|
||||
|
||||
desktop.draw();
|
||||
@@ -423,16 +429,16 @@ pub fn main() !void {
|
||||
|
||||
update = animate;
|
||||
} else {
|
||||
std.time.sleep(10_000_000);
|
||||
std.time.sleep(std.time.ns_per_ms * 10);
|
||||
update = buffer.cascade();
|
||||
|
||||
if (!update) {
|
||||
std.time.sleep(7_000_000_000);
|
||||
std.time.sleep(std.time.ns_per_s * 7);
|
||||
auth_fails = 0;
|
||||
}
|
||||
}
|
||||
|
||||
termbox.tb_present();
|
||||
_ = termbox.tb_present();
|
||||
}
|
||||
|
||||
var timeout: i32 = -1;
|
||||
@@ -510,9 +516,18 @@ pub fn main() !void {
|
||||
};
|
||||
update = true;
|
||||
},
|
||||
termbox.TB_KEY_BACK_TAB => {
|
||||
active_input = switch (active_input) {
|
||||
.session => .password,
|
||||
.login => .session,
|
||||
.password => .login,
|
||||
};
|
||||
|
||||
update = true;
|
||||
},
|
||||
termbox.TB_KEY_ENTER => {
|
||||
if (config.save) save_last_settings: {
|
||||
var file = std.fs.createFileAbsolute(save_path, .{}) catch break :save_last_settings;
|
||||
var file = std.fs.cwd().createFile(save_path, .{}) catch break :save_last_settings;
|
||||
defer file.close();
|
||||
|
||||
const save_data = Save{
|
||||
@@ -531,9 +546,15 @@ pub fn main() !void {
|
||||
const password_text = try allocator.dupeZ(u8, password.text.items);
|
||||
defer allocator.free(password_text);
|
||||
|
||||
try info_line.setText(lang.authenticating);
|
||||
InfoLine.clearRendered(allocator, buffer) catch {};
|
||||
info_line.draw(buffer);
|
||||
_ = termbox.tb_present();
|
||||
|
||||
session_pid = try std.posix.fork();
|
||||
if (session_pid == 0) {
|
||||
auth.authenticate(config, desktop, login_text, password_text) catch |err| {
|
||||
const current_environment = desktop.environments.items[desktop.current];
|
||||
auth.authenticate(config, current_environment, login_text, password_text) catch |err| {
|
||||
shared_err.writeError(err);
|
||||
std.process.exit(1);
|
||||
};
|
||||
@@ -556,14 +577,15 @@ pub fn main() !void {
|
||||
}
|
||||
|
||||
try std.posix.tcsetattr(std.posix.STDIN_FILENO, .FLUSH, tb_termios);
|
||||
termbox.tb_clear();
|
||||
if (auth_fails < 10) {
|
||||
_ = termbox.tb_clear();
|
||||
_ = termbox.tb_present();
|
||||
}
|
||||
|
||||
update = true;
|
||||
|
||||
var restore_cursor = std.ChildProcess.init(&[_][]const u8{ "/bin/sh", "-c", config.term_restore_cursor_cmd }, allocator);
|
||||
_ = restore_cursor.spawnAndWait() catch .{};
|
||||
|
||||
termbox.tb_present();
|
||||
},
|
||||
else => {
|
||||
if (!insert_mode) {
|
||||
@@ -617,6 +639,10 @@ pub fn main() !void {
|
||||
fn getAuthErrorMsg(err: anyerror, lang: Lang) []const u8 {
|
||||
return switch (err) {
|
||||
error.GetPasswordNameFailed => lang.err_pwnam,
|
||||
error.GetEnvListFailed => lang.err_envlist,
|
||||
error.XauthFailed => lang.err_xauth,
|
||||
error.McookieFailed => lang.err_mcookie,
|
||||
error.XcbConnectionFailed => lang.err_xcb_conn,
|
||||
error.GroupInitializationFailed => lang.err_user_init,
|
||||
error.SetUserGidFailed => lang.err_user_gid,
|
||||
error.SetUserUidFailed => lang.err_user_uid,
|
||||
|
||||
@@ -100,34 +100,35 @@ pub fn cascade(self: TerminalBuffer) bool {
|
||||
}
|
||||
|
||||
pub fn drawBoxCenter(self: *TerminalBuffer, show_borders: bool, blank_box: bool) void {
|
||||
const x1 = (self.width - self.box_width) / 2;
|
||||
const y1 = (self.height - self.box_height) / 2;
|
||||
const x2 = (self.width + self.box_width) / 2;
|
||||
const y2 = (self.height + self.box_height) / 2;
|
||||
if (self.width < 2 or self.height < 2) return;
|
||||
const x1 = (self.width - @min(self.width - 2, self.box_width)) / 2;
|
||||
const y1 = (self.height - @min(self.height - 2, self.box_height)) / 2;
|
||||
const x2 = (self.width + @min(self.width, self.box_width)) / 2;
|
||||
const y2 = (self.height + @min(self.height, self.box_height)) / 2;
|
||||
|
||||
self.box_x = x1;
|
||||
self.box_y = y1;
|
||||
|
||||
if (show_borders) {
|
||||
termbox.tb_change_cell(@intCast(x1 - 1), @intCast(y1 - 1), self.box_chars.left_up, self.border_fg, self.bg);
|
||||
termbox.tb_change_cell(@intCast(x2), @intCast(y1 - 1), self.box_chars.right_up, self.border_fg, self.bg);
|
||||
termbox.tb_change_cell(@intCast(x1 - 1), @intCast(y2), self.box_chars.left_down, self.border_fg, self.bg);
|
||||
termbox.tb_change_cell(@intCast(x2), @intCast(y2), self.box_chars.right_down, self.border_fg, self.bg);
|
||||
_ = termbox.tb_set_cell(@intCast(x1 - 1), @intCast(y1 - 1), self.box_chars.left_up, self.border_fg, self.bg);
|
||||
_ = termbox.tb_set_cell(@intCast(x2), @intCast(y1 - 1), self.box_chars.right_up, self.border_fg, self.bg);
|
||||
_ = termbox.tb_set_cell(@intCast(x1 - 1), @intCast(y2), self.box_chars.left_down, self.border_fg, self.bg);
|
||||
_ = termbox.tb_set_cell(@intCast(x2), @intCast(y2), self.box_chars.right_down, self.border_fg, self.bg);
|
||||
|
||||
var c1 = utils.initCell(self.box_chars.top, self.border_fg, self.bg);
|
||||
var c2 = utils.initCell(self.box_chars.bottom, self.border_fg, self.bg);
|
||||
|
||||
for (0..self.box_width) |i| {
|
||||
termbox.tb_put_cell(@intCast(x1 + i), @intCast(y1 - 1), &c1);
|
||||
termbox.tb_put_cell(@intCast(x1 + i), @intCast(y2), &c2);
|
||||
_ = utils.putCell(@intCast(x1 + i), @intCast(y1 - 1), &c1);
|
||||
_ = utils.putCell(@intCast(x1 + i), @intCast(y2), &c2);
|
||||
}
|
||||
|
||||
c1.ch = self.box_chars.left;
|
||||
c2.ch = self.box_chars.right;
|
||||
|
||||
for (0..self.box_height) |i| {
|
||||
termbox.tb_put_cell(@intCast(x1 - 1), @intCast(y1 + i), &c1);
|
||||
termbox.tb_put_cell(@intCast(x2), @intCast(y1 + i), &c2);
|
||||
_ = utils.putCell(@intCast(x1 - 1), @intCast(y1 + i), &c1);
|
||||
_ = utils.putCell(@intCast(x2), @intCast(y1 + i), &c2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +137,7 @@ pub fn drawBoxCenter(self: *TerminalBuffer, show_borders: bool, blank_box: bool)
|
||||
|
||||
for (0..self.box_height) |y| {
|
||||
for (0..self.box_width) |x| {
|
||||
termbox.tb_put_cell(@intCast(x1 + x), @intCast(y1 + y), &blank);
|
||||
_ = utils.putCell(@intCast(x1 + x), @intCast(y1 + y), &blank);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -165,7 +166,19 @@ pub fn drawLabel(self: TerminalBuffer, text: []const u8, x: u64, y: u64) void {
|
||||
|
||||
var i = x;
|
||||
while (utf8.nextCodepoint()) |codepoint| : (i += 1) {
|
||||
termbox.tb_change_cell(@intCast(i), yc, codepoint, self.fg, self.bg);
|
||||
_ = termbox.tb_set_cell(@intCast(i), yc, codepoint, self.fg, self.bg);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn drawConfinedLabel(self: TerminalBuffer, text: []const u8, x: u64, y: u64, max_length: u64) void {
|
||||
const yc: c_int = @intCast(y);
|
||||
const utf8view = std.unicode.Utf8View.init(text) catch return;
|
||||
var utf8 = utf8view.iterator();
|
||||
|
||||
var i: usize = 0;
|
||||
while (utf8.nextCodepoint()) |codepoint| : (i += 1) {
|
||||
if (i >= max_length) break;
|
||||
_ = termbox.tb_set_cell(@intCast(i + x), yc, codepoint, self.fg, self.bg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,5 +186,5 @@ pub fn drawCharMultiple(self: TerminalBuffer, char: u8, x: u64, y: u64, length:
|
||||
const yc: c_int = @intCast(y);
|
||||
const cell = utils.initCell(char, self.fg, self.bg);
|
||||
|
||||
for (0..length) |xx| termbox.tb_put_cell(@intCast(x + xx), yc, &cell);
|
||||
for (0..length) |xx| _ = utils.putCell(@intCast(x + xx), yc, &cell);
|
||||
}
|
||||
|
||||
@@ -185,7 +185,7 @@ pub fn handle(self: *Desktop, maybe_event: ?*termbox.tb_event, insert_mode: bool
|
||||
}
|
||||
}
|
||||
|
||||
termbox.tb_set_cursor(@intCast(self.x + 2), @intCast(self.y));
|
||||
_ = termbox.tb_set_cursor(@intCast(self.x + 2), @intCast(self.y));
|
||||
}
|
||||
|
||||
pub fn draw(self: Desktop) void {
|
||||
@@ -198,8 +198,8 @@ pub fn draw(self: Desktop) void {
|
||||
const y = self.buffer.box_y + self.buffer.margin_box_v + 2;
|
||||
self.buffer.drawLabel(environment.specifier, x, y);
|
||||
|
||||
termbox.tb_change_cell(@intCast(self.x), @intCast(self.y), '<', self.buffer.fg, self.buffer.bg);
|
||||
termbox.tb_change_cell(@intCast(self.x + self.visible_length - 1), @intCast(self.y), '>', self.buffer.fg, self.buffer.bg);
|
||||
_ = termbox.tb_set_cell(@intCast(self.x), @intCast(self.y), '<', self.buffer.fg, self.buffer.bg);
|
||||
_ = termbox.tb_set_cell(@intCast(self.x + self.visible_length - 1), @intCast(self.y), '>', self.buffer.fg, self.buffer.bg);
|
||||
|
||||
self.buffer.drawLabel(environment.name, self.x + 2, self.y);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
const std = @import("std");
|
||||
const utils = @import("../utils.zig");
|
||||
const TerminalBuffer = @import("../TerminalBuffer.zig");
|
||||
|
||||
const InfoLine = @This();
|
||||
|
||||
@@ -9,3 +11,23 @@ pub fn setText(self: *InfoLine, text: []const u8) !void {
|
||||
self.width = if (text.len > 0) try utils.strWidth(text) else 0;
|
||||
self.text = text;
|
||||
}
|
||||
|
||||
pub fn draw(self: InfoLine, buffer: TerminalBuffer) void {
|
||||
if (self.width > 0 and buffer.box_width > self.width) {
|
||||
const label_y = buffer.box_y + buffer.margin_box_v;
|
||||
const x = buffer.box_x + ((buffer.box_width - self.width) / 2);
|
||||
|
||||
buffer.drawLabel(self.text, x, label_y);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clearRendered(allocator: std.mem.Allocator, buffer: TerminalBuffer) !void {
|
||||
// draw over the area
|
||||
const y = buffer.box_y + buffer.margin_box_v;
|
||||
const spaces = try allocator.alloc(u8, buffer.box_width);
|
||||
defer allocator.free(spaces);
|
||||
|
||||
@memset(spaces, ' ');
|
||||
|
||||
buffer.drawLabel(spaces, buffer.box_x, y);
|
||||
}
|
||||
|
||||
@@ -78,14 +78,21 @@ pub fn handle(self: *Text, maybe_event: ?*termbox.tb_event, insert_mode: bool) !
|
||||
}
|
||||
}
|
||||
|
||||
termbox.tb_set_cursor(@intCast(self.x + (self.cursor - self.visible_start)), @intCast(self.y));
|
||||
_ = termbox.tb_set_cursor(@intCast(self.x + (self.cursor - self.visible_start)), @intCast(self.y));
|
||||
}
|
||||
|
||||
pub fn draw(self: Text) void {
|
||||
const length = @min(self.text.items.len, self.visible_length);
|
||||
if (length == 0) return;
|
||||
|
||||
const visible_slice = if (self.text.items.len > self.visible_length and self.cursor < self.text.items.len) self.text.items[self.visible_start..(self.visible_length + self.visible_start)] else self.text.items[self.visible_start..];
|
||||
const visible_slice = vs: {
|
||||
if (self.text.items.len > self.visible_length and self.cursor < self.text.items.len) {
|
||||
break :vs self.text.items[self.visible_start..(self.visible_length + self.visible_start)];
|
||||
} else {
|
||||
break :vs self.text.items[self.visible_start..];
|
||||
}
|
||||
};
|
||||
|
||||
self.buffer.drawLabel(visible_slice, self.x, self.y);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ const interop = @import("../interop.zig");
|
||||
|
||||
const termbox = interop.termbox;
|
||||
|
||||
pub fn initCell(ch: u32, fg: u32, bg: u32) termbox.tb_cell {
|
||||
pub fn initCell(ch: u32, fg: u16, bg: u16) termbox.tb_cell {
|
||||
return .{
|
||||
.ch = ch,
|
||||
.fg = fg,
|
||||
@@ -11,6 +11,10 @@ pub fn initCell(ch: u32, fg: u32, bg: u32) termbox.tb_cell {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn putCell(x: i32, y: i32, cell: *const termbox.tb_cell) c_int {
|
||||
return termbox.tb_set_cell(x, y, cell.ch, cell.fg, cell.bg);
|
||||
}
|
||||
|
||||
// Every codepoint is assumed to have a width of 1.
|
||||
// Since ly should be running in a tty, this should be fine.
|
||||
pub fn strWidth(str: []const u8) !u8 {
|
||||
|
||||
Reference in New Issue
Block a user