mirror of https://github.com/fairyglade/ly.git
Merge branch 'master' into refactor/termbox2-dependency
This commit is contained in:
commit
6933c4db02
14
build.zig
14
build.zig
|
@ -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});
|
||||
};
|
||||
|
||||
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" });
|
||||
std.fs.cwd().makePath(ly_lang_path) catch {
|
||||
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 });
|
||||
}
|
||||
|
||||
{
|
||||
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;
|
||||
defer lang_dir.close();
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
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).
|
||||
|
||||
## Dependencies
|
||||
|
|
|
@ -100,20 +100,28 @@ colormix_col2 = 0x000000FF
|
|||
# Color mixing animation third color id
|
||||
colormix_col3 = 0x20000000
|
||||
|
||||
# Console path
|
||||
console_dev = /dev/console
|
||||
# Custom sessions directory
|
||||
# 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
|
||||
# Available inputs: info_line, session, login, password
|
||||
default_input = login
|
||||
|
||||
# DOOM animation top color (low intensity flames)
|
||||
doom_top_color = 0x00FF0000
|
||||
# DOOM animation fire height (1 thru 9)
|
||||
doom_fire_height = 6
|
||||
|
||||
# DOOM animation middle color (medium intensity flames)
|
||||
doom_middle_color = 0x00FFFF00
|
||||
# DOOM animation fire spread (0 thru 4)
|
||||
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
|
||||
|
||||
# Error background color id
|
||||
|
@ -176,6 +184,9 @@ load = true
|
|||
# You can also set environment variables in there, they'll persist until logout
|
||||
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
|
||||
# If null, no command will be executed
|
||||
# Important: the session will already be terminated when this command is executed, so
|
||||
|
@ -248,7 +259,7 @@ vi_mode = false
|
|||
|
||||
# Wayland desktop environments
|
||||
# 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
|
||||
|
||||
# Xorg server command
|
||||
|
@ -263,5 +274,5 @@ xinitrc = ~/.xinitrc
|
|||
|
||||
# Xorg desktop environments
|
||||
# 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
|
||||
|
|
|
@ -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)
|
|
@ -2,17 +2,18 @@ authenticating = جاري المصادقة...
|
|||
brightness_down = خفض السطوع
|
||||
brightness_up = رفع السطوع
|
||||
capslock = capslock
|
||||
|
||||
err_alloc = فشل في تخصيص الذاكرة
|
||||
err_bounds = out-of-bounds index
|
||||
err_brightness_change = فشل في تغيير سطوع الشاشة
|
||||
err_chdir = فشل في فتح مجلد المنزل
|
||||
err_config = فشل في تفسير ملف الإعدادات
|
||||
err_console_dev = فشل في الوصول إلى جهاز وحدة التحكم
|
||||
err_dgn_oob = رسالة سجل (Log)
|
||||
err_domain = اسم نطاق غير صالح
|
||||
err_empty_password = لا يُسمح بكلمة مرور فارغة
|
||||
err_envlist = فشل في جلب قائمة المتغيرات البيئية
|
||||
err_hostname = فشل في جلب اسم المضيف (Hostname)
|
||||
|
||||
err_mlock = فشل في تأمين ذاكرة كلمة المرور (mlock)
|
||||
err_null = مؤشر فارغ (Null pointer)
|
||||
err_numlock = فشل في ضبط Num Lock
|
||||
|
@ -38,7 +39,9 @@ err_perm_group = فشل في تخفيض صلاحيات المجموعة (Group p
|
|||
err_perm_user = فشل في تخفيض صلاحيات المستخدم (User permissions)
|
||||
err_pwnam = فشل في جلب معلومات المستخدم
|
||||
err_sleep = فشل في تنفيذ أمر sleep
|
||||
|
||||
err_tty_ctrl = فشل في نقل تحكم الطرفية (TTY)
|
||||
|
||||
err_user_gid = فشل في تعيين معرّف المجموعة (GID) للمستخدم
|
||||
err_user_init = فشل في تهيئة بيانات المستخدم
|
||||
err_user_uid = فشل في تعيين معرّف المستخدم (UID)
|
||||
|
|
|
@ -2,17 +2,18 @@ authenticating = autenticant...
|
|||
brightness_down = abaixar brillantor
|
||||
brightness_up = apujar brillantor
|
||||
capslock = Bloq Majús
|
||||
|
||||
err_alloc = assignació de memòria fallida
|
||||
err_bounds = índex fora de límits
|
||||
err_brightness_change = error en canviar la brillantor
|
||||
err_chdir = error en obrir la carpeta home
|
||||
|
||||
err_console_dev = error en accedir a la consola
|
||||
err_dgn_oob = missatge de registre
|
||||
err_domain = domini invàlid
|
||||
|
||||
err_envlist = error en obtenir l'envlist
|
||||
err_hostname = error en obtenir el nom de l'amfitrió
|
||||
|
||||
err_mlock = error en bloquejar la memòria de clau
|
||||
err_null = punter nul
|
||||
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_user_gid = error en establir el GID de l'usuari
|
||||
err_user_init = error en inicialitzar usuari
|
||||
err_user_uid = error en establir l'UID de l'usuari
|
||||
|
|
|
@ -2,17 +2,18 @@
|
|||
|
||||
|
||||
capslock = capslock
|
||||
|
||||
err_alloc = alokace paměti selhala
|
||||
err_bounds = index je mimo hranice pole
|
||||
|
||||
err_chdir = nelze otevřít domovský adresář
|
||||
|
||||
err_console_dev = chyba při přístupu do konzole
|
||||
err_dgn_oob = zpráva protokolu
|
||||
err_domain = neplatná doména
|
||||
|
||||
|
||||
err_hostname = nelze získat název hostitele
|
||||
|
||||
err_mlock = uzamčení paměti hesel selhalo
|
||||
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_user_gid = nastavení GID uživatele selhalo
|
||||
err_user_init = inicializace uživatele selhala
|
||||
err_user_uid = nastavení UID uživateli selhalo
|
||||
|
|
|
@ -2,17 +2,18 @@ authenticating = authentifizieren...
|
|||
brightness_down = Helligkeit-
|
||||
brightness_up = Helligkeit+
|
||||
capslock = Feststelltaste
|
||||
|
||||
err_alloc = Speicherzuweisung fehlgeschlagen
|
||||
err_bounds = Index ausserhalb des Bereichs
|
||||
err_brightness_change = Helligkeitsänderung fehlgeschlagen
|
||||
err_chdir = Fehler beim Oeffnen des Home-Ordners
|
||||
err_config = Fehler beim Verarbeiten der Konfigurationsdatei
|
||||
err_console_dev = Zugriff auf die Konsole fehlgeschlagen
|
||||
err_dgn_oob = Diagnose-Nachricht
|
||||
err_domain = Ungueltige Domain
|
||||
err_empty_password = Leeres Passwort nicht zugelassen
|
||||
err_envlist = Fehler beim Abrufen der Umgebungs-Variablen
|
||||
err_hostname = Abrufen des Hostnames fehlgeschlagen
|
||||
|
||||
err_mlock = Sperren des Passwortspeichers fehlgeschlagen
|
||||
err_null = Null Pointer
|
||||
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_pwnam = Abrufen der Benutzerinformationen fehlgeschlagen
|
||||
err_sleep = Sleep-Befehl fehlgeschlagen
|
||||
|
||||
err_tty_ctrl = Fehler bei der TTY-Uebergabe
|
||||
|
||||
err_user_gid = Fehler beim Setzen der Gruppen-ID
|
||||
err_user_init = Nutzer-Initialisierung fehlgeschlagen
|
||||
err_user_uid = Setzen der Benutzer-ID fehlgeschlagen
|
||||
|
|
|
@ -2,17 +2,18 @@ authenticating = authenticating...
|
|||
brightness_down = decrease brightness
|
||||
brightness_up = increase brightness
|
||||
capslock = capslock
|
||||
custom = custom
|
||||
err_alloc = failed memory allocation
|
||||
err_bounds = out-of-bounds index
|
||||
err_brightness_change = failed to change brightness
|
||||
err_chdir = failed to open home folder
|
||||
err_config = unable to parse config file
|
||||
err_console_dev = failed to access console
|
||||
err_dgn_oob = log message
|
||||
err_domain = invalid domain
|
||||
err_empty_password = empty password not allowed
|
||||
err_envlist = failed to get envlist
|
||||
err_hostname = failed to get hostname
|
||||
err_lock_state = failed to get lock state
|
||||
err_mlock = failed to lock password memory
|
||||
err_null = null pointer
|
||||
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_pwnam = failed to get user info
|
||||
err_sleep = failed to execute sleep command
|
||||
err_switch_tty = failed to switch tty
|
||||
err_tty_ctrl = tty control transfer failed
|
||||
err_no_users = no users found
|
||||
err_user_gid = failed to set user GID
|
||||
err_user_init = failed to initialize user
|
||||
err_user_uid = failed to set user UID
|
||||
|
|
|
@ -2,17 +2,18 @@ authenticating = autenticando...
|
|||
brightness_down = bajar brillo
|
||||
brightness_up = subir brillo
|
||||
capslock = Bloq Mayús
|
||||
|
||||
err_alloc = asignación de memoria fallida
|
||||
err_bounds = índice fuera de límites
|
||||
|
||||
err_chdir = error al abrir la carpeta home
|
||||
|
||||
err_console_dev = error al acceder a la consola
|
||||
err_dgn_oob = mensaje de registro
|
||||
err_domain = dominio inválido
|
||||
|
||||
|
||||
err_hostname = error al obtener el nombre de host
|
||||
|
||||
err_mlock = error al bloquear la contraseña de memoria
|
||||
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_user_gid = error al establecer el GID del usuario
|
||||
err_user_init = error al inicializar usuario
|
||||
err_user_uid = error al establecer el UID del usuario
|
||||
|
|
|
@ -2,17 +2,18 @@ authenticating = authentification...
|
|||
brightness_down = diminuer la luminosité
|
||||
brightness_up = augmenter la luminosité
|
||||
capslock = verr.maj
|
||||
custom = customisé
|
||||
err_alloc = échec d'allocation mémoire
|
||||
err_bounds = indice hors-limite
|
||||
err_brightness_change = échec du changement de luminosité
|
||||
err_chdir = échec de l'ouverture du répertoire home
|
||||
err_config = échec de lecture du fichier de configuration
|
||||
err_console_dev = échec d'accès à la console
|
||||
err_dgn_oob = message
|
||||
err_domain = domaine invalide
|
||||
err_empty_password = mot de passe vide non autorisé
|
||||
err_envlist = échec de lecture de la liste d'environnement
|
||||
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_null = pointeur null
|
||||
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_pwnam = échec de lecture des infos utilisateur
|
||||
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_no_users = aucun utilisateur trouvé
|
||||
err_user_gid = échec de modification du GID
|
||||
err_user_init = échec d'initialisation de l'utilisateur
|
||||
err_user_uid = échec de modification du UID
|
||||
|
|
|
@ -2,17 +2,18 @@
|
|||
|
||||
|
||||
capslock = capslock
|
||||
|
||||
err_alloc = impossibile allocare memoria
|
||||
err_bounds = indice fuori limite
|
||||
|
||||
err_chdir = impossibile aprire home directory
|
||||
|
||||
err_console_dev = impossibile aprire console
|
||||
err_dgn_oob = messaggio log
|
||||
err_domain = dominio non valido
|
||||
|
||||
|
||||
err_hostname = impossibile ottenere hostname
|
||||
|
||||
err_mlock = impossibile ottenere lock per la password in memoria
|
||||
err_null = puntatore nullo
|
||||
|
||||
|
@ -39,6 +40,8 @@ err_perm_user = impossibile ridurre permessi utente
|
|||
err_pwnam = impossibile ottenere dati utente
|
||||
|
||||
|
||||
|
||||
|
||||
err_user_gid = impossibile impostare GID utente
|
||||
err_user_init = impossibile inizializzare utente
|
||||
err_user_uid = impossible impostare UID utente
|
||||
|
|
|
@ -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
|
|
@ -2,17 +2,18 @@ authenticating = uwierzytelnianie...
|
|||
brightness_down = zmniejsz jasność
|
||||
brightness_up = zwiększ jasność
|
||||
capslock = capslock
|
||||
|
||||
err_alloc = nieudana alokacja pamięci
|
||||
err_bounds = indeks poza zakresem
|
||||
err_brightness_change = nie udało się zmienić jasności
|
||||
err_chdir = nie udało się otworzyć folderu domowego
|
||||
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_domain = niepoprawna domena
|
||||
err_empty_password = puste hasło jest niedozwolone
|
||||
err_envlist = nie udało się pobrać listy zmiennych środowiskowych
|
||||
err_hostname = nie udało się uzyskać nazwy hosta
|
||||
|
||||
err_mlock = nie udało się zablokować pamięci haseł
|
||||
err_null = pusty wskaźnik
|
||||
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_pwnam = nie udało się uzyskać informacji o użytkowniku
|
||||
err_sleep = nie udało się wykonać polecenia sleep
|
||||
|
||||
err_tty_ctrl = nie udało się przekazać kontroli tty
|
||||
|
||||
err_user_gid = nie udało się ustawić GID użytkownika
|
||||
err_user_init = nie udało się zainicjalizować użytkownika
|
||||
err_user_uid = nie udało się ustawić UID użytkownika
|
||||
|
|
|
@ -2,17 +2,18 @@
|
|||
|
||||
|
||||
capslock = capslock
|
||||
|
||||
err_alloc = erro na atribuição de memória
|
||||
err_bounds = índice fora de limites
|
||||
|
||||
err_chdir = erro ao abrir a pasta home
|
||||
|
||||
err_console_dev = erro ao aceder à consola
|
||||
err_dgn_oob = mensagem de registo
|
||||
err_domain = domínio inválido
|
||||
|
||||
|
||||
err_hostname = erro ao obter o nome do host
|
||||
|
||||
err_mlock = erro de bloqueio de memória
|
||||
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_user_gid = erro ao definir o GID do utilizador
|
||||
err_user_init = erro ao iniciar o utilizador
|
||||
err_user_uid = erro ao definir o UID do utilizador
|
||||
|
|
|
@ -2,17 +2,18 @@
|
|||
|
||||
|
||||
capslock = caixa alta
|
||||
|
||||
err_alloc = alocação de memória malsucedida
|
||||
err_bounds = índice fora de limites
|
||||
|
||||
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_domain = domínio inválido
|
||||
|
||||
|
||||
err_hostname = não foi possível obter o nome do host
|
||||
|
||||
err_mlock = bloqueio da memória de senha malsucedido
|
||||
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_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_uid = não foi possível definir o UID do usuário
|
||||
|
|
|
@ -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
|
||||
logout = opreşte sesiunea
|
||||
|
||||
|
|
|
@ -2,17 +2,18 @@
|
|||
|
||||
|
||||
capslock = capslock
|
||||
|
||||
err_alloc = не удалось выделить память
|
||||
err_bounds = за пределами индекса
|
||||
|
||||
err_chdir = не удалось открыть домашнюю папку
|
||||
|
||||
err_console_dev = не удалось получить доступ к консоли
|
||||
err_dgn_oob = отладочное сообщение (log)
|
||||
err_domain = неверный домен
|
||||
|
||||
|
||||
err_hostname = не удалось получить имя хоста
|
||||
|
||||
err_mlock = сбой блокировки памяти
|
||||
err_null = нулевой указатель
|
||||
|
||||
|
@ -39,6 +40,8 @@ err_perm_user = не удалось понизить права доступа
|
|||
err_pwnam = не удалось получить информацию о пользователе
|
||||
|
||||
|
||||
|
||||
|
||||
err_user_gid = не удалось установить GID пользователя
|
||||
err_user_init = не удалось инициализировать пользователя
|
||||
err_user_uid = не удалось установить UID пользователя
|
||||
|
|
|
@ -2,17 +2,18 @@
|
|||
|
||||
|
||||
capslock = capslock
|
||||
|
||||
err_alloc = neuspijesna alokacija memorije
|
||||
err_bounds = izvan granica indeksa
|
||||
|
||||
err_chdir = neuspijesno otvaranje home foldera
|
||||
|
||||
err_console_dev = neuspijesno pristupanje konzoli
|
||||
err_dgn_oob = log poruka
|
||||
err_domain = nevazeci domen
|
||||
|
||||
|
||||
err_hostname = neuspijesno trazenje hostname-a
|
||||
|
||||
err_mlock = neuspijesno zakljucavanje memorije lozinke
|
||||
err_null = null pokazivac
|
||||
|
||||
|
@ -39,6 +40,8 @@ err_perm_user = neuspijesno snizavanje dozvola korisnika
|
|||
err_pwnam = neuspijesno skupljanje informacija o korisniku
|
||||
|
||||
|
||||
|
||||
|
||||
err_user_gid = neuspijesno postavljanje korisničkog GID-a
|
||||
err_user_init = neuspijensa inicijalizacija korisnika
|
||||
err_user_uid = neuspijesno postavljanje UID-a korisnika
|
||||
|
|
|
@ -2,17 +2,18 @@
|
|||
|
||||
|
||||
capslock = capslock
|
||||
|
||||
err_alloc = misslyckad minnesallokering
|
||||
err_bounds = utanför banan index
|
||||
|
||||
err_chdir = misslyckades att öppna hemkatalog
|
||||
|
||||
err_console_dev = misslyckades att komma åt konsol
|
||||
err_dgn_oob = loggmeddelande
|
||||
err_domain = okänd domän
|
||||
|
||||
|
||||
err_hostname = misslyckades att hämta värdnamn
|
||||
|
||||
err_mlock = misslyckades att låsa lösenordsminne
|
||||
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_user_gid = misslyckades att ställa in användar-GID
|
||||
err_user_init = misslyckades att initialisera användaren
|
||||
err_user_uid = misslyckades att ställa in användar-UID
|
||||
|
|
|
@ -2,17 +2,18 @@
|
|||
|
||||
|
||||
capslock = capslock
|
||||
|
||||
err_alloc = basarisiz bellek ayirma
|
||||
err_bounds = sinirlarin disinda dizin
|
||||
|
||||
err_chdir = ev klasoru acilamadi
|
||||
|
||||
err_console_dev = konsola erisilemedi
|
||||
err_dgn_oob = log mesaji
|
||||
err_domain = gecersiz etki alani
|
||||
|
||||
|
||||
err_hostname = ana bilgisayar adi alinamadi
|
||||
|
||||
err_mlock = parola bellegi kilitlenemedi
|
||||
err_null = bos isaretci hatasi
|
||||
|
||||
|
@ -39,6 +40,8 @@ err_perm_user = kullanici izinleri dusurulemedi
|
|||
err_pwnam = kullanici bilgileri alinamadi
|
||||
|
||||
|
||||
|
||||
|
||||
err_user_gid = kullanici icin GID ayarlanamadi
|
||||
err_user_init = kullanici oturumu baslatilamadi
|
||||
err_user_uid = kullanici icin UID ayarlanamadi
|
||||
|
|
|
@ -2,17 +2,18 @@
|
|||
|
||||
|
||||
capslock = capslock
|
||||
|
||||
err_alloc = невдале виділення пам'яті
|
||||
err_bounds = поза межами індексу
|
||||
|
||||
err_chdir = не вдалося відкрити домашній каталог
|
||||
|
||||
err_console_dev = невдалий доступ до консолі
|
||||
err_dgn_oob = повідомлення журналу (log)
|
||||
err_domain = недійсний домен
|
||||
|
||||
|
||||
err_hostname = не вдалося отримати ім'я хосту
|
||||
|
||||
err_mlock = збій блокування пам'яті
|
||||
err_null = нульовий вказівник
|
||||
|
||||
|
@ -39,6 +40,8 @@ err_perm_user = не вдалося понизити права доступу
|
|||
err_pwnam = не вдалося отримати дані користувача
|
||||
|
||||
|
||||
|
||||
|
||||
err_user_gid = не вдалося змінити GID користувача
|
||||
err_user_init = не вдалося ініціалізувати користувача
|
||||
err_user_uid = не вдалося змінити UID користувача
|
||||
|
|
|
@ -2,17 +2,18 @@
|
|||
|
||||
|
||||
capslock = 大写锁定
|
||||
|
||||
err_alloc = 内存分配失败
|
||||
err_bounds = 索引越界
|
||||
|
||||
err_chdir = 无法打开home文件夹
|
||||
|
||||
err_console_dev = 无法访问控制台
|
||||
err_dgn_oob = 日志消息
|
||||
err_domain = 无效的域
|
||||
|
||||
|
||||
err_hostname = 获取主机名失败
|
||||
|
||||
err_mlock = 锁定密码存储器失败
|
||||
err_null = 空指针
|
||||
|
||||
|
@ -39,6 +40,8 @@ err_perm_user = 用户权限降级失败
|
|||
err_pwnam = 获取用户信息失败
|
||||
|
||||
|
||||
|
||||
|
||||
err_user_gid = 设置用户GID失败
|
||||
err_user_init = 初始化用户失败
|
||||
err_user_uid = 设置用户UID失败
|
||||
|
|
|
@ -8,6 +8,7 @@ pub const DesktopEntry = struct {
|
|||
Exec: []const u8 = "",
|
||||
Name: [:0]const u8 = "",
|
||||
DesktopNames: ?[:0]u8 = null,
|
||||
Terminal: ?bool = null,
|
||||
};
|
||||
|
||||
pub const Entry = struct { @"Desktop Entry": DesktopEntry = .{} };
|
||||
|
@ -19,3 +20,4 @@ xdg_desktop_names: ?[:0]const u8 = null,
|
|||
cmd: []const u8 = "",
|
||||
specifier: []const u8 = "",
|
||||
display_server: DisplayServer = .wayland,
|
||||
is_terminal: bool = false,
|
||||
|
|
|
@ -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,
|
|
@ -7,21 +7,22 @@ const TerminalBuffer = @import("../tui/TerminalBuffer.zig");
|
|||
const Doom = @This();
|
||||
|
||||
pub const STEPS = 12;
|
||||
pub const HEIGHT_MAX = 9;
|
||||
pub const SPREAD_MAX = 4;
|
||||
|
||||
allocator: Allocator,
|
||||
terminal_buffer: *TerminalBuffer,
|
||||
buffer: []u8,
|
||||
height: u8,
|
||||
spread: u8,
|
||||
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);
|
||||
initBuffer(buffer, terminal_buffer.width);
|
||||
|
||||
return .{
|
||||
.allocator = allocator,
|
||||
.terminal_buffer = terminal_buffer,
|
||||
.buffer = buffer,
|
||||
.fire = [_]Cell{
|
||||
const levels =
|
||||
[_]Cell{
|
||||
Cell.init(' ', TerminalBuffer.Color.DEFAULT, TerminalBuffer.Color.DEFAULT),
|
||||
Cell.init(0x2591, 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(0x2593, 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| {
|
||||
// We start from 1 so that we always have the topmost line when spreading fire
|
||||
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 cell_index = self.buffer[from];
|
||||
|
||||
// Spread fire
|
||||
const propagate = self.terminal_buffer.random.int(u1);
|
||||
const to = from - self.terminal_buffer.width; // Get the line above
|
||||
// Generate random data for fire propagation
|
||||
const rand_loss = self.terminal_buffer.random.intRangeAtMost(u8, 0, HEIGHT_MAX);
|
||||
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
|
||||
const cell = self.fire[cell_index];
|
||||
cell.put(x, y);
|
||||
// Get fire level of current cell
|
||||
const level_buf_from = self.buffer[from];
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
37
src/auth.zig
37
src/auth.zig
|
@ -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});
|
||||
|
||||
// Set the XDG environment variables
|
||||
setXdgSessionEnv(current_environment.display_server);
|
||||
try setXdgEnv(tty_str, current_environment.xdg_session_desktop, current_environment.xdg_desktop_names);
|
||||
try setXdgEnv(tty_str, current_environment);
|
||||
|
||||
// Open the PAM session
|
||||
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();
|
||||
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);
|
||||
std.process.exit(1);
|
||||
};
|
||||
|
@ -132,6 +131,7 @@ pub fn authenticate(options: AuthOptions, current_environment: Environment, logi
|
|||
|
||||
fn startSession(
|
||||
options: AuthOptions,
|
||||
tty_str: [:0]u8,
|
||||
pwd: *interop.pwd.passwd,
|
||||
handle: ?*interop.pam.pam_handle,
|
||||
current_environment: Environment,
|
||||
|
@ -155,6 +155,9 @@ fn startSession(
|
|||
// Set up the environment
|
||||
try initEnv(pwd, options.path);
|
||||
|
||||
// Reset the XDG environment variables
|
||||
try setXdgEnv(tty_str, current_environment);
|
||||
|
||||
// Set the PAM variables
|
||||
const pam_env_vars: ?[*:null]?[*:0]u8 = interop.pam.pam_getenvlist(handle);
|
||||
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});
|
||||
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 {
|
||||
_ = interop.stdlib.setenv("XDG_SESSION_TYPE", switch (display_server) {
|
||||
fn setXdgEnv(tty_str: [:0]u8, environment: Environment) !void {
|
||||
_ = interop.stdlib.setenv("XDG_SESSION_TYPE", switch (environment.display_server) {
|
||||
.wayland => "wayland",
|
||||
.shell => "tty",
|
||||
.xinitrc, .x11 => "x11",
|
||||
.custom => "unspecified",
|
||||
}, 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
|
||||
// better to stick to the defaults and let applications using
|
||||
// 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);
|
||||
}
|
||||
|
||||
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_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_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);
|
||||
}
|
||||
|
||||
fn executeCustomCmd(shell: [*:0]const u8, options: AuthOptions, is_terminal: bool, exec_cmd: []const u8) !void {
|
||||
var maybe_log_file: ?std.fs.File = null;
|
||||
if (!is_terminal) {
|
||||
// For custom desktop entries, the "Terminal" value here determines if
|
||||
// we redirect standard output & error or not. That is, we redirect only
|
||||
// if it's equal to false (so if it's not running in a TTY).
|
||||
maybe_log_file = try redirectStandardStreams(options.session_log, true);
|
||||
}
|
||||
defer if (maybe_log_file) |log_file| log_file.close();
|
||||
|
||||
var cmd_buffer: [1024]u8 = undefined;
|
||||
const cmd_str = try std.fmt.bufPrintZ(&cmd_buffer, "{s} {s} {s}", .{ options.setup_cmd, options.login_cmd orelse "", exec_cmd });
|
||||
const args = [_:null]?[*:0]const u8{ shell, "-c", cmd_str };
|
||||
return std.posix.execveZ(shell, &args, std.c.environ);
|
||||
}
|
||||
|
||||
fn redirectStandardStreams(session_log: []const u8, create: bool) !std.fs.File {
|
||||
const log_file = if (create) (try std.fs.cwd().createFile(session_log, .{ .mode = 0o666 })) else (try std.fs.cwd().openFile(session_log, .{ .mode = .read_write }));
|
||||
|
||||
|
|
|
@ -28,8 +28,10 @@ cmatrix_max_codepoint: u16 = 0x7B,
|
|||
colormix_col1: u32 = 0x00FF0000,
|
||||
colormix_col2: u32 = 0x000000FF,
|
||||
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,
|
||||
doom_fire_height: u8 = 6,
|
||||
doom_fire_spread: u8 = 2,
|
||||
doom_top_color: u32 = 0x00FF0000,
|
||||
doom_middle_color: u32 = 0x00FFFF00,
|
||||
doom_bottom_color: u32 = 0x00FFFFFF,
|
||||
|
@ -48,6 +50,7 @@ input_len: u8 = 34,
|
|||
lang: []const u8 = "en",
|
||||
load: bool = true,
|
||||
login_cmd: ?[]const u8 = null,
|
||||
login_defs_path: []const u8 = "/etc/login.defs",
|
||||
logout_cmd: ?[]const u8 = null,
|
||||
margin_box_h: u8 = 2,
|
||||
margin_box_v: u8 = 1,
|
||||
|
|
|
@ -7,17 +7,18 @@ authenticating: []const u8 = "authenticating...",
|
|||
brightness_down: []const u8 = "decrease brightness",
|
||||
brightness_up: []const u8 = "increase brightness",
|
||||
capslock: []const u8 = "capslock",
|
||||
custom: []const u8 = "custom",
|
||||
err_alloc: []const u8 = "failed memory allocation",
|
||||
err_bounds: []const u8 = "out-of-bounds index",
|
||||
err_brightness_change: []const u8 = "failed to change brightness",
|
||||
err_chdir: []const u8 = "failed to open home folder",
|
||||
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_domain: []const u8 = "invalid domain",
|
||||
err_empty_password: []const u8 = "empty password not allowed",
|
||||
err_envlist: []const u8 = "failed to get envlist",
|
||||
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_null: []const u8 = "null pointer",
|
||||
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_pwnam: []const u8 = "failed to get user info",
|
||||
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_no_users: []const u8 = "no users found",
|
||||
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",
|
||||
|
|
|
@ -26,6 +26,7 @@ const removed_properties = [_][]const u8{
|
|||
"term_restore_cursor_cmd",
|
||||
"x_cmd_setup",
|
||||
"wayland_cmd",
|
||||
"console_dev",
|
||||
};
|
||||
|
||||
var temporary_allocator = std.heap.page_allocator;
|
||||
|
|
|
@ -11,6 +11,7 @@ pub const DisplayServer = enum {
|
|||
shell,
|
||||
xinitrc,
|
||||
x11,
|
||||
custom,
|
||||
};
|
||||
|
||||
pub const Input = enum {
|
||||
|
|
|
@ -36,7 +36,7 @@ pub const stdlib = @cImport({
|
|||
pub const pwd = @cImport({
|
||||
@cInclude("pwd.h");
|
||||
// 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");
|
||||
});
|
||||
|
||||
|
@ -75,23 +75,21 @@ pub fn timeAsString(buf: [:0]u8, format: [:0]const u8) ![]u8 {
|
|||
return buf[0..len];
|
||||
}
|
||||
|
||||
pub fn switchTty(console_dev: []const u8, tty: u8) !void {
|
||||
const fd = try std.posix.open(console_dev, .{ .ACCMODE = .WRONLY }, 0);
|
||||
defer std.posix.close(fd);
|
||||
pub fn switchTty(tty: u8) !void {
|
||||
var status = std.c.ioctl(std.c.STDIN_FILENO, vt.VT_ACTIVATE, tty);
|
||||
if (status != 0) return error.FailedToActivateTty;
|
||||
|
||||
_ = std.c.ioctl(fd, vt.VT_ACTIVATE, tty);
|
||||
_ = std.c.ioctl(fd, vt.VT_WAITACTIVE, tty);
|
||||
status = std.c.ioctl(std.c.STDIN_FILENO, vt.VT_WAITACTIVE, tty);
|
||||
if (status != 0) return error.FailedToWaitForActiveTty;
|
||||
}
|
||||
|
||||
pub fn getLockState(console_dev: []const u8) !struct {
|
||||
pub fn getLockState() !struct {
|
||||
numlock: bool,
|
||||
capslock: bool,
|
||||
} {
|
||||
const fd = try std.posix.open(console_dev, .{ .ACCMODE = .RDONLY }, 0);
|
||||
defer std.posix.close(fd);
|
||||
|
||||
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 .{
|
||||
.numlock = (led & numlock_led) != 0,
|
||||
|
@ -101,11 +99,12 @@ pub fn getLockState(console_dev: []const u8) !struct {
|
|||
|
||||
pub fn setNumlock(val: bool) !void {
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
180
src/main.zig
180
src/main.zig
|
@ -18,12 +18,15 @@ const TerminalBuffer = @import("tui/TerminalBuffer.zig");
|
|||
const Session = @import("tui/components/Session.zig");
|
||||
const Text = @import("tui/components/Text.zig");
|
||||
const InfoLine = @import("tui/components/InfoLine.zig");
|
||||
const UserList = @import("tui/components/UserList.zig");
|
||||
const Config = @import("config/Config.zig");
|
||||
const Lang = @import("config/Lang.zig");
|
||||
const Save = @import("config/Save.zig");
|
||||
const migrator = @import("config/migrator.zig");
|
||||
const SharedError = @import("SharedError.zig");
|
||||
const UidRange = @import("UidRange.zig");
|
||||
|
||||
const StringList = std.ArrayListUnmanaged([]const u8);
|
||||
const Ini = ini.Ini;
|
||||
const DisplayServer = enums.DisplayServer;
|
||||
const Entry = Environment.Entry;
|
||||
|
@ -102,6 +105,7 @@ pub fn main() !void {
|
|||
var lang: Lang = undefined;
|
||||
var save: Save = undefined;
|
||||
var config_load_failed = false;
|
||||
var can_get_lock_state = true;
|
||||
|
||||
if (res.args.help != 0) {
|
||||
try clap.help(stderr, clap.Help, ¶ms, .{});
|
||||
|
@ -289,10 +293,12 @@ pub fn main() !void {
|
|||
try info_line.addMessage(hostname, config.bg, config.fg);
|
||||
}
|
||||
|
||||
// Crawl session directories (Wayland, X11 and custom respectively)
|
||||
var wayland_session_dirs = std.mem.splitScalar(u8, config.waylandsessions, ':');
|
||||
while (wayland_session_dirs.next()) |dir| {
|
||||
try crawl(&session, lang, dir, .wayland);
|
||||
}
|
||||
|
||||
if (build_options.enable_x11_support) {
|
||||
var x_session_dirs = std.mem.splitScalar(u8, config.xsessions, ':');
|
||||
while (x_session_dirs.next()) |dir| {
|
||||
|
@ -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();
|
||||
|
||||
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
|
||||
if (config.load) {
|
||||
if (save.user) |user| {
|
||||
try login.text.appendSlice(login.allocator, user);
|
||||
login.end = user.len;
|
||||
login.cursor = login.end;
|
||||
// Find user with saved name, and switch over to it
|
||||
// If it doesn't exist (anymore), we don't change the value
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
@ -330,15 +363,13 @@ pub fn main() !void {
|
|||
const coordinates = buffer.calculateComponentCoordinates();
|
||||
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);
|
||||
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);
|
||||
|
||||
switch (active_input) {
|
||||
.info_line => info_line.label.handle(null, insert_mode),
|
||||
.session => session.label.handle(null, insert_mode),
|
||||
.login => login.handle(null, insert_mode) catch {
|
||||
try info_line.addMessage(lang.err_alloc, config.error_bg, config.error_fg);
|
||||
},
|
||||
.login => login.label.handle(null, insert_mode),
|
||||
.password => password.handle(null, insert_mode) catch {
|
||||
try info_line.addMessage(lang.err_alloc, config.error_bg, config.error_fg);
|
||||
},
|
||||
|
@ -354,7 +385,7 @@ pub fn main() !void {
|
|||
animation = dummy.animation();
|
||||
},
|
||||
.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();
|
||||
},
|
||||
.matrix => {
|
||||
|
@ -389,12 +420,10 @@ pub fn main() !void {
|
|||
var update = true;
|
||||
var resolution_changed = false;
|
||||
var auth_fails: u64 = 0;
|
||||
var can_access_console_dev = true;
|
||||
|
||||
// Switch to selected TTY if possible
|
||||
interop.switchTty(config.console_dev, config.tty) catch {
|
||||
try info_line.addMessage(lang.err_console_dev, config.error_bg, config.error_fg);
|
||||
can_access_console_dev = false;
|
||||
// Switch to selected TTY
|
||||
interop.switchTty(config.tty) catch {
|
||||
try info_line.addMessage(lang.err_switch_tty, config.error_bg, config.error_fg);
|
||||
};
|
||||
|
||||
while (run) {
|
||||
|
@ -458,7 +487,7 @@ pub fn main() !void {
|
|||
const coordinates = buffer.calculateComponentCoordinates();
|
||||
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);
|
||||
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);
|
||||
|
||||
resolution_changed = false;
|
||||
|
@ -467,9 +496,7 @@ pub fn main() !void {
|
|||
switch (active_input) {
|
||||
.info_line => info_line.label.handle(null, insert_mode),
|
||||
.session => session.label.handle(null, insert_mode),
|
||||
.login => login.handle(null, insert_mode) catch {
|
||||
try info_line.addMessage(lang.err_alloc, config.error_bg, config.error_fg);
|
||||
},
|
||||
.login => login.label.handle(null, insert_mode),
|
||||
.password => password.handle(null, insert_mode) catch {
|
||||
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);
|
||||
}
|
||||
|
||||
if (can_access_console_dev) draw_lock_state: {
|
||||
const lock_state = interop.getLockState(config.console_dev) catch {
|
||||
try info_line.addMessage(lang.err_console_dev, config.error_bg, config.error_fg);
|
||||
if (can_get_lock_state) draw_lock_state: {
|
||||
const lock_state = interop.getLockState() catch {
|
||||
try info_line.addMessage(lang.err_lock_state, config.error_bg, config.error_fg);
|
||||
can_get_lock_state = false;
|
||||
break :draw_lock_state;
|
||||
};
|
||||
|
||||
|
@ -564,7 +592,7 @@ pub fn main() !void {
|
|||
}
|
||||
|
||||
session.label.draw();
|
||||
login.draw();
|
||||
login.label.draw();
|
||||
password.draw();
|
||||
} else {
|
||||
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_U => {
|
||||
if (active_input == .login) {
|
||||
login.clear();
|
||||
update = true;
|
||||
} else if (active_input == .password) {
|
||||
if (active_input == .password) {
|
||||
password.clear();
|
||||
update = true;
|
||||
}
|
||||
|
@ -719,7 +744,7 @@ pub fn main() !void {
|
|||
defer file.close();
|
||||
|
||||
const save_data = Save{
|
||||
.user = login.text.items,
|
||||
.user = login.getCurrentUser(),
|
||||
.session_index = session.label.current,
|
||||
};
|
||||
ini.writeFromStruct(save_data, file.writer(), null, .{}) catch break :save_last_settings;
|
||||
|
@ -732,7 +757,7 @@ pub fn main() !void {
|
|||
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);
|
||||
const password_text = try allocator.dupeZ(u8, password.text.items);
|
||||
defer allocator.free(password_text);
|
||||
|
@ -838,9 +863,7 @@ pub fn main() !void {
|
|||
switch (active_input) {
|
||||
.info_line => info_line.label.handle(&event, insert_mode),
|
||||
.session => session.label.handle(&event, insert_mode),
|
||||
.login => login.handle(&event, insert_mode) catch {
|
||||
try info_line.addMessage(lang.err_alloc, config.error_bg, config.error_fg);
|
||||
},
|
||||
.login => login.label.handle(&event, insert_mode),
|
||||
.password => password.handle(&event, insert_mode) catch {
|
||||
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_desktop_names = null,
|
||||
.cmd = exec orelse "",
|
||||
.specifier = switch (display_server) {
|
||||
.wayland => lang.wayland,
|
||||
.x11 => lang.x11,
|
||||
else => lang.other,
|
||||
},
|
||||
.specifier = lang.other,
|
||||
.display_server = display_server,
|
||||
});
|
||||
}
|
||||
|
@ -890,44 +909,111 @@ fn crawl(session: *Session, lang: Lang, path: []const u8, display_server: Displa
|
|||
});
|
||||
errdefer entry_ini.deinit();
|
||||
|
||||
var xdg_session_desktop: []const u8 = undefined;
|
||||
var maybe_xdg_session_desktop: ?[]const u8 = null;
|
||||
const maybe_desktop_names = entry_ini.data.@"Desktop Entry".DesktopNames;
|
||||
if (maybe_desktop_names) |desktop_names| {
|
||||
xdg_session_desktop = std.mem.sliceTo(desktop_names, ';');
|
||||
} else {
|
||||
// if DesktopNames is empty, we'll take the name of the session file
|
||||
xdg_session_desktop = std.fs.path.stem(item.name);
|
||||
maybe_xdg_session_desktop = std.mem.sliceTo(desktop_names, ';');
|
||||
} else if (display_server != .custom) {
|
||||
// If DesktopNames is empty, and this isn't a custom session entry,
|
||||
// we'll take the name of the session file
|
||||
maybe_xdg_session_desktop = std.fs.path.stem(item.name);
|
||||
}
|
||||
|
||||
// Prepare the XDG_CURRENT_DESKTOP environment variable here
|
||||
const entry = entry_ini.data.@"Desktop Entry";
|
||||
var xdg_desktop_names: ?[:0]const u8 = null;
|
||||
var maybe_xdg_desktop_names: ?[:0]const u8 = null;
|
||||
if (entry.DesktopNames) |desktop_names| {
|
||||
for (desktop_names) |*c| {
|
||||
if (c.* == ';') c.* = ':';
|
||||
}
|
||||
xdg_desktop_names = desktop_names;
|
||||
maybe_xdg_desktop_names = desktop_names;
|
||||
}
|
||||
|
||||
const session_desktop = try session.label.allocator.dupeZ(u8, xdg_session_desktop);
|
||||
errdefer session.label.allocator.free(session_desktop);
|
||||
const maybe_session_desktop = if (maybe_xdg_session_desktop) |xdg_session_desktop| try session.label.allocator.dupeZ(u8, xdg_session_desktop) else null;
|
||||
errdefer if (maybe_session_desktop) |session_desktop| session.label.allocator.free(session_desktop);
|
||||
|
||||
try session.addEnvironment(.{
|
||||
.entry_ini = entry_ini,
|
||||
.name = entry.Name,
|
||||
.xdg_session_desktop = session_desktop,
|
||||
.xdg_desktop_names = xdg_desktop_names,
|
||||
.xdg_session_desktop = maybe_session_desktop,
|
||||
.xdg_desktop_names = maybe_xdg_desktop_names,
|
||||
.cmd = entry.Exec,
|
||||
.specifier = switch (display_server) {
|
||||
.wayland => lang.wayland,
|
||||
.x11 => lang.x11,
|
||||
.custom => lang.custom,
|
||||
else => lang.other,
|
||||
},
|
||||
.display_server = display_server,
|
||||
.is_terminal = entry.Terminal orelse false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
var brightness = std.process.Child.init(&[_][]const u8{ "/bin/sh", "-c", cmd }, allocator);
|
||||
brightness.stdout_behavior = .Ignore;
|
||||
|
|
|
@ -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;
|
||||
var utf8 = utf8view.iterator();
|
||||
|
||||
var i = x;
|
||||
while (utf8.nextCodepoint()) |codepoint| : (i += 1) {
|
||||
_ = termbox.tb_set_cell(@intCast(i), yc, codepoint, fg, bg);
|
||||
var i: c_int = @intCast(x);
|
||||
while (utf8.nextCodepoint()) |codepoint| : (i += termbox.tb_wcwidth(codepoint)) {
|
||||
_ = 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;
|
||||
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);
|
||||
var i: c_int = @intCast(x);
|
||||
while (utf8.nextCodepoint()) |codepoint| : (i += termbox.tb_wcwidth(codepoint)) {
|
||||
if (i - @as(c_int, @intCast(x)) >= max_length) break;
|
||||
_ = 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 {
|
||||
const utf8view = try std.unicode.Utf8View.init(str);
|
||||
var utf8 = utf8view.iterator();
|
||||
var i: u8 = 0;
|
||||
while (utf8.nextCodepoint()) |_| i += 1;
|
||||
return i;
|
||||
var i: c_int = 0;
|
||||
while (utf8.nextCodepoint()) |codepoint| i += termbox.tb_wcwidth(codepoint);
|
||||
|
||||
return @intCast(i);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue