Merge branch 'master' into refactor/termbox2-dependency

This commit is contained in:
jlucaso 2025-07-25 06:31:10 +02:00
commit 6933c4db02
35 changed files with 543 additions and 124 deletions

View File

@ -139,6 +139,12 @@ fn install_ly(allocator: std.mem.Allocator, patch_map: PatchMap, install_config:
std.debug.print("warn: {s} already exists as a directory.\n", .{ly_config_directory}); std.debug.print("warn: {s} already exists as a directory.\n", .{ly_config_directory});
}; };
const ly_custom_sessions_directory = try std.fs.path.join(allocator, &[_][]const u8{ dest_directory, config_directory, "/ly/custom-sessions" });
std.fs.cwd().makePath(ly_custom_sessions_directory) catch {
std.debug.print("warn: {s} already exists as a directory.\n", .{ly_custom_sessions_directory});
};
const ly_lang_path = try std.fs.path.join(allocator, &[_][]const u8{ dest_directory, config_directory, "/ly/lang" }); const ly_lang_path = try std.fs.path.join(allocator, &[_][]const u8{ dest_directory, config_directory, "/ly/lang" });
std.fs.cwd().makePath(ly_lang_path) catch { std.fs.cwd().makePath(ly_lang_path) catch {
std.debug.print("warn: {s} already exists as a directory.\n", .{ly_lang_path}); std.debug.print("warn: {s} already exists as a directory.\n", .{ly_lang_path});
@ -171,6 +177,14 @@ fn install_ly(allocator: std.mem.Allocator, patch_map: PatchMap, install_config:
try installText(patched_setup, config_dir, ly_config_directory, "setup.sh", .{ .mode = 0o755 }); try installText(patched_setup, config_dir, ly_config_directory, "setup.sh", .{ .mode = 0o755 });
} }
{
var custom_sessions_dir = std.fs.cwd().openDir(ly_custom_sessions_directory, .{}) catch unreachable;
defer custom_sessions_dir.close();
const patched_readme = try patchFile(allocator, "res/custom-sessions/README", patch_map);
try installText(patched_readme, custom_sessions_dir, ly_custom_sessions_directory, "README", .{});
}
{ {
var lang_dir = std.fs.cwd().openDir(ly_lang_path, .{}) catch unreachable; var lang_dir = std.fs.cwd().openDir(ly_lang_path, .{}) catch unreachable;
defer lang_dir.close(); defer lang_dir.close();

View File

@ -4,6 +4,8 @@
Ly is a lightweight TUI (ncurses-like) display manager for Linux and BSD. Ly is a lightweight TUI (ncurses-like) display manager for Linux and BSD.
Join us on Matrix over at [#ly:envs.net](https://matrix.to/#/#ly:envs.net)!
**Note**: Development happens on [Codeberg](https://codeberg.org/AnErrupTion/ly) with a mirror on [GitHub](https://github.com/fairyglade/ly). **Note**: Development happens on [Codeberg](https://codeberg.org/AnErrupTion/ly) with a mirror on [GitHub](https://github.com/fairyglade/ly).
## Dependencies ## Dependencies

View File

@ -100,20 +100,28 @@ colormix_col2 = 0x000000FF
# Color mixing animation third color id # Color mixing animation third color id
colormix_col3 = 0x20000000 colormix_col3 = 0x20000000
# Console path # Custom sessions directory
console_dev = /dev/console # You can specify multiple directories,
# e.g. $CONFIG_DIRECTORY/ly/custom-sessions:$PREFIX_DIRECTORY/share/custom-sessions
waylandsessions = $CONFIG_DIRECTORY/share/custom-sessions
# Input box active by default on startup # Input box active by default on startup
# Available inputs: info_line, session, login, password # Available inputs: info_line, session, login, password
default_input = login default_input = login
# DOOM animation top color (low intensity flames) # DOOM animation fire height (1 thru 9)
doom_top_color = 0x00FF0000 doom_fire_height = 6
# DOOM animation middle color (medium intensity flames) # DOOM animation fire spread (0 thru 4)
doom_middle_color = 0x00FFFF00 doom_fire_spread = 2
# DOOM animation bottom color (high intensity flames) # DOOM animation custom top color (low intensity flames)
doom_top_color = 0x009F2707
# DOOM animation custom middle color (medium intensity flames)
doom_middle_color = 0x00C78F17
# DOOM animation custom bottom color (high intensity flames)
doom_bottom_color = 0x00FFFFFF doom_bottom_color = 0x00FFFFFF
# Error background color id # Error background color id
@ -176,6 +184,9 @@ load = true
# You can also set environment variables in there, they'll persist until logout # You can also set environment variables in there, they'll persist until logout
login_cmd = null login_cmd = null
# Path for login.defs file (used for listing all local users on the system)
login_defs_path = /etc/login.defs
# Command executed when logging out # Command executed when logging out
# If null, no command will be executed # If null, no command will be executed
# Important: the session will already be terminated when this command is executed, so # Important: the session will already be terminated when this command is executed, so
@ -248,7 +259,7 @@ vi_mode = false
# Wayland desktop environments # Wayland desktop environments
# You can specify multiple directories, # You can specify multiple directories,
# e.g. /usr/share/wayland-sessions:/usr/local/share/wayland-sessions # e.g. $PREFIX_DIRECTORY/share/wayland-sessions:$PREFIX_DIRECTORY/local/share/wayland-sessions
waylandsessions = $PREFIX_DIRECTORY/share/wayland-sessions waylandsessions = $PREFIX_DIRECTORY/share/wayland-sessions
# Xorg server command # Xorg server command
@ -263,5 +274,5 @@ xinitrc = ~/.xinitrc
# Xorg desktop environments # Xorg desktop environments
# You can specify multiple directories, # You can specify multiple directories,
# e.g. /usr/share/xsessions:/usr/local/share/xsessions # e.g. $PREFIX_DIRECTORY/share/xsessions:$PREFIX_DIRECTORY/local/share/xsessions
xsessions = $PREFIX_DIRECTORY/share/xsessions xsessions = $PREFIX_DIRECTORY/share/xsessions

View File

@ -0,0 +1,22 @@
A custom session is just a desktop entry file, like for X11 and Wayland
sessions. For example:
[Desktop Entry]
Name=Fish shell
Exec=$PREFIX_DIRECTORY/bin/fish
DesktopNames=null
Terminal=true
The DesktopNames value is optional and sets the XDG_SESSION_DESKTOP and
XDG_CURRENT_DESKTOP environment variables. If equal to null or if not present,
XDG_SESSION_DESKTOP and XDG_CURRENT_DESKTOP will not be set. Otherwise, the
syntax is the same as described in the Freedesktop Desktop Entry Specification.
The Terminal value specifies if standard output and standard error should be
redirected to the session log file found in Ly's configuration file. If set to
true, Ly will consider the program is going to run in a TTY, and thus will not
redirect standard output & error.
Finally, do note that the XDG_SESSION_TYPE environment variable is set to
"unspecified" (without quotes), which is behavior that at least systemd
recognizes (see pam_systemd's man page)

View File

@ -2,17 +2,18 @@ authenticating = جاري المصادقة...
brightness_down = خفض السطوع brightness_down = خفض السطوع
brightness_up = رفع السطوع brightness_up = رفع السطوع
capslock = capslock capslock = capslock
err_alloc = فشل في تخصيص الذاكرة err_alloc = فشل في تخصيص الذاكرة
err_bounds = out-of-bounds index err_bounds = out-of-bounds index
err_brightness_change = فشل في تغيير سطوع الشاشة err_brightness_change = فشل في تغيير سطوع الشاشة
err_chdir = فشل في فتح مجلد المنزل err_chdir = فشل في فتح مجلد المنزل
err_config = فشل في تفسير ملف الإعدادات err_config = فشل في تفسير ملف الإعدادات
err_console_dev = فشل في الوصول إلى جهاز وحدة التحكم
err_dgn_oob = رسالة سجل (Log) err_dgn_oob = رسالة سجل (Log)
err_domain = اسم نطاق غير صالح err_domain = اسم نطاق غير صالح
err_empty_password = لا يُسمح بكلمة مرور فارغة err_empty_password = لا يُسمح بكلمة مرور فارغة
err_envlist = فشل في جلب قائمة المتغيرات البيئية 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
@ -38,7 +39,9 @@ err_perm_group = فشل في تخفيض صلاحيات المجموعة (Group p
err_perm_user = فشل في تخفيض صلاحيات المستخدم (User permissions) err_perm_user = فشل في تخفيض صلاحيات المستخدم (User permissions)
err_pwnam = فشل في جلب معلومات المستخدم err_pwnam = فشل في جلب معلومات المستخدم
err_sleep = فشل في تنفيذ أمر sleep err_sleep = فشل في تنفيذ أمر sleep
err_tty_ctrl = فشل في نقل تحكم الطرفية (TTY) err_tty_ctrl = فشل في نقل تحكم الطرفية (TTY)
err_user_gid = فشل في تعيين معرّف المجموعة (GID) للمستخدم err_user_gid = فشل في تعيين معرّف المجموعة (GID) للمستخدم
err_user_init = فشل في تهيئة بيانات المستخدم err_user_init = فشل في تهيئة بيانات المستخدم
err_user_uid = فشل في تعيين معرّف المستخدم (UID) err_user_uid = فشل في تعيين معرّف المستخدم (UID)

View File

@ -2,17 +2,18 @@ authenticating = autenticant...
brightness_down = abaixar brillantor brightness_down = abaixar brillantor
brightness_up = apujar brillantor brightness_up = apujar brillantor
capslock = Bloq Majús capslock = Bloq Majús
err_alloc = assignació de memòria fallida err_alloc = assignació de memòria fallida
err_bounds = índex fora de límits err_bounds = índex fora de límits
err_brightness_change = error en canviar la brillantor err_brightness_change = error en canviar la brillantor
err_chdir = error en obrir la carpeta home err_chdir = error en obrir la carpeta home
err_console_dev = error en accedir a la consola
err_dgn_oob = missatge de registre err_dgn_oob = missatge de registre
err_domain = domini invàlid err_domain = domini invàlid
err_envlist = error en obtenir l'envlist 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
@ -39,6 +40,8 @@ err_perm_user = error en degradar els permisos de l'usuari
err_pwnam = error en obtenir la informació de l'usuari err_pwnam = error en obtenir la informació de l'usuari
err_user_gid = error en establir el GID de l'usuari err_user_gid = error en establir el GID de l'usuari
err_user_init = error en inicialitzar usuari err_user_init = error en inicialitzar usuari
err_user_uid = error en establir l'UID de l'usuari err_user_uid = error en establir l'UID de l'usuari

View File

@ -2,17 +2,18 @@
capslock = capslock capslock = capslock
err_alloc = alokace paměti selhala err_alloc = alokace paměti selhala
err_bounds = index je mimo hranice pole err_bounds = index je mimo hranice pole
err_chdir = nelze otevřít domovský adresář err_chdir = nelze otevřít domovský adresář
err_console_dev = chyba při přístupu do konzole
err_dgn_oob = zpráva protokolu err_dgn_oob = zpráva protokolu
err_domain = neplatná doména 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
@ -39,6 +40,8 @@ err_perm_user = nepodařilo se snížit uživatelská oprávnění
err_pwnam = nelze získat informace o uživateli err_pwnam = nelze získat informace o uživateli
err_user_gid = nastavení GID uživatele selhalo err_user_gid = nastavení GID uživatele selhalo
err_user_init = inicializace uživatele selhala err_user_init = inicializace uživatele selhala
err_user_uid = nastavení UID uživateli selhalo err_user_uid = nastavení UID uživateli selhalo

View File

@ -2,17 +2,18 @@ authenticating = authentifizieren...
brightness_down = Helligkeit- brightness_down = Helligkeit-
brightness_up = Helligkeit+ brightness_up = Helligkeit+
capslock = Feststelltaste capslock = Feststelltaste
err_alloc = Speicherzuweisung fehlgeschlagen err_alloc = Speicherzuweisung fehlgeschlagen
err_bounds = Index ausserhalb des Bereichs err_bounds = Index ausserhalb des Bereichs
err_brightness_change = Helligkeitsänderung fehlgeschlagen err_brightness_change = Helligkeitsänderung fehlgeschlagen
err_chdir = Fehler beim Oeffnen des Home-Ordners err_chdir = Fehler beim Oeffnen des Home-Ordners
err_config = Fehler beim Verarbeiten der Konfigurationsdatei err_config = Fehler beim Verarbeiten der Konfigurationsdatei
err_console_dev = Zugriff auf die Konsole fehlgeschlagen
err_dgn_oob = Diagnose-Nachricht err_dgn_oob = Diagnose-Nachricht
err_domain = Ungueltige Domain err_domain = Ungueltige Domain
err_empty_password = Leeres Passwort nicht zugelassen err_empty_password = Leeres Passwort nicht zugelassen
err_envlist = Fehler beim Abrufen der Umgebungs-Variablen 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
@ -38,7 +39,9 @@ err_perm_group = Fehler beim Heruntersetzen der Gruppenberechtigungen
err_perm_user = Fehler beim Heruntersetzen der Nutzerberechtigungen err_perm_user = Fehler beim Heruntersetzen der Nutzerberechtigungen
err_pwnam = Abrufen der Benutzerinformationen fehlgeschlagen err_pwnam = Abrufen der Benutzerinformationen fehlgeschlagen
err_sleep = Sleep-Befehl fehlgeschlagen err_sleep = Sleep-Befehl fehlgeschlagen
err_tty_ctrl = Fehler bei der TTY-Uebergabe err_tty_ctrl = Fehler bei der TTY-Uebergabe
err_user_gid = Fehler beim Setzen der Gruppen-ID err_user_gid = Fehler beim Setzen der Gruppen-ID
err_user_init = Nutzer-Initialisierung fehlgeschlagen err_user_init = Nutzer-Initialisierung fehlgeschlagen
err_user_uid = Setzen der Benutzer-ID fehlgeschlagen err_user_uid = Setzen der Benutzer-ID fehlgeschlagen

View File

@ -2,17 +2,18 @@ authenticating = authenticating...
brightness_down = decrease brightness brightness_down = decrease brightness
brightness_up = increase brightness brightness_up = increase brightness
capslock = capslock capslock = capslock
custom = custom
err_alloc = failed memory allocation err_alloc = failed memory allocation
err_bounds = out-of-bounds index err_bounds = out-of-bounds index
err_brightness_change = failed to change brightness err_brightness_change = failed to change brightness
err_chdir = failed to open home folder err_chdir = failed to open home folder
err_config = unable to parse config file err_config = unable to parse config file
err_console_dev = failed to access console
err_dgn_oob = log message err_dgn_oob = log message
err_domain = invalid domain err_domain = invalid domain
err_empty_password = empty password not allowed err_empty_password = empty password not allowed
err_envlist = failed to get envlist err_envlist = failed to get envlist
err_hostname = failed to get hostname err_hostname = failed to get hostname
err_lock_state = failed to get lock state
err_mlock = failed to lock password memory err_mlock = failed to lock password memory
err_null = null pointer err_null = null pointer
err_numlock = failed to set numlock err_numlock = failed to set numlock
@ -38,7 +39,9 @@ err_perm_group = failed to downgrade group permissions
err_perm_user = failed to downgrade user permissions err_perm_user = failed to downgrade user permissions
err_pwnam = failed to get user info err_pwnam = failed to get user info
err_sleep = failed to execute sleep command err_sleep = failed to execute sleep command
err_switch_tty = failed to switch tty
err_tty_ctrl = tty control transfer failed err_tty_ctrl = tty control transfer failed
err_no_users = no users found
err_user_gid = failed to set user GID err_user_gid = failed to set user GID
err_user_init = failed to initialize user err_user_init = failed to initialize user
err_user_uid = failed to set user UID err_user_uid = failed to set user UID

View File

@ -2,17 +2,18 @@ authenticating = autenticando...
brightness_down = bajar brillo brightness_down = bajar brillo
brightness_up = subir brillo brightness_up = subir brillo
capslock = Bloq Mayús capslock = Bloq Mayús
err_alloc = asignación de memoria fallida err_alloc = asignación de memoria fallida
err_bounds = índice fuera de límites err_bounds = índice fuera de límites
err_chdir = error al abrir la carpeta home err_chdir = error al abrir la carpeta home
err_console_dev = error al acceder a la consola
err_dgn_oob = mensaje de registro err_dgn_oob = mensaje de registro
err_domain = dominio inválido 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
@ -39,6 +40,8 @@ err_perm_user = error al degradar los permisos del usuario
err_pwnam = error al obtener la información del usuario err_pwnam = error al obtener la información del usuario
err_user_gid = error al establecer el GID del usuario err_user_gid = error al establecer el GID del usuario
err_user_init = error al inicializar usuario err_user_init = error al inicializar usuario
err_user_uid = error al establecer el UID del usuario err_user_uid = error al establecer el UID del usuario

View File

@ -2,17 +2,18 @@ authenticating = authentification...
brightness_down = diminuer la luminosité brightness_down = diminuer la luminosité
brightness_up = augmenter la luminosité brightness_up = augmenter la luminosité
capslock = verr.maj capslock = verr.maj
custom = customisé
err_alloc = échec d'allocation mémoire err_alloc = échec d'allocation mémoire
err_bounds = indice hors-limite err_bounds = indice hors-limite
err_brightness_change = échec du changement de luminosité err_brightness_change = échec du changement de luminosité
err_chdir = échec de l'ouverture du répertoire home err_chdir = échec de l'ouverture du répertoire home
err_config = échec de lecture du fichier de configuration err_config = échec de lecture du fichier de configuration
err_console_dev = échec d'accès à la console
err_dgn_oob = message err_dgn_oob = message
err_domain = domaine invalide err_domain = domaine invalide
err_empty_password = mot de passe vide non autorisé err_empty_password = mot de passe vide non autorisé
err_envlist = échec de lecture de la liste d'environnement err_envlist = échec de lecture de la liste d'environnement
err_hostname = échec de lecture du nom d'hôte err_hostname = échec de lecture du nom d'hôte
err_lock_state = échec de lecture de l'état de verrouillage
err_mlock = échec du verrouillage mémoire err_mlock = échec du verrouillage mémoire
err_null = pointeur null err_null = pointeur null
err_numlock = échec de modification du verr.num err_numlock = échec de modification du verr.num
@ -38,7 +39,9 @@ err_perm_group = échec du déclassement des permissions de groupe
err_perm_user = échec du déclassement des permissions utilisateur err_perm_user = échec du déclassement des permissions utilisateur
err_pwnam = échec de lecture des infos utilisateur err_pwnam = échec de lecture des infos utilisateur
err_sleep = échec de l'exécution de la commande de veille err_sleep = échec de l'exécution de la commande de veille
err_switch_tty = échec du changement de terminal
err_tty_ctrl = échec du transfert de contrôle du terminal err_tty_ctrl = échec du transfert de contrôle du terminal
err_no_users = aucun utilisateur trouvé
err_user_gid = échec de modification du GID err_user_gid = échec de modification du GID
err_user_init = échec d'initialisation de l'utilisateur err_user_init = échec d'initialisation de l'utilisateur
err_user_uid = échec de modification du UID err_user_uid = échec de modification du UID

View File

@ -2,17 +2,18 @@
capslock = capslock capslock = capslock
err_alloc = impossibile allocare memoria err_alloc = impossibile allocare memoria
err_bounds = indice fuori limite err_bounds = indice fuori limite
err_chdir = impossibile aprire home directory err_chdir = impossibile aprire home directory
err_console_dev = impossibile aprire console
err_dgn_oob = messaggio log err_dgn_oob = messaggio log
err_domain = dominio non valido 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
@ -39,6 +40,8 @@ err_perm_user = impossibile ridurre permessi utente
err_pwnam = impossibile ottenere dati utente err_pwnam = impossibile ottenere dati utente
err_user_gid = impossibile impostare GID utente err_user_gid = impossibile impostare GID utente
err_user_init = impossibile inizializzare utente err_user_init = impossibile inizializzare utente
err_user_uid = impossible impostare UID utente err_user_uid = impossible impostare UID utente

126
res/lang/ja_JP.ini Normal file
View File

@ -0,0 +1,126 @@
authenticating=認証中...
brightness_down=明るさを下げる
brightness_up=明るさを上げる
capslock=CapsLock
err_alloc=メモリ割り当て失敗
err_bounds=境界外インデックス
err_brightness_change=明るさの変更に失敗しました
err_chdir=ホームフォルダを開けませんでした
err_config=設定ファイルを解析できません
err_console_dev=コンソールへのアクセスに失敗しました
err_dgn_oob=ログメッセージ
err_domain=無効なドメイン
err_empty_password=空のパスワードは許可されていません
err_envlist=環境変数リストの取得に失敗しました
err_hostname=ホスト名の取得に失敗しました
err_mlock=パスワードメモリのロックに失敗しました
err_null=ヌルポインタ
err_numlock=NumLockの設定に失敗しました
err_pam=PAMトランザクション失敗
err_pam_abort=PAMトランザクションが中断されました
err_pam_acct_expired=アカウントの有効期限が切れています
err_pam_auth=認証エラー
err_pam_authinfo_unavail=ユーザー情報の取得に失敗しました
err_pam_authok_reqd=トークンの有効期限が切れています
err_pam_buf=メモリバッファエラー
err_pam_cred_err=認証情報の設定に失敗しました
err_pam_cred_expired=認証情報の有効期限が切れています
err_pam_cred_insufficient=認証情報が不十分です
err_pam_cred_unavail=認証情報の取得に失敗しました
err_pam_maxtries=最大試行回数に到達しました
err_pam_perm_denied=アクセスが拒否されました
err_pam_session=セッションエラー
err_pam_sys=システムエラー
err_pam_user_unknown=不明なユーザー
err_path=パスの設定に失敗しました
err_perm_dir=カレントディレクトリの変更に失敗しました
err_perm_group=グループ権限のダウングレードに失敗しました
err_perm_user=ユーザー権限のダウングレードに失敗しました
err_pwnam=ユーザー情報の取得に失敗しました
err_sleep=スリープコマンドの実行に失敗しました
err_tty_ctrl=TTY制御の転送に失敗しました
err_user_gid=ユーザーGIDの設定に失敗しました
err_user_init=ユーザーの初期化に失敗しました
err_user_uid=ユーザーUIDの設定に失敗しました
err_xauth=xauthコマンドの実行に失敗しました
err_xcb_conn=XCB接続に失敗しました
err_xsessions_dir=セッションフォルダが見つかりませんでした
err_xsessions_open=セッションフォルダを開けませんでした
insert=挿入
login=ログイン
logout=ログアウト済み
no_x11_support=X11サポートはコンパイル時に無効化されています
normal=通常
numlock=NumLock
other=その他
password=パスワード
restart=再起動
shell=シェル
shutdown=シャットダウン
sleep=スリープ
wayland=Wayland
x11=X11
xinitrc=xinitrc
authenticating=認証中...
brightness_down=明るさを下げる
brightness_up=明るさを上げる
capslock=CapsLock
err_alloc=メモリ割り当て失敗
err_bounds=境界外インデックス
err_brightness_change=明るさの変更に失敗しました
err_chdir=ホームフォルダを開けませんでした
err_config=設定ファイルを解析できません
err_console_dev=コンソールへのアクセスに失敗しました
err_dgn_oob=ログメッセージ
err_domain=無効なドメイン
err_empty_password=空のパスワードは許可されていません
err_envlist=環境変数リストの取得に失敗しました
err_hostname=ホスト名の取得に失敗しました
err_mlock=パスワードメモリのロックに失敗しました
err_null=ヌルポインタ
err_numlock=NumLockの設定に失敗しました
err_pam=PAMトランザクション失敗
err_pam_abort=PAMトランザクションが中断されました
err_pam_acct_expired=アカウントの有効期限が切れています
err_pam_auth=認証エラー
err_pam_authinfo_unavail=ユーザー情報の取得に失敗しました
err_pam_authok_reqd=トークンの有効期限が切れています
err_pam_buf=メモリバッファエラー
err_pam_cred_err=認証情報の設定に失敗しました
err_pam_cred_expired=認証情報の有効期限が切れています
err_pam_cred_insufficient=認証情報が不十分です
err_pam_cred_unavail=認証情報の取得に失敗しました
err_pam_maxtries=最大試行回数に到達しました
err_pam_perm_denied=アクセスが拒否されました
err_pam_session=セッションエラー
err_pam_sys=システムエラー
err_pam_user_unknown=不明なユーザー
err_path=パスの設定に失敗しました
err_perm_dir=カレントディレクトリの変更に失敗しました
err_perm_group=グループ権限のダウングレードに失敗しました
err_perm_user=ユーザー権限のダウングレードに失敗しました
err_pwnam=ユーザー情報の取得に失敗しました
err_sleep=スリープコマンドの実行に失敗しました
err_tty_ctrl=TTY制御の転送に失敗しました
err_user_gid=ユーザーGIDの設定に失敗しました
err_user_init=ユーザーの初期化に失敗しました
err_user_uid=ユーザーUIDの設定に失敗しました
err_xauth=xauthコマンドの実行に失敗しました
err_xcb_conn=XCB接続に失敗しました
err_xsessions_dir=セッションフォルダが見つかりませんでした
err_xsessions_open=セッションフォルダを開けませんでした
insert=挿入
login=ログイン
logout=ログアウト済み
no_x11_support=X11サポートはコンパイル時に無効化されています
normal=通常
numlock=NumLock
other=その他
password=パスワード
restart=再起動
shell=シェル
shutdown=シャットダウン
sleep=スリープ
wayland=Wayland
x11=X11
xinitrc=xinitrc

View File

@ -2,17 +2,18 @@ authenticating = uwierzytelnianie...
brightness_down = zmniejsz jasność brightness_down = zmniejsz jasność
brightness_up = zwiększ jasność brightness_up = zwiększ jasność
capslock = capslock capslock = capslock
err_alloc = nieudana alokacja pamięci err_alloc = nieudana alokacja pamięci
err_bounds = indeks poza zakresem err_bounds = indeks poza zakresem
err_brightness_change = nie udało się zmienić jasności err_brightness_change = nie udało się zmienić jasności
err_chdir = nie udało się otworzyć folderu domowego err_chdir = nie udało się otworzyć folderu domowego
err_config = nie można przetworzyć pliku konfiguracyjnego err_config = nie można przetworzyć pliku konfiguracyjnego
err_console_dev = nie udało się uzyskać dostępu do konsoli
err_dgn_oob = wiadomość loga err_dgn_oob = wiadomość loga
err_domain = niepoprawna domena err_domain = niepoprawna domena
err_empty_password = puste hasło jest niedozwolone err_empty_password = puste hasło jest niedozwolone
err_envlist = nie udało się pobrać listy zmiennych środowiskowych err_envlist = nie udało się pobrać listy zmiennych środowiskowych
err_hostname = nie udało się uzyskać nazwy hosta err_hostname = nie udało się uzyskać nazwy hosta
err_mlock = nie udało się zablokować pamięci haseł err_mlock = nie udało się zablokować pamięci haseł
err_null = pusty wskaźnik err_null = pusty wskaźnik
err_numlock = nie udało się ustawić numlock err_numlock = nie udało się ustawić numlock
@ -38,7 +39,9 @@ err_perm_group = nie udało się obniżyć uprawnień grupy
err_perm_user = nie udało się obniżyć uprawnień użytkownika err_perm_user = nie udało się obniżyć uprawnień użytkownika
err_pwnam = nie udało się uzyskać informacji o użytkowniku err_pwnam = nie udało się uzyskać informacji o użytkowniku
err_sleep = nie udało się wykonać polecenia sleep err_sleep = nie udało się wykonać polecenia sleep
err_tty_ctrl = nie udało się przekazać kontroli tty err_tty_ctrl = nie udało się przekazać kontroli tty
err_user_gid = nie udało się ustawić GID użytkownika err_user_gid = nie udało się ustawić GID użytkownika
err_user_init = nie udało się zainicjalizować użytkownika err_user_init = nie udało się zainicjalizować użytkownika
err_user_uid = nie udało się ustawić UID użytkownika err_user_uid = nie udało się ustawić UID użytkownika

View File

@ -2,17 +2,18 @@
capslock = capslock capslock = capslock
err_alloc = erro na atribuição de memória err_alloc = erro na atribuição de memória
err_bounds = índice fora de limites err_bounds = índice fora de limites
err_chdir = erro ao abrir a pasta home err_chdir = erro ao abrir a pasta home
err_console_dev = erro ao aceder à consola
err_dgn_oob = mensagem de registo err_dgn_oob = mensagem de registo
err_domain = domínio inválido 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
@ -39,6 +40,8 @@ err_perm_user = erro ao reduzir as permissões do utilizador
err_pwnam = erro ao obter informação do utilizador err_pwnam = erro ao obter informação do utilizador
err_user_gid = erro ao definir o GID do utilizador err_user_gid = erro ao definir o GID do utilizador
err_user_init = erro ao iniciar o utilizador err_user_init = erro ao iniciar o utilizador
err_user_uid = erro ao definir o UID do utilizador err_user_uid = erro ao definir o UID do utilizador

View File

@ -2,17 +2,18 @@
capslock = caixa alta capslock = caixa alta
err_alloc = alocação de memória malsucedida err_alloc = alocação de memória malsucedida
err_bounds = índice fora de limites err_bounds = índice fora de limites
err_chdir = não foi possível abrir o diretório home err_chdir = não foi possível abrir o diretório home
err_console_dev = não foi possível acessar o console
err_dgn_oob = mensagem de log err_dgn_oob = mensagem de log
err_domain = domínio inválido 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
@ -39,6 +40,8 @@ err_perm_user = não foi possível reduzir as permissões de usuário
err_pwnam = não foi possível obter informações do usuário err_pwnam = não foi possível obter informações do usuário
err_user_gid = não foi possível definir o GID do usuário err_user_gid = não foi possível definir o GID do usuário
err_user_init = não foi possível iniciar o usuário err_user_init = não foi possível iniciar o usuário
err_user_uid = não foi possível definir o UID do usuário err_user_uid = não foi possível definir o UID do usuário

View File

@ -7,7 +7,8 @@ capslock = capslock
err_console_dev = nu s-a putut accesa consola
@ -47,6 +48,8 @@ err_perm_user = nu s-a putut face downgrade permisiunilor de utilizator
login = utilizator login = utilizator
logout = opreşte sesiunea logout = opreşte sesiunea

View File

@ -2,17 +2,18 @@
capslock = capslock capslock = capslock
err_alloc = не удалось выделить память err_alloc = не удалось выделить память
err_bounds = за пределами индекса err_bounds = за пределами индекса
err_chdir = не удалось открыть домашнюю папку err_chdir = не удалось открыть домашнюю папку
err_console_dev = не удалось получить доступ к консоли
err_dgn_oob = отладочное сообщение (log) err_dgn_oob = отладочное сообщение (log)
err_domain = неверный домен err_domain = неверный домен
err_hostname = не удалось получить имя хоста err_hostname = не удалось получить имя хоста
err_mlock = сбой блокировки памяти err_mlock = сбой блокировки памяти
err_null = нулевой указатель err_null = нулевой указатель
@ -39,6 +40,8 @@ err_perm_user = не удалось понизить права доступа
err_pwnam = не удалось получить информацию о пользователе err_pwnam = не удалось получить информацию о пользователе
err_user_gid = не удалось установить GID пользователя err_user_gid = не удалось установить GID пользователя
err_user_init = не удалось инициализировать пользователя err_user_init = не удалось инициализировать пользователя
err_user_uid = не удалось установить UID пользователя err_user_uid = не удалось установить UID пользователя

View File

@ -2,17 +2,18 @@
capslock = capslock capslock = capslock
err_alloc = neuspijesna alokacija memorije err_alloc = neuspijesna alokacija memorije
err_bounds = izvan granica indeksa err_bounds = izvan granica indeksa
err_chdir = neuspijesno otvaranje home foldera err_chdir = neuspijesno otvaranje home foldera
err_console_dev = neuspijesno pristupanje konzoli
err_dgn_oob = log poruka err_dgn_oob = log poruka
err_domain = nevazeci domen 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
@ -39,6 +40,8 @@ err_perm_user = neuspijesno snizavanje dozvola korisnika
err_pwnam = neuspijesno skupljanje informacija o korisniku err_pwnam = neuspijesno skupljanje informacija o korisniku
err_user_gid = neuspijesno postavljanje korisničkog GID-a err_user_gid = neuspijesno postavljanje korisničkog GID-a
err_user_init = neuspijensa inicijalizacija korisnika err_user_init = neuspijensa inicijalizacija korisnika
err_user_uid = neuspijesno postavljanje UID-a korisnika err_user_uid = neuspijesno postavljanje UID-a korisnika

View File

@ -2,17 +2,18 @@
capslock = capslock capslock = capslock
err_alloc = misslyckad minnesallokering err_alloc = misslyckad minnesallokering
err_bounds = utanför banan index err_bounds = utanför banan index
err_chdir = misslyckades att öppna hemkatalog err_chdir = misslyckades att öppna hemkatalog
err_console_dev = misslyckades att komma åt konsol
err_dgn_oob = loggmeddelande err_dgn_oob = loggmeddelande
err_domain = okänd domän 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
@ -39,6 +40,8 @@ err_perm_user = misslyckades att nergradera användarbehörigheter
err_pwnam = misslyckades att hämta användarinfo err_pwnam = misslyckades att hämta användarinfo
err_user_gid = misslyckades att ställa in användar-GID err_user_gid = misslyckades att ställa in användar-GID
err_user_init = misslyckades att initialisera användaren err_user_init = misslyckades att initialisera användaren
err_user_uid = misslyckades att ställa in användar-UID err_user_uid = misslyckades att ställa in användar-UID

View File

@ -2,17 +2,18 @@
capslock = capslock capslock = capslock
err_alloc = basarisiz bellek ayirma err_alloc = basarisiz bellek ayirma
err_bounds = sinirlarin disinda dizin err_bounds = sinirlarin disinda dizin
err_chdir = ev klasoru acilamadi err_chdir = ev klasoru acilamadi
err_console_dev = konsola erisilemedi
err_dgn_oob = log mesaji err_dgn_oob = log mesaji
err_domain = gecersiz etki alani 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
@ -39,6 +40,8 @@ err_perm_user = kullanici izinleri dusurulemedi
err_pwnam = kullanici bilgileri alinamadi err_pwnam = kullanici bilgileri alinamadi
err_user_gid = kullanici icin GID ayarlanamadi err_user_gid = kullanici icin GID ayarlanamadi
err_user_init = kullanici oturumu baslatilamadi err_user_init = kullanici oturumu baslatilamadi
err_user_uid = kullanici icin UID ayarlanamadi err_user_uid = kullanici icin UID ayarlanamadi

View File

@ -2,17 +2,18 @@
capslock = capslock capslock = capslock
err_alloc = невдале виділення пам'яті err_alloc = невдале виділення пам'яті
err_bounds = поза межами індексу err_bounds = поза межами індексу
err_chdir = не вдалося відкрити домашній каталог err_chdir = не вдалося відкрити домашній каталог
err_console_dev = невдалий доступ до консолі
err_dgn_oob = повідомлення журналу (log) err_dgn_oob = повідомлення журналу (log)
err_domain = недійсний домен err_domain = недійсний домен
err_hostname = не вдалося отримати ім'я хосту err_hostname = не вдалося отримати ім'я хосту
err_mlock = збій блокування пам'яті err_mlock = збій блокування пам'яті
err_null = нульовий вказівник err_null = нульовий вказівник
@ -39,6 +40,8 @@ err_perm_user = не вдалося понизити права доступу
err_pwnam = не вдалося отримати дані користувача err_pwnam = не вдалося отримати дані користувача
err_user_gid = не вдалося змінити GID користувача err_user_gid = не вдалося змінити GID користувача
err_user_init = не вдалося ініціалізувати користувача err_user_init = не вдалося ініціалізувати користувача
err_user_uid = не вдалося змінити UID користувача err_user_uid = не вдалося змінити UID користувача

View File

@ -2,17 +2,18 @@
capslock = 大写锁定 capslock = 大写锁定
err_alloc = 内存分配失败 err_alloc = 内存分配失败
err_bounds = 索引越界 err_bounds = 索引越界
err_chdir = 无法打开home文件夹 err_chdir = 无法打开home文件夹
err_console_dev = 无法访问控制台
err_dgn_oob = 日志消息 err_dgn_oob = 日志消息
err_domain = 无效的域 err_domain = 无效的域
err_hostname = 获取主机名失败 err_hostname = 获取主机名失败
err_mlock = 锁定密码存储器失败 err_mlock = 锁定密码存储器失败
err_null = 空指针 err_null = 空指针
@ -39,6 +40,8 @@ err_perm_user = 用户权限降级失败
err_pwnam = 获取用户信息失败 err_pwnam = 获取用户信息失败
err_user_gid = 设置用户GID失败 err_user_gid = 设置用户GID失败
err_user_init = 初始化用户失败 err_user_init = 初始化用户失败
err_user_uid = 设置用户UID失败 err_user_uid = 设置用户UID失败

View File

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

6
src/UidRange.zig Normal file
View File

@ -0,0 +1,6 @@
const std = @import("std");
// We set both values to 0 by default so that, in case they aren't present in
// the login.defs for some reason, then only the root username will be shown
uid_min: std.c.uid_t = 0,
uid_max: std.c.uid_t = 0,

View File

@ -7,21 +7,22 @@ const TerminalBuffer = @import("../tui/TerminalBuffer.zig");
const Doom = @This(); const Doom = @This();
pub const STEPS = 12; pub const STEPS = 12;
pub const HEIGHT_MAX = 9;
pub const SPREAD_MAX = 4;
allocator: Allocator, allocator: Allocator,
terminal_buffer: *TerminalBuffer, terminal_buffer: *TerminalBuffer,
buffer: []u8, buffer: []u8,
height: u8,
spread: u8,
fire: [STEPS + 1]Cell, fire: [STEPS + 1]Cell,
pub fn init(allocator: Allocator, terminal_buffer: *TerminalBuffer, top_color: u32, middle_color: u32, bottom_color: u32) !Doom { pub fn init(allocator: Allocator, terminal_buffer: *TerminalBuffer, top_color: u32, middle_color: u32, bottom_color: u32, fire_height: u8, fire_spread: u8) !Doom {
const buffer = try allocator.alloc(u8, terminal_buffer.width * terminal_buffer.height); const buffer = try allocator.alloc(u8, terminal_buffer.width * terminal_buffer.height);
initBuffer(buffer, terminal_buffer.width); initBuffer(buffer, terminal_buffer.width);
return .{ const levels =
.allocator = allocator, [_]Cell{
.terminal_buffer = terminal_buffer,
.buffer = buffer,
.fire = [_]Cell{
Cell.init(' ', TerminalBuffer.Color.DEFAULT, TerminalBuffer.Color.DEFAULT), Cell.init(' ', TerminalBuffer.Color.DEFAULT, TerminalBuffer.Color.DEFAULT),
Cell.init(0x2591, top_color, TerminalBuffer.Color.DEFAULT), Cell.init(0x2591, top_color, TerminalBuffer.Color.DEFAULT),
Cell.init(0x2592, top_color, TerminalBuffer.Color.DEFAULT), Cell.init(0x2592, top_color, TerminalBuffer.Color.DEFAULT),
@ -35,7 +36,15 @@ pub fn init(allocator: Allocator, terminal_buffer: *TerminalBuffer, top_color: u
Cell.init(0x2592, bottom_color, middle_color), Cell.init(0x2592, bottom_color, middle_color),
Cell.init(0x2593, bottom_color, middle_color), Cell.init(0x2593, bottom_color, middle_color),
Cell.init(0x2588, bottom_color, middle_color), Cell.init(0x2588, bottom_color, middle_color),
}, };
return .{
.allocator = allocator,
.terminal_buffer = terminal_buffer,
.buffer = buffer,
.height = @min(HEIGHT_MAX, fire_height),
.spread = @min(SPREAD_MAX, fire_spread),
.fire = levels,
}; };
} }
@ -57,20 +66,35 @@ fn draw(self: *Doom) void {
for (0..self.terminal_buffer.width) |x| { for (0..self.terminal_buffer.width) |x| {
// We start from 1 so that we always have the topmost line when spreading fire // We start from 1 so that we always have the topmost line when spreading fire
for (1..self.terminal_buffer.height) |y| { for (1..self.terminal_buffer.height) |y| {
// Get current cell // Get index of current cell in fire level buffer
const from = y * self.terminal_buffer.width + x; const from = y * self.terminal_buffer.width + x;
const cell_index = self.buffer[from];
// Spread fire // Generate random data for fire propagation
const propagate = self.terminal_buffer.random.int(u1); const rand_loss = self.terminal_buffer.random.intRangeAtMost(u8, 0, HEIGHT_MAX);
const to = from - self.terminal_buffer.width; // Get the line above const rand_spread = self.terminal_buffer.random.intRangeAtMost(u8, 0, self.spread * 2);
self.buffer[to] = if (cell_index > 0) cell_index - propagate else cell_index; // Select semi-random target cell
const to = from -| self.terminal_buffer.width + self.spread -| rand_spread;
const to_x = to % self.terminal_buffer.width;
const to_y = to / self.terminal_buffer.width;
// Put the cell // Get fire level of current cell
const cell = self.fire[cell_index]; const level_buf_from = self.buffer[from];
cell.put(x, y);
// Choose new fire level and store in level buffer
const level_buf_to = level_buf_from -| @intFromBool(rand_loss >= self.height);
self.buffer[to] = level_buf_to;
// Send known fire levels to terminal buffer
const from_cell = self.fire[level_buf_from];
const to_cell = self.fire[level_buf_to];
from_cell.put(x, y);
to_cell.put(to_x, to_y);
} }
// Draw bottom line (fire source)
const src_cell = self.fire[STEPS];
src_cell.put(x, self.terminal_buffer.height - 1);
} }
} }

View File

@ -41,8 +41,7 @@ pub fn authenticate(options: AuthOptions, current_environment: Environment, logi
const pam_tty_str = try std.fmt.bufPrintZ(&pam_tty_buffer, "tty{d}", .{options.tty}); const pam_tty_str = try std.fmt.bufPrintZ(&pam_tty_buffer, "tty{d}", .{options.tty});
// Set the XDG environment variables // Set the XDG environment variables
setXdgSessionEnv(current_environment.display_server); try setXdgEnv(tty_str, current_environment);
try setXdgEnv(tty_str, current_environment.xdg_session_desktop, current_environment.xdg_desktop_names);
// Open the PAM session // Open the PAM session
var credentials = [_:null]?[*:0]const u8{ login, password }; var credentials = [_:null]?[*:0]const u8{ login, password };
@ -96,7 +95,7 @@ pub fn authenticate(options: AuthOptions, current_environment: Environment, logi
child_pid = try std.posix.fork(); child_pid = try std.posix.fork();
if (child_pid == 0) { if (child_pid == 0) {
startSession(options, pwd, handle, current_environment) catch |e| { startSession(options, tty_str, pwd, handle, current_environment) catch |e| {
shared_err.writeError(e); shared_err.writeError(e);
std.process.exit(1); std.process.exit(1);
}; };
@ -132,6 +131,7 @@ pub fn authenticate(options: AuthOptions, current_environment: Environment, logi
fn startSession( fn startSession(
options: AuthOptions, options: AuthOptions,
tty_str: [:0]u8,
pwd: *interop.pwd.passwd, pwd: *interop.pwd.passwd,
handle: ?*interop.pam.pam_handle, handle: ?*interop.pam.pam_handle,
current_environment: Environment, current_environment: Environment,
@ -155,6 +155,9 @@ fn startSession(
// Set up the environment // Set up the environment
try initEnv(pwd, options.path); try initEnv(pwd, options.path);
// Reset the XDG environment variables
try setXdgEnv(tty_str, current_environment);
// Set the PAM variables // Set the PAM variables
const pam_env_vars: ?[*:null]?[*:0]u8 = 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; if (pam_env_vars == null) return error.GetEnvListFailed;
@ -177,6 +180,7 @@ fn startSession(
const vt = try std.fmt.bufPrint(&vt_buf, "vt{d}", .{options.tty}); 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); 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),
} }
} }
@ -193,15 +197,14 @@ fn initEnv(pwd: *interop.pwd.passwd, path_env: ?[:0]const u8) !void {
} }
} }
fn setXdgSessionEnv(display_server: enums.DisplayServer) void { fn setXdgEnv(tty_str: [:0]u8, environment: Environment) !void {
_ = interop.stdlib.setenv("XDG_SESSION_TYPE", switch (display_server) { _ = interop.stdlib.setenv("XDG_SESSION_TYPE", switch (environment.display_server) {
.wayland => "wayland", .wayland => "wayland",
.shell => "tty", .shell => "tty",
.xinitrc, .x11 => "x11", .xinitrc, .x11 => "x11",
.custom => "unspecified",
}, 0); }, 0);
}
fn setXdgEnv(tty_str: [:0]u8, maybe_desktop_name: ?[:0]const u8, maybe_xdg_desktop_names: ?[:0]const u8) !void {
// The "/run/user/%d" directory is not available on FreeBSD. It is much // The "/run/user/%d" directory is not available on FreeBSD. It is much
// better to stick to the defaults and let applications using // better to stick to the defaults and let applications using
// XDG_RUNTIME_DIR to fall back to directories inside user's home // XDG_RUNTIME_DIR to fall back to directories inside user's home
@ -214,10 +217,10 @@ fn setXdgEnv(tty_str: [:0]u8, maybe_desktop_name: ?[:0]const u8, maybe_xdg_deskt
_ = interop.stdlib.setenv("XDG_RUNTIME_DIR", uid_str, 0); _ = interop.stdlib.setenv("XDG_RUNTIME_DIR", uid_str, 0);
} }
if (maybe_xdg_desktop_names) |xdg_desktop_names| _ = interop.stdlib.setenv("XDG_CURRENT_DESKTOP", xdg_desktop_names, 0); if (environment.xdg_desktop_names) |xdg_desktop_names| _ = interop.stdlib.setenv("XDG_CURRENT_DESKTOP", xdg_desktop_names, 0);
_ = interop.stdlib.setenv("XDG_SESSION_CLASS", "user", 0); _ = interop.stdlib.setenv("XDG_SESSION_CLASS", "user", 0);
_ = interop.stdlib.setenv("XDG_SESSION_ID", "1", 0); _ = interop.stdlib.setenv("XDG_SESSION_ID", "1", 0);
if (maybe_desktop_name) |desktop_name| _ = interop.stdlib.setenv("XDG_SESSION_DESKTOP", desktop_name, 0); if (environment.xdg_session_desktop) |desktop_name| _ = interop.stdlib.setenv("XDG_SESSION_DESKTOP", desktop_name, 0);
_ = interop.stdlib.setenv("XDG_SEAT", "seat0", 0); _ = interop.stdlib.setenv("XDG_SEAT", "seat0", 0);
_ = interop.stdlib.setenv("XDG_VTNR", tty_str, 0); _ = interop.stdlib.setenv("XDG_VTNR", tty_str, 0);
} }
@ -461,6 +464,22 @@ fn executeX11Cmd(shell: [*:0]const u8, pw_dir: [*:0]const u8, options: AuthOptio
_ = std.c.waitpid(x_pid, &status, 0); _ = 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 { 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 })); 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,8 +28,10 @@ cmatrix_max_codepoint: u16 = 0x7B,
colormix_col1: u32 = 0x00FF0000, colormix_col1: u32 = 0x00FF0000,
colormix_col2: u32 = 0x000000FF, colormix_col2: u32 = 0x000000FF,
colormix_col3: u32 = 0x20000000, colormix_col3: u32 = 0x20000000,
console_dev: []const u8 = "/dev/console", custom_sessions: []const u8 = build_options.config_directory ++ "/ly/custom-sessions",
default_input: Input = .login, default_input: Input = .login,
doom_fire_height: u8 = 6,
doom_fire_spread: u8 = 2,
doom_top_color: u32 = 0x00FF0000, doom_top_color: u32 = 0x00FF0000,
doom_middle_color: u32 = 0x00FFFF00, doom_middle_color: u32 = 0x00FFFF00,
doom_bottom_color: u32 = 0x00FFFFFF, doom_bottom_color: u32 = 0x00FFFFFF,
@ -48,6 +50,7 @@ input_len: u8 = 34,
lang: []const u8 = "en", lang: []const u8 = "en",
load: bool = true, load: bool = true,
login_cmd: ?[]const u8 = null, login_cmd: ?[]const u8 = null,
login_defs_path: []const u8 = "/etc/login.defs",
logout_cmd: ?[]const u8 = null, logout_cmd: ?[]const u8 = null,
margin_box_h: u8 = 2, margin_box_h: u8 = 2,
margin_box_v: u8 = 1, margin_box_v: u8 = 1,

View File

@ -7,17 +7,18 @@ authenticating: []const u8 = "authenticating...",
brightness_down: []const u8 = "decrease brightness", brightness_down: []const u8 = "decrease brightness",
brightness_up: []const u8 = "increase brightness", brightness_up: []const u8 = "increase brightness",
capslock: []const u8 = "capslock", capslock: []const u8 = "capslock",
custom: []const u8 = "custom",
err_alloc: []const u8 = "failed memory allocation", err_alloc: []const u8 = "failed memory allocation",
err_bounds: []const u8 = "out-of-bounds index", err_bounds: []const u8 = "out-of-bounds index",
err_brightness_change: []const u8 = "failed to change brightness", err_brightness_change: []const u8 = "failed to change brightness",
err_chdir: []const u8 = "failed to open home folder", err_chdir: []const u8 = "failed to open home folder",
err_config: []const u8 = "unable to parse config file", err_config: []const u8 = "unable to parse config file",
err_console_dev: []const u8 = "failed to access console",
err_dgn_oob: []const u8 = "log message", err_dgn_oob: []const u8 = "log message",
err_domain: []const u8 = "invalid domain", err_domain: []const u8 = "invalid domain",
err_empty_password: []const u8 = "empty password not allowed", err_empty_password: []const u8 = "empty password not allowed",
err_envlist: []const u8 = "failed to get envlist", err_envlist: []const u8 = "failed to get envlist",
err_hostname: []const u8 = "failed to get hostname", err_hostname: []const u8 = "failed to get hostname",
err_lock_state: []const u8 = "failed to get lock state",
err_mlock: []const u8 = "failed to lock password memory", err_mlock: []const u8 = "failed to lock password memory",
err_null: []const u8 = "null pointer", err_null: []const u8 = "null pointer",
err_numlock: []const u8 = "failed to set numlock", err_numlock: []const u8 = "failed to set numlock",
@ -43,7 +44,9 @@ err_perm_group: []const u8 = "failed to downgrade group permissions",
err_perm_user: []const u8 = "failed to downgrade user permissions", err_perm_user: []const u8 = "failed to downgrade user permissions",
err_pwnam: []const u8 = "failed to get user info", err_pwnam: []const u8 = "failed to get user info",
err_sleep: []const u8 = "failed to execute sleep command", err_sleep: []const u8 = "failed to execute sleep command",
err_switch_tty: []const u8 = "failed to switch tty",
err_tty_ctrl: []const u8 = "tty control transfer failed", err_tty_ctrl: []const u8 = "tty control transfer failed",
err_no_users: []const u8 = "no users found",
err_user_gid: []const u8 = "failed to set user GID", err_user_gid: []const u8 = "failed to set user GID",
err_user_init: []const u8 = "failed to initialize user", err_user_init: []const u8 = "failed to initialize user",
err_user_uid: []const u8 = "failed to set user UID", err_user_uid: []const u8 = "failed to set user UID",

View File

@ -26,6 +26,7 @@ const removed_properties = [_][]const u8{
"term_restore_cursor_cmd", "term_restore_cursor_cmd",
"x_cmd_setup", "x_cmd_setup",
"wayland_cmd", "wayland_cmd",
"console_dev",
}; };
var temporary_allocator = std.heap.page_allocator; var temporary_allocator = std.heap.page_allocator;

View File

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

View File

@ -36,7 +36,7 @@ pub const stdlib = @cImport({
pub const pwd = @cImport({ pub const pwd = @cImport({
@cInclude("pwd.h"); @cInclude("pwd.h");
// We include a FreeBSD-specific header here since login_cap.h references // We include a FreeBSD-specific header here since login_cap.h references
// the passwd struct directly, so we can't import it separately' // the passwd struct directly, so we can't import it separately
if (builtin.os.tag == .freebsd) @cInclude("login_cap.h"); if (builtin.os.tag == .freebsd) @cInclude("login_cap.h");
}); });
@ -75,23 +75,21 @@ pub fn timeAsString(buf: [:0]u8, format: [:0]const u8) ![]u8 {
return buf[0..len]; return buf[0..len];
} }
pub fn switchTty(console_dev: []const u8, tty: u8) !void { pub fn switchTty(tty: u8) !void {
const fd = try std.posix.open(console_dev, .{ .ACCMODE = .WRONLY }, 0); var status = std.c.ioctl(std.c.STDIN_FILENO, vt.VT_ACTIVATE, tty);
defer std.posix.close(fd); if (status != 0) return error.FailedToActivateTty;
_ = std.c.ioctl(fd, vt.VT_ACTIVATE, tty); status = std.c.ioctl(std.c.STDIN_FILENO, vt.VT_WAITACTIVE, tty);
_ = std.c.ioctl(fd, vt.VT_WAITACTIVE, tty); if (status != 0) return error.FailedToWaitForActiveTty;
} }
pub fn getLockState(console_dev: []const u8) !struct { pub fn getLockState() !struct {
numlock: bool, numlock: bool,
capslock: bool, capslock: bool,
} { } {
const fd = try std.posix.open(console_dev, .{ .ACCMODE = .RDONLY }, 0);
defer std.posix.close(fd);
var led: LedState = undefined; var led: LedState = undefined;
_ = std.c.ioctl(fd, get_led_state, &led); const status = std.c.ioctl(std.c.STDIN_FILENO, get_led_state, &led);
if (status != 0) return error.FailedToGetLockState;
return .{ return .{
.numlock = (led & numlock_led) != 0, .numlock = (led & numlock_led) != 0,
@ -101,11 +99,12 @@ pub fn getLockState(console_dev: []const u8) !struct {
pub fn setNumlock(val: bool) !void { pub fn setNumlock(val: bool) !void {
var led: LedState = undefined; var led: LedState = undefined;
_ = std.c.ioctl(0, get_led_state, &led); var status = std.c.ioctl(std.c.STDIN_FILENO, get_led_state, &led);
if (status != 0) return error.FailedToGetNumlock;
const numlock = (led & numlock_led) != 0; const numlock = (led & numlock_led) != 0;
if (numlock != val) { if (numlock != val) {
const status = std.c.ioctl(std.posix.STDIN_FILENO, set_led_state, led ^ numlock_led); status = std.c.ioctl(std.posix.STDIN_FILENO, set_led_state, led ^ numlock_led);
if (status != 0) return error.FailedToSetNumlock; if (status != 0) return error.FailedToSetNumlock;
} }
} }

View File

@ -18,12 +18,15 @@ const TerminalBuffer = @import("tui/TerminalBuffer.zig");
const Session = @import("tui/components/Session.zig"); const Session = @import("tui/components/Session.zig");
const Text = @import("tui/components/Text.zig"); const Text = @import("tui/components/Text.zig");
const InfoLine = @import("tui/components/InfoLine.zig"); const InfoLine = @import("tui/components/InfoLine.zig");
const UserList = @import("tui/components/UserList.zig");
const Config = @import("config/Config.zig"); const Config = @import("config/Config.zig");
const Lang = @import("config/Lang.zig"); const Lang = @import("config/Lang.zig");
const Save = @import("config/Save.zig"); const Save = @import("config/Save.zig");
const migrator = @import("config/migrator.zig"); const migrator = @import("config/migrator.zig");
const SharedError = @import("SharedError.zig"); const SharedError = @import("SharedError.zig");
const UidRange = @import("UidRange.zig");
const StringList = std.ArrayListUnmanaged([]const u8);
const Ini = ini.Ini; const Ini = ini.Ini;
const DisplayServer = enums.DisplayServer; const DisplayServer = enums.DisplayServer;
const Entry = Environment.Entry; const Entry = Environment.Entry;
@ -102,6 +105,7 @@ pub fn main() !void {
var lang: Lang = undefined; var lang: Lang = undefined;
var save: Save = undefined; var save: Save = undefined;
var config_load_failed = false; var config_load_failed = false;
var can_get_lock_state = true;
if (res.args.help != 0) { if (res.args.help != 0) {
try clap.help(stderr, clap.Help, &params, .{}); try clap.help(stderr, clap.Help, &params, .{});
@ -289,10 +293,12 @@ pub fn main() !void {
try info_line.addMessage(hostname, config.bg, config.fg); 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, ':'); var wayland_session_dirs = std.mem.splitScalar(u8, config.waylandsessions, ':');
while (wayland_session_dirs.next()) |dir| { while (wayland_session_dirs.next()) |dir| {
try crawl(&session, lang, dir, .wayland); try crawl(&session, lang, dir, .wayland);
} }
if (build_options.enable_x11_support) { if (build_options.enable_x11_support) {
var x_session_dirs = std.mem.splitScalar(u8, config.xsessions, ':'); var x_session_dirs = std.mem.splitScalar(u8, config.xsessions, ':');
while (x_session_dirs.next()) |dir| { while (x_session_dirs.next()) |dir| {
@ -300,7 +306,26 @@ pub fn main() !void {
} }
} }
var login = Text.init(allocator, &buffer, false, null); var custom_session_dirs = std.mem.splitScalar(u8, config.custom_sessions, ':');
while (custom_session_dirs.next()) |dir| {
try crawl(&session, lang, dir, .custom);
}
var usernames = try getAllUsernames(allocator, config.login_defs_path);
defer {
for (usernames.items) |username| allocator.free(username);
usernames.deinit(allocator);
}
if (usernames.items.len == 0) {
// If we have no usernames, simply add an error to the info line.
// This effectively means you can't login, since there would be no local
// accounts *and* no root account...but at this point, if that's the
// case, you have bigger problems to deal with in the first place. :D
try info_line.addMessage(lang.err_no_users, config.error_bg, config.error_fg);
}
var login = try UserList.init(allocator, &buffer, usernames);
defer login.deinit(); defer login.deinit();
var password = Text.init(allocator, &buffer, true, config.asterisk); var password = Text.init(allocator, &buffer, true, config.asterisk);
@ -312,9 +337,17 @@ pub fn main() !void {
// Load last saved username and desktop selection, if any // Load last saved username and desktop selection, if any
if (config.load) { if (config.load) {
if (save.user) |user| { if (save.user) |user| {
try login.text.appendSlice(login.allocator, user); // Find user with saved name, and switch over to it
login.end = user.len; // If it doesn't exist (anymore), we don't change the value
login.cursor = login.end; // Note that we could instead save the username index, but migrating
// from the raw username to an index is non-trivial and I'm lazy :P
for (usernames.items, 0..) |username, i| {
if (std.mem.eql(u8, username, user)) {
login.label.current = i;
break;
}
}
active_input = .password; active_input = .password;
} }
@ -330,15 +363,13 @@ pub fn main() !void {
const coordinates = buffer.calculateComponentCoordinates(); const coordinates = buffer.calculateComponentCoordinates();
info_line.label.position(coordinates.start_x, coordinates.y, coordinates.full_visible_length, null); info_line.label.position(coordinates.start_x, coordinates.y, coordinates.full_visible_length, null);
session.label.position(coordinates.x, coordinates.y + 2, coordinates.visible_length, config.text_in_center); session.label.position(coordinates.x, coordinates.y + 2, coordinates.visible_length, config.text_in_center);
login.position(coordinates.x, coordinates.y + 4, coordinates.visible_length); login.label.position(coordinates.x, coordinates.y + 4, coordinates.visible_length, config.text_in_center);
password.position(coordinates.x, coordinates.y + 6, coordinates.visible_length); password.position(coordinates.x, coordinates.y + 6, coordinates.visible_length);
switch (active_input) { switch (active_input) {
.info_line => info_line.label.handle(null, insert_mode), .info_line => info_line.label.handle(null, insert_mode),
.session => session.label.handle(null, insert_mode), .session => session.label.handle(null, insert_mode),
.login => login.handle(null, insert_mode) catch { .login => login.label.handle(null, insert_mode),
try info_line.addMessage(lang.err_alloc, config.error_bg, config.error_fg);
},
.password => password.handle(null, insert_mode) catch { .password => password.handle(null, insert_mode) catch {
try info_line.addMessage(lang.err_alloc, config.error_bg, config.error_fg); try info_line.addMessage(lang.err_alloc, config.error_bg, config.error_fg);
}, },
@ -354,7 +385,7 @@ pub fn main() !void {
animation = dummy.animation(); animation = dummy.animation();
}, },
.doom => { .doom => {
var doom = try Doom.init(allocator, &buffer, config.doom_top_color, config.doom_middle_color, config.doom_bottom_color); var doom = try Doom.init(allocator, &buffer, config.doom_top_color, config.doom_middle_color, config.doom_bottom_color, config.doom_fire_height, config.doom_fire_spread);
animation = doom.animation(); animation = doom.animation();
}, },
.matrix => { .matrix => {
@ -389,12 +420,10 @@ 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 can_access_console_dev = true;
// Switch to selected TTY if possible // Switch to selected TTY
interop.switchTty(config.console_dev, config.tty) catch { interop.switchTty(config.tty) catch {
try info_line.addMessage(lang.err_console_dev, config.error_bg, config.error_fg); try info_line.addMessage(lang.err_switch_tty, config.error_bg, config.error_fg);
can_access_console_dev = false;
}; };
while (run) { while (run) {
@ -458,7 +487,7 @@ pub fn main() !void {
const coordinates = buffer.calculateComponentCoordinates(); const coordinates = buffer.calculateComponentCoordinates();
info_line.label.position(coordinates.start_x, coordinates.y, coordinates.full_visible_length, null); info_line.label.position(coordinates.start_x, coordinates.y, coordinates.full_visible_length, null);
session.label.position(coordinates.x, coordinates.y + 2, coordinates.visible_length, config.text_in_center); session.label.position(coordinates.x, coordinates.y + 2, coordinates.visible_length, config.text_in_center);
login.position(coordinates.x, coordinates.y + 4, coordinates.visible_length); login.label.position(coordinates.x, coordinates.y + 4, coordinates.visible_length, config.text_in_center);
password.position(coordinates.x, coordinates.y + 6, coordinates.visible_length); password.position(coordinates.x, coordinates.y + 6, coordinates.visible_length);
resolution_changed = false; resolution_changed = false;
@ -467,9 +496,7 @@ pub fn main() !void {
switch (active_input) { switch (active_input) {
.info_line => info_line.label.handle(null, insert_mode), .info_line => info_line.label.handle(null, insert_mode),
.session => session.label.handle(null, insert_mode), .session => session.label.handle(null, insert_mode),
.login => login.handle(null, insert_mode) catch { .login => login.label.handle(null, insert_mode),
try info_line.addMessage(lang.err_alloc, config.error_bg, config.error_fg);
},
.password => password.handle(null, insert_mode) catch { .password => password.handle(null, insert_mode) catch {
try info_line.addMessage(lang.err_alloc, config.error_bg, config.error_fg); try info_line.addMessage(lang.err_alloc, config.error_bg, config.error_fg);
}, },
@ -546,9 +573,10 @@ pub fn main() !void {
buffer.drawLabel(label_txt, buffer.box_x, buffer.box_y + buffer.box_height); buffer.drawLabel(label_txt, buffer.box_x, buffer.box_y + buffer.box_height);
} }
if (can_access_console_dev) draw_lock_state: { if (can_get_lock_state) draw_lock_state: {
const lock_state = interop.getLockState(config.console_dev) catch { const lock_state = interop.getLockState() catch {
try info_line.addMessage(lang.err_console_dev, config.error_bg, config.error_fg); try info_line.addMessage(lang.err_lock_state, config.error_bg, config.error_fg);
can_get_lock_state = false;
break :draw_lock_state; break :draw_lock_state;
}; };
@ -564,7 +592,7 @@ pub fn main() !void {
} }
session.label.draw(); session.label.draw();
login.draw(); login.label.draw();
password.draw(); password.draw();
} else { } else {
std.Thread.sleep(std.time.ns_per_ms * 10); std.Thread.sleep(std.time.ns_per_ms * 10);
@ -653,10 +681,7 @@ pub fn main() !void {
}, },
termbox.TB_KEY_CTRL_C => run = false, termbox.TB_KEY_CTRL_C => run = false,
termbox.TB_KEY_CTRL_U => { termbox.TB_KEY_CTRL_U => {
if (active_input == .login) { if (active_input == .password) {
login.clear();
update = true;
} else if (active_input == .password) {
password.clear(); password.clear();
update = true; update = true;
} }
@ -719,7 +744,7 @@ pub fn main() !void {
defer file.close(); defer file.close();
const save_data = Save{ const save_data = Save{
.user = login.text.items, .user = login.getCurrentUser(),
.session_index = session.label.current, .session_index = session.label.current,
}; };
ini.writeFromStruct(save_data, file.writer(), null, .{}) catch break :save_last_settings; ini.writeFromStruct(save_data, file.writer(), null, .{}) catch break :save_last_settings;
@ -732,7 +757,7 @@ pub fn main() !void {
defer shared_err.deinit(); defer shared_err.deinit();
{ {
const login_text = try allocator.dupeZ(u8, login.text.items); const login_text = try allocator.dupeZ(u8, login.getCurrentUser());
defer allocator.free(login_text); defer allocator.free(login_text);
const password_text = try allocator.dupeZ(u8, password.text.items); const password_text = try allocator.dupeZ(u8, password.text.items);
defer allocator.free(password_text); defer allocator.free(password_text);
@ -838,9 +863,7 @@ pub fn main() !void {
switch (active_input) { switch (active_input) {
.info_line => info_line.label.handle(&event, insert_mode), .info_line => info_line.label.handle(&event, insert_mode),
.session => session.label.handle(&event, insert_mode), .session => session.label.handle(&event, insert_mode),
.login => login.handle(&event, insert_mode) catch { .login => login.label.handle(&event, insert_mode),
try info_line.addMessage(lang.err_alloc, config.error_bg, config.error_fg);
},
.password => password.handle(&event, insert_mode) catch { .password => password.handle(&event, insert_mode) catch {
try info_line.addMessage(lang.err_alloc, config.error_bg, config.error_fg); try info_line.addMessage(lang.err_alloc, config.error_bg, config.error_fg);
}, },
@ -864,11 +887,7 @@ fn addOtherEnvironment(session: *Session, lang: Lang, display_server: DisplaySer
.xdg_session_desktop = null, .xdg_session_desktop = null,
.xdg_desktop_names = null, .xdg_desktop_names = null,
.cmd = exec orelse "", .cmd = exec orelse "",
.specifier = switch (display_server) { .specifier = lang.other,
.wayland => lang.wayland,
.x11 => lang.x11,
else => lang.other,
},
.display_server = display_server, .display_server = display_server,
}); });
} }
@ -890,44 +909,111 @@ fn crawl(session: *Session, lang: Lang, path: []const u8, display_server: Displa
}); });
errdefer entry_ini.deinit(); 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; const maybe_desktop_names = entry_ini.data.@"Desktop Entry".DesktopNames;
if (maybe_desktop_names) |desktop_names| { if (maybe_desktop_names) |desktop_names| {
xdg_session_desktop = std.mem.sliceTo(desktop_names, ';'); maybe_xdg_session_desktop = std.mem.sliceTo(desktop_names, ';');
} else { } else if (display_server != .custom) {
// if DesktopNames is empty, we'll take the name of the session file // If DesktopNames is empty, and this isn't a custom session entry,
xdg_session_desktop = std.fs.path.stem(item.name); // 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 // Prepare the XDG_CURRENT_DESKTOP environment variable here
const entry = entry_ini.data.@"Desktop Entry"; 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| { if (entry.DesktopNames) |desktop_names| {
for (desktop_names) |*c| { for (desktop_names) |*c| {
if (c.* == ';') 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); const maybe_session_desktop = if (maybe_xdg_session_desktop) |xdg_session_desktop| try session.label.allocator.dupeZ(u8, xdg_session_desktop) else null;
errdefer session.label.allocator.free(session_desktop); errdefer if (maybe_session_desktop) |session_desktop| session.label.allocator.free(session_desktop);
try session.addEnvironment(.{ try session.addEnvironment(.{
.entry_ini = entry_ini, .entry_ini = entry_ini,
.name = entry.Name, .name = entry.Name,
.xdg_session_desktop = session_desktop, .xdg_session_desktop = maybe_session_desktop,
.xdg_desktop_names = xdg_desktop_names, .xdg_desktop_names = maybe_xdg_desktop_names,
.cmd = entry.Exec, .cmd = entry.Exec,
.specifier = switch (display_server) { .specifier = switch (display_server) {
.wayland => lang.wayland, .wayland => lang.wayland,
.x11 => lang.x11, .x11 => lang.x11,
.custom => lang.custom,
else => lang.other, else => lang.other,
}, },
.display_server = display_server, .display_server = display_server,
.is_terminal = entry.Terminal orelse false,
}); });
} }
} }
fn getAllUsernames(allocator: std.mem.Allocator, login_defs_path: []const u8) !StringList {
const uid_range = try getUserIdRange(allocator, login_defs_path);
var usernames: StringList = .empty;
var maybe_entry = interop.pwd.getpwent();
while (maybe_entry != null) {
const entry = maybe_entry.*;
// We check if the UID is equal to 0 because we always want to add root
// as a username (even if you can't log into it)
if (entry.pw_uid >= uid_range.uid_min and entry.pw_uid <= uid_range.uid_max or entry.pw_uid == 0) {
const pw_name_slice = entry.pw_name[0..std.mem.len(entry.pw_name)];
const username = try allocator.dupe(u8, pw_name_slice);
try usernames.append(allocator, username);
}
maybe_entry = interop.pwd.getpwent();
}
interop.pwd.endpwent();
return usernames;
}
// This is very bad parsing, but we only need to get 2 values... and the format
// of the file doesn't seem to be standard? So this should be fine...
fn getUserIdRange(allocator: std.mem.Allocator, login_defs_path: []const u8) !UidRange {
const login_defs_file = try std.fs.cwd().openFile(login_defs_path, .{});
defer login_defs_file.close();
const login_defs_buffer = try login_defs_file.readToEndAlloc(allocator, std.math.maxInt(u16));
defer allocator.free(login_defs_buffer);
var iterator = std.mem.splitScalar(u8, login_defs_buffer, '\n');
var uid_range = UidRange{};
while (iterator.next()) |line| {
const trimmed_line = std.mem.trim(u8, line, " \n\r\t");
if (std.mem.startsWith(u8, trimmed_line, "UID_MIN")) {
uid_range.uid_min = try parseValue(std.c.uid_t, "UID_MIN", trimmed_line);
} else if (std.mem.startsWith(u8, trimmed_line, "UID_MAX")) {
uid_range.uid_max = try parseValue(std.c.uid_t, "UID_MAX", trimmed_line);
}
}
return uid_range;
}
fn parseValue(comptime T: type, name: []const u8, buffer: []const u8) !T {
var iterator = std.mem.splitAny(u8, buffer, " \t");
var maybe_value: ?T = null;
while (iterator.next()) |slice| {
// Skip the slice if it's empty (whitespace) or is the name of the
// property (e.g. UID_MIN or UID_MAX)
if (slice.len == 0 or std.mem.eql(u8, slice, name)) continue;
maybe_value = std.fmt.parseInt(T, slice, 10) catch continue;
}
return maybe_value orelse error.ValueNotFound;
}
fn adjustBrightness(allocator: std.mem.Allocator, cmd: []const u8) !void { fn adjustBrightness(allocator: std.mem.Allocator, cmd: []const u8) !void {
var brightness = std.process.Child.init(&[_][]const u8{ "/bin/sh", "-c", cmd }, allocator); var brightness = std.process.Child.init(&[_][]const u8{ "/bin/sh", "-c", cmd }, allocator);
brightness.stdout_behavior = .Ignore; brightness.stdout_behavior = .Ignore;

View File

@ -208,9 +208,9 @@ pub fn drawColorLabel(text: []const u8, x: usize, y: usize, fg: u32, bg: u32) vo
const utf8view = std.unicode.Utf8View.init(text) catch return; const utf8view = std.unicode.Utf8View.init(text) catch return;
var utf8 = utf8view.iterator(); var utf8 = utf8view.iterator();
var i = x; var i: c_int = @intCast(x);
while (utf8.nextCodepoint()) |codepoint| : (i += 1) { while (utf8.nextCodepoint()) |codepoint| : (i += termbox.tb_wcwidth(codepoint)) {
_ = termbox.tb_set_cell(@intCast(i), yc, codepoint, fg, bg); _ = termbox.tb_set_cell(i, yc, codepoint, fg, bg);
} }
} }
@ -219,10 +219,10 @@ pub fn drawConfinedLabel(self: TerminalBuffer, text: []const u8, x: usize, y: us
const utf8view = std.unicode.Utf8View.init(text) catch return; const utf8view = std.unicode.Utf8View.init(text) catch return;
var utf8 = utf8view.iterator(); var utf8 = utf8view.iterator();
var i: usize = 0; var i: c_int = @intCast(x);
while (utf8.nextCodepoint()) |codepoint| : (i += 1) { while (utf8.nextCodepoint()) |codepoint| : (i += termbox.tb_wcwidth(codepoint)) {
if (i >= max_length) break; if (i - @as(c_int, @intCast(x)) >= max_length) break;
_ = termbox.tb_set_cell(@intCast(i + x), yc, codepoint, self.fg, self.bg); _ = termbox.tb_set_cell(i, yc, codepoint, self.fg, self.bg);
} }
} }
@ -236,7 +236,8 @@ pub fn drawCharMultiple(self: TerminalBuffer, char: u32, x: usize, y: usize, len
pub fn strWidth(str: []const u8) !u8 { pub fn strWidth(str: []const u8) !u8 {
const utf8view = try std.unicode.Utf8View.init(str); const utf8view = try std.unicode.Utf8View.init(str);
var utf8 = utf8view.iterator(); var utf8 = utf8view.iterator();
var i: u8 = 0; var i: c_int = 0;
while (utf8.nextCodepoint()) |_| i += 1; while (utf8.nextCodepoint()) |codepoint| i += termbox.tb_wcwidth(codepoint);
return i;
return @intCast(i);
} }

View File

@ -0,0 +1,45 @@
const std = @import("std");
const TerminalBuffer = @import("../TerminalBuffer.zig");
const generic = @import("generic.zig");
const StringList = std.ArrayListUnmanaged([]const u8);
const Allocator = std.mem.Allocator;
const UsernameText = generic.CyclableLabel([]const u8);
const UserList = @This();
label: UsernameText,
pub fn init(allocator: Allocator, buffer: *TerminalBuffer, usernames: StringList) !UserList {
var userList = UserList{
.label = UsernameText.init(allocator, buffer, drawItem),
};
for (usernames.items) |username| {
if (username.len == 0) continue;
try userList.label.addItem(username);
}
return userList;
}
pub fn deinit(self: *UserList) void {
self.label.deinit();
}
pub fn getCurrentUser(self: UserList) []const u8 {
return self.label.list.items[self.label.current];
}
fn drawItem(label: *UsernameText, username: []const u8, _: usize, _: usize) bool {
const length = @min(username.len, label.visible_length - 3);
if (length == 0) return false;
const x = if (label.text_in_center) (label.x + (label.visible_length - username.len) / 2) else (label.x + 2);
label.first_char_x = x + username.len;
label.buffer.drawLabel(username, x, label.y);
return true;
}