Add option to run command after inactivity delay (closes #747)

Signed-off-by: AnErrupTion <anerruption@disroot.org>
This commit is contained in:
AnErrupTion
2025-12-03 20:39:27 +01:00
parent 6cce221cbf
commit 3bfdc75a70
25 changed files with 64 additions and 6 deletions

View File

@@ -231,6 +231,13 @@ hide_keyboard_locks = false
# Remove version number from the top left corner # Remove version number from the top left corner
hide_version_string = false hide_version_string = false
# Command executed when no input is detected for a certain time
# If null, no command will be executed
inactivity_cmd = null
# Executes a command after a certain amount of seconds
inactivity_delay = 0
# Initial text to show on the info line # Initial text to show on the info line
# If set to null, the info line defaults to the hostname # If set to null, the info line defaults to the hostname
initial_info_text = null initial_info_text = null

View File

@@ -21,6 +21,7 @@ err_envlist = فشل في جلب قائمة المتغيرات البيئية
err_hostname = فشل في جلب اسم المضيف (Hostname) err_hostname = فشل في جلب اسم المضيف (Hostname)
err_mlock = فشل في تأمين ذاكرة كلمة المرور (mlock) err_mlock = فشل في تأمين ذاكرة كلمة المرور (mlock)
err_null = مؤشر فارغ (Null pointer) err_null = مؤشر فارغ (Null pointer)
err_numlock = فشل في ضبط Num Lock err_numlock = فشل في ضبط Num Lock

View File

@@ -19,6 +19,7 @@ err_envlist = неуспешно получаване на списъка с п
err_get_active_tty = неуспешно откриване на активния TTY err_get_active_tty = неуспешно откриване на активния TTY
err_hibernate = неуспешно изпълнение на командата за хибернация err_hibernate = неуспешно изпълнение на командата за хибернация
err_hostname = неуспешно получаване на името на хоста err_hostname = неуспешно получаване на името на хоста
err_lock_state = неуспешно получаване на състоянието на заключване err_lock_state = неуспешно получаване на състоянието на заключване
err_log = неуспешно отваряне на файла с дневника err_log = неуспешно отваряне на файла с дневника
err_mlock = неуспешно заключване на паметта за паролата err_mlock = неуспешно заключване на паметта за паролата

View File

@@ -21,6 +21,7 @@ err_envlist = error en obtenir l'envlist
err_hostname = error en obtenir el nom de l'amfitrió err_hostname = error en obtenir el nom de l'amfitrió
err_mlock = error en bloquejar la memòria de clau err_mlock = error en bloquejar la memòria de clau
err_null = punter nul err_null = punter nul
err_numlock = error en establir el Bloq num err_numlock = error en establir el Bloq num

View File

@@ -21,6 +21,7 @@ err_domain = neplatná doména
err_hostname = nelze získat název hostitele err_hostname = nelze získat název hostitele
err_mlock = uzamčení paměti hesel selhalo err_mlock = uzamčení paměti hesel selhalo
err_null = nulový ukazatel err_null = nulový ukazatel

View File

@@ -21,6 +21,7 @@ err_envlist = Fehler beim Abrufen der Umgebungs-Variablen
err_hostname = Abrufen des Hostnames fehlgeschlagen err_hostname = Abrufen des Hostnames fehlgeschlagen
err_mlock = Sperren des Passwortspeichers fehlgeschlagen err_mlock = Sperren des Passwortspeichers fehlgeschlagen
err_null = Null Pointer err_null = Null Pointer
err_numlock = Numlock konnte nicht aktiviert werden err_numlock = Numlock konnte nicht aktiviert werden

View File

@@ -19,6 +19,7 @@ err_envlist = failed to get envlist
err_get_active_tty = failed to get active tty err_get_active_tty = failed to get active tty
err_hibernate = failed to execute hibernate command err_hibernate = failed to execute hibernate command
err_hostname = failed to get hostname err_hostname = failed to get hostname
err_inactivity = failed to execute inactivity command
err_lock_state = failed to get lock state err_lock_state = failed to get lock state
err_log = failed to open log file err_log = failed to open log file
err_mlock = failed to lock password memory err_mlock = failed to lock password memory

View File

@@ -21,6 +21,7 @@ err_domain = dominio inválido
err_hostname = error al obtener el nombre de host err_hostname = error al obtener el nombre de host
err_mlock = error al bloquear la contraseña de memoria err_mlock = error al bloquear la contraseña de memoria
err_null = puntero nulo err_null = puntero nulo

View File

@@ -19,6 +19,7 @@ err_envlist = échec de lecture de la liste d'environnement
err_get_active_tty = échec de lecture du terminal actif err_get_active_tty = échec de lecture du terminal actif
err_hibernate = échec de l'exécution de la commande de veille prolongée err_hibernate = échec de l'exécution de la commande de veille prolongée
err_hostname = échec de lecture du nom d'hôte err_hostname = échec de lecture du nom d'hôte
err_inactivity = échec de l'exécution de la commande d'inactivité
err_lock_state = échec de lecture de l'état de verrouillage err_lock_state = échec de lecture de l'état de verrouillage
err_log = échec de l'ouverture du fichier de journal err_log = échec de l'ouverture du fichier de journal
err_mlock = échec du verrouillage mémoire err_mlock = échec du verrouillage mémoire

View File

@@ -21,6 +21,7 @@ err_domain = dominio non valido
err_hostname = impossibile ottenere hostname err_hostname = impossibile ottenere hostname
err_mlock = impossibile ottenere lock per la password in memoria err_mlock = impossibile ottenere lock per la password in memoria
err_null = puntatore nullo err_null = puntatore nullo

View File

@@ -21,6 +21,7 @@ err_envlist = 環境変数リストの取得に失敗しました
err_hostname = ホスト名の取得に失敗しました err_hostname = ホスト名の取得に失敗しました
err_mlock = パスワードメモリのロックに失敗しました err_mlock = パスワードメモリのロックに失敗しました
err_null = ヌルポインタ err_null = ヌルポインタ
err_numlock = NumLockの設定に失敗しました err_numlock = NumLockの設定に失敗しました

View File

@@ -19,6 +19,7 @@ err_envlist = neizdevās iegūt vides mainīgo sarakstu
err_get_active_tty = neizdevās iegūt aktīvo tty err_get_active_tty = neizdevās iegūt aktīvo tty
err_hostname = neizdevās iegūt hostname err_hostname = neizdevās iegūt hostname
err_lock_state = neizdevās iegūt bloķēšanas stāvokli err_lock_state = neizdevās iegūt bloķēšanas stāvokli
err_log = neizdevās atvērt žurnāla failu err_log = neizdevās atvērt žurnāla failu
err_mlock = neizdevās bloķēt paroles atmiņu err_mlock = neizdevās bloķēt paroles atmiņu

View File

@@ -19,6 +19,7 @@ err_envlist = nie udało się pobrać listy zmiennych środowiskowych
err_get_active_tty = nie udało się uzyskać aktywnego tty err_get_active_tty = nie udało się uzyskać aktywnego tty
err_hostname = nie udało się uzyskać nazwy hosta err_hostname = nie udało się uzyskać nazwy hosta
err_lock_state = nie udało się uzyskać stanu blokady err_lock_state = nie udało się uzyskać stanu blokady
err_log = nie udało się otworzyć pliku logu err_log = nie udało się otworzyć pliku logu
err_mlock = nie udało się zablokować pamięci haseł err_mlock = nie udało się zablokować pamięci haseł

View File

@@ -21,6 +21,7 @@ err_domain = domínio inválido
err_hostname = erro ao obter o nome do host err_hostname = erro ao obter o nome do host
err_mlock = erro de bloqueio de memória err_mlock = erro de bloqueio de memória
err_null = ponteiro nulo err_null = ponteiro nulo

View File

@@ -21,6 +21,7 @@ err_domain = domínio inválido
err_hostname = não foi possível obter o nome do host err_hostname = não foi possível obter o nome do host
err_mlock = bloqueio da memória de senha malsucedido err_mlock = bloqueio da memória de senha malsucedido
err_null = ponteiro nulo err_null = ponteiro nulo

View File

@@ -23,6 +23,7 @@ capslock = capslock
err_pam_abort = tranzacţie pam anulată err_pam_abort = tranzacţie pam anulată

View File

@@ -19,6 +19,7 @@ err_envlist = не удалось получить список переменн
err_get_active_tty = не удалось получить активный tty err_get_active_tty = не удалось получить активный tty
err_hostname = не удалось получить имя хоста err_hostname = не удалось получить имя хоста
err_lock_state = не удалось получить состояние lock err_lock_state = не удалось получить состояние lock
err_log = не удалось открыть файл log err_log = не удалось открыть файл log
err_mlock = сбой блокировки памяти err_mlock = сбой блокировки памяти

View File

@@ -21,6 +21,7 @@ err_domain = nevazeci domen
err_hostname = neuspijesno trazenje hostname-a err_hostname = neuspijesno trazenje hostname-a
err_mlock = neuspijesno zakljucavanje memorije lozinke err_mlock = neuspijesno zakljucavanje memorije lozinke
err_null = null pokazivac err_null = null pokazivac

View File

@@ -21,6 +21,7 @@ err_domain = okänd domän
err_hostname = misslyckades att hämta värdnamn err_hostname = misslyckades att hämta värdnamn
err_mlock = misslyckades att låsa lösenordsminne err_mlock = misslyckades att låsa lösenordsminne
err_null = nullpekare err_null = nullpekare

View File

@@ -21,6 +21,7 @@ err_domain = gecersiz etki alani
err_hostname = ana bilgisayar adi alinamadi err_hostname = ana bilgisayar adi alinamadi
err_mlock = parola bellegi kilitlenemedi err_mlock = parola bellegi kilitlenemedi
err_null = bos isaretci hatasi err_null = bos isaretci hatasi

View File

@@ -21,6 +21,7 @@ err_domain = недійсний домен
err_hostname = не вдалося отримати ім'я хосту err_hostname = не вдалося отримати ім'я хосту
err_mlock = збій блокування пам'яті err_mlock = збій блокування пам'яті
err_null = нульовий вказівник err_null = нульовий вказівник

View File

@@ -21,6 +21,7 @@ err_domain = 无效的域
err_hostname = 获取主机名失败 err_hostname = 获取主机名失败
err_mlock = 锁定密码存储器失败 err_mlock = 锁定密码存储器失败
err_null = 空指针 err_null = 空指针

View File

@@ -57,6 +57,8 @@ hide_borders: bool = false,
hide_key_hints: bool = false, hide_key_hints: bool = false,
hide_keyboard_locks: bool = false, hide_keyboard_locks: bool = false,
hide_version_string: bool = false, hide_version_string: bool = false,
inactivity_cmd: ?[]const u8 = null,
inactivity_delay: u16 = 0,
initial_info_text: ?[]const u8 = null, initial_info_text: ?[]const u8 = null,
input_len: u8 = 34, input_len: u8 = 34,
lang: []const u8 = "en", lang: []const u8 = "en",

View File

@@ -24,6 +24,7 @@ err_envlist: []const u8 = "failed to get envlist",
err_get_active_tty: []const u8 = "failed to get active tty", err_get_active_tty: []const u8 = "failed to get active tty",
err_hibernate: []const u8 = "failed to execute hibernate command", err_hibernate: []const u8 = "failed to execute hibernate command",
err_hostname: []const u8 = "failed to get hostname", err_hostname: []const u8 = "failed to get hostname",
err_inactivity: []const u8 = "failed to execute inactivity command",
err_lock_state: []const u8 = "failed to get lock state", err_lock_state: []const u8 = "failed to get lock state",
err_log: []const u8 = "failed to open log file", err_log: []const u8 = "failed to open log file",
err_mlock: []const u8 = "failed to lock password memory", err_mlock: []const u8 = "failed to lock password memory",

View File

@@ -98,7 +98,7 @@ pub fn main() !void {
defer _ = gpa.deinit(); defer _ = gpa.deinit();
// Allows stopping an animation after some time // Allows stopping an animation after some time
const time_start = try interop.getTimeOfDay(); const animation_time_start = try interop.getTimeOfDay();
var animation_timed_out: bool = false; var animation_timed_out: bool = false;
const allocator = gpa.allocator(); const allocator = gpa.allocator();
@@ -284,12 +284,12 @@ pub fn main() !void {
commands_allocated = true; commands_allocated = true;
if (config.start_cmd) |start_cmd| { if (config.start_cmd) |start_cmd| {
var sleep = std.process.Child.init(&[_][]const u8{ "/bin/sh", "-c", start_cmd }, allocator); var start = std.process.Child.init(&[_][]const u8{ "/bin/sh", "-c", start_cmd }, allocator);
sleep.stdout_behavior = .Ignore; start.stdout_behavior = .Ignore;
sleep.stderr_behavior = .Ignore; start.stderr_behavior = .Ignore;
handle_start_cmd: { handle_start_cmd: {
const process_result = sleep.spawnAndWait() catch { const process_result = start.spawnAndWait() catch {
break :handle_start_cmd; break :handle_start_cmd;
}; };
start_cmd_exit_code = process_result.Exited; start_cmd_exit_code = process_result.Exited;
@@ -594,6 +594,8 @@ pub fn main() !void {
var update = true; var update = true;
var resolution_changed = false; var resolution_changed = false;
var auth_fails: u64 = 0; var auth_fails: u64 = 0;
var inactivity_time_start = try interop.getTimeOfDay();
var inactivity_cmd_ran = false;
// Switch to selected TTY // Switch to selected TTY
const active_tty = interop.getActiveTty(allocator) catch |err| no_tty_found: { const active_tty = interop.getActiveTty(allocator) catch |err| no_tty_found: {
@@ -858,7 +860,7 @@ pub fn main() !void {
// Check how long we've been running so we can turn off the animation // Check how long we've been running so we can turn off the animation
const time = try interop.getTimeOfDay(); const time = try interop.getTimeOfDay();
if (config.animation_timeout_sec > 0 and time.seconds - time_start.seconds > config.animation_timeout_sec) { if (config.animation_timeout_sec > 0 and time.seconds - animation_time_start.seconds > config.animation_timeout_sec) {
animation_timed_out = true; animation_timed_out = true;
animation.deinit(); animation.deinit();
} }
@@ -872,6 +874,28 @@ pub fn main() !void {
timeout = @intCast(1000 - @divTrunc(time.microseconds, 1000) + 1); timeout = @intCast(1000 - @divTrunc(time.microseconds, 1000) + 1);
} }
if (config.inactivity_cmd) |inactivity_cmd| {
const time = try interop.getTimeOfDay();
if (!inactivity_cmd_ran and time.seconds - inactivity_time_start.seconds > config.inactivity_delay) {
var inactivity = std.process.Child.init(&[_][]const u8{ "/bin/sh", "-c", inactivity_cmd }, allocator);
inactivity.stdout_behavior = .Ignore;
inactivity.stderr_behavior = .Ignore;
handle_inactivity_cmd: {
const process_result = inactivity.spawnAndWait() catch {
break :handle_inactivity_cmd;
};
if (process_result.Exited != 0) {
try info_line.addMessage(lang.err_inactivity, config.error_bg, config.error_fg);
try log_writer.print("failed to execute inactivity command: exit code {d}\n", .{process_result.Exited});
}
}
inactivity_cmd_ran = true;
}
}
// Skip event polling if autologin is set, use simulated Enter key press instead // Skip event polling if autologin is set, use simulated Enter key press instead
if (is_autologin) { if (is_autologin) {
event = termbox.tb_event{ event = termbox.tb_event{
@@ -892,6 +916,9 @@ pub fn main() !void {
if (event_error < 0 or event.type != termbox.TB_EVENT_KEY) continue; if (event_error < 0 or event.type != termbox.TB_EVENT_KEY) continue;
} }
// Input of some kind was detected, so reset the inactivity timer
inactivity_time_start = try interop.getTimeOfDay();
switch (event.key) { switch (event.key) {
termbox.TB_KEY_ESC => { termbox.TB_KEY_ESC => {
if (config.vi_mode and insert_mode) { if (config.vi_mode and insert_mode) {