feat: ask which lock screen to use on hyprland and niri

This commit is contained in:
Felitendo committed 2026-09-26 19:37:06 +02:00
1 parent 5699158bb1
commit 1da82f21fc
34 files changed
+5319 -1609

No files matched your search

+2
View File
@@ -156,6 +156,8 @@ fu_head() { printf '\n%s%s%s\n\n' "$FU_C_BOLD$FU_C_BLUE" "$*" "$FU_C_RESET"; }
fu_ok() { FU_UI_NOTICES+=("$FU_C_GREEN✔$FU_C_RESET $*"); printf '%s✔%s %s\n' "$FU_C_GREEN" "$FU_C_RESET" "$*"; }
fu_bad() { FU_UI_NOTICES+=("$FU_C_RED✘$FU_C_RESET $*"); printf '%s✘%s %s\n' "$FU_C_RED" "$FU_C_RESET" "$*" >&2; }
fu_note() { FU_UI_NOTICES+=("$FU_C_DIM•$FU_C_RESET $*"); printf '%s•%s %s\n' "$FU_C_DIM" "$FU_C_RESET" "$*"; }
# A line of config to copy, under a note.
fu_code() { FU_UI_NOTICES+=(" $*"); printf ' %s\n' "$*"; }
fu_have() { command -v "$1" > /dev/null 2>&1; }
+28 -7
View File
@@ -200,6 +200,8 @@ fu_value_label() {
AnimationSpeed:slow) fu_msg "slow" ;;
ScanSeconds:*) fu_msg "%s seconds" "$2" ;;
Camera:auto) fu_msg "automatic" ;;
LockScreenStyle:own) fu_msg "face-unlock's" ;;
LockScreenStyle:*) fu_msg "yours" ;;
*) printf '%s' "$2" ;;
esac
}
@@ -277,10 +279,11 @@ fu_ui_status() {
# scope user (this user's file), sys (the system file, through sudo),
# pam (the service of that name, through sudo), or group for a
# heading, with only the label after it
# type bool, choice (steps through the choices), camera, or path (typed
# in; empty for the desktop's picture)
# needs a bool setting this one does nothing without; it is dimmed while
# that is off
# type bool, choice (steps through the choices), camera, path (typed
# in; empty for the desktop's picture), or lockstyle (the window
# with the two lock screens, see fu_lock_choose)
# needs a bool setting this one does nothing without, or Key=value; it is
# dimmed while that is not so
# only lockers: only where the lock screen is a program of its own with a
# PAM file (Hyprland, Niri), see fu_pam_lockers_here; ownlock: only
# where face-unlock's own lock screen can be used
@@ -289,8 +292,9 @@ FU_SETTINGS=(
"user|LockScreen|bool|yes|Unlock with your face"
"user|ScanOnWake|bool|yes|Scan when you come back||LockScreen"
"user|ScanOnLock|bool|no|Scan right after locking||LockScreen"
"user|LockWallpaper|path||Wallpaper|||ownlock"
"user|LockBlur|bool|no|Blur the wallpaper|||ownlock"
"user|LockScreenStyle|lockstyle|yours|Which lock screen|||ownlock"
"user|LockWallpaper|path||Wallpaper||LockScreenStyle=own|ownlock"
"user|LockBlur|bool|no|Blur the wallpaper||LockScreenStyle=own|ownlock"
"group|Password prompts"
"pam|sudo|bool|no|sudo in a terminal"
"pam|polkit-1|bool|no|Admin prompts"
@@ -328,6 +332,7 @@ fu_setting_help() {
ScanOnWake:*) fu_msg "Scans when you press a key or move the mouse on the lock screen, and when the computer wakes up." ;;
ScanOnLock:*) fu_msg "Scans as soon as the screen locks. Off by default: if you lock it yourself, it would unlock again right away." ;;
sudo:*) fu_msg "sudo takes your face instead of the password. No match: you type the password as usual." ;;
LockScreenStyle:*) fu_msg "face-unlock's lock screen shows the bubble, and you lock with \`face-unlock lock\`. Or keep yours: hyprlock then shows a line of text at the top. Enter opens the choice." ;;
LockWallpaper:*) fu_msg "The picture behind face-unlock's own lock screen (\`face-unlock lock\`). Empty: the one on your desktop. Or a file, a folder to take one from at random, or \`none\`. Enter to type it." ;;
LockBlur:*) fu_msg "Blurs the picture behind face-unlock's own lock screen." ;;
lockscreens:*) fu_msg "The lock screen takes your face in its password check. Press Enter on the empty field to scan. Found here: %s." "$(fu_pam_lockers_list)" ;;
@@ -483,6 +488,18 @@ _fu_setting_change() {
bool) if fu_is_true "$current"; then next=no; else next=yes; fi ;;
choice) next="$(_fu_next_choice "$current" "$options" "$step")" ;;
camera) next="$(_fu_next_camera "$current" "$step")" ;;
lockstyle)
# The window with the pictures where there is a screen for it,
# else the other one of the two.
if [[ -n ${WAYLAND_DISPLAY:-} ]]; then
fu_ui_cooked fu_lock_choose
elif [[ $current == own ]]; then
fu_lock_style_set yours
else
fu_lock_style_set own
fi
return 0
;;
path)
printf '\n %s ' "$(fu_msg "Picture or folder:")"
fu_ui_read_line "$current" || return 0
@@ -612,7 +629,11 @@ fu_ui_settings() {
before="${FU_C_BLUE}◂${FU_C_RESET} " after=" ${FU_C_BLUE}▸${FU_C_RESET}"
fi
dim=''
[[ -n ${needs[i]} ]] && ! fu_is_true "${current[${needs[i]}]}" && dim="$FU_C_DIM"
case "${needs[i]}" in
'') ;;
*=*) [[ ${current[${needs[i]%%=*}]} == "${needs[i]#*=}" ]] || dim="$FU_C_DIM" ;;
*) fu_is_true "${current[${needs[i]}]}" || dim="$FU_C_DIM" ;;
esac
pad=$(( width + 2 - widths[i] ))
if (( i == selected )); then marker="${FU_C_BLUE}▸${FU_C_RESET} "; else marker=' '; fi
printf -v row ' %s%s%s%s%*s%s%s%s' "$marker" "$dim" "${labels[i]}" "$FU_C_RESET" "$pad" '' "$before" "$dim$shown$FU_C_RESET" "$after"
+123
View File
@@ -193,6 +193,129 @@ fu_gnome_extension_disable() {
gsettings set org.gnome.shell enabled-extensions "$list" > /dev/null 2>&1 || true
}
# ---------------------------------------------------------------------------
# The lock screen where it is a program of its own (Hyprland, Niri)
# ---------------------------------------------------------------------------
# Either face-unlock's (`face-unlock lock`, with the bubble), or the user's
# own program. hyprlock then shows what the bubble would as a line of text: a
# label in its config reads a file the agent writes (see
# src/agent/locktext.h). Asked once in a window, and under Settings.
FU_HYPRLOCK_SNIPPET="$FU_XDG_CONFIG/$FU_NAME/hyprlock.conf"
FU_HYPRLOCK_MARK="# $FU_NAME: what face unlock is doing, at the top"
fu_own_lock_here() {
[[ $FU_DESKTOP != plasma && $FU_DESKTOP != gnome ]]
}
# fu_hyprlock_text_on
# 0 done, 1 could not write, 2 no hyprlock, 3 hyprlock has no config here.
fu_hyprlock_text_on() {
local conf="$FU_XDG_CONFIG/hypr/hyprlock.conf"
fu_have hyprlock || return 2
[[ -f $conf ]] || return 3
mkdir -p "${FU_HYPRLOCK_SNIPPET%/*}" || return 1
cat > "$FU_HYPRLOCK_SNIPPET" <<- EOF || return 1
# Written by $FU_NAME: what face unlock is doing, as a line at the top of
# hyprlock. Picking $FU_NAME's lock screen in its menu takes it out again.
label {
monitor =
text = cmd[update:0:1] cat "\$XDG_RUNTIME_DIR/$FU_NAME/lock-text" 2>/dev/null
color = rgba(255, 255, 255, 0.95)
font_size = 20
shadow_passes = 2
shadow_size = 3
halign = center
valign = top
position = 0, -48
zindex = 10
}
EOF
grep -qxF "$FU_HYPRLOCK_MARK" "$conf" && return 0
# With ~ where it can, like a hand-written config. hyprlock expands it.
local snippet="$FU_HYPRLOCK_SNIPPET"
# shellcheck disable=SC2088 # for hyprlock, not for the shell
[[ $snippet == "$HOME"/* ]] && snippet="~/${snippet#"$HOME"/}"
printf '\n%s\nsource = %s\n' "$FU_HYPRLOCK_MARK" "$snippet" >> "$conf" || return 1
}
# fu_hyprlock_text_off
# The mark, the source line under it, and the empty lines before it. Written
# back in place, so a hyprlock.conf that is a link to a dotfile stays one.
fu_hyprlock_text_off() {
local conf="$FU_XDG_CONFIG/hypr/hyprlock.conf" content
rm -f "$FU_HYPRLOCK_SNIPPET"
[[ -f $conf ]] && grep -qxF "$FU_HYPRLOCK_MARK" "$conf" || return 0
content="$(awk -v mark="$FU_HYPRLOCK_MARK" '
$0 == mark { held = ""; skip = 1; next }
skip && /^[[:space:]]*source[[:space:]]*=/ { skip = 0; next }
{ skip = 0 }
/^[[:space:]]*$/ { held = held $0 "\n"; next }
{ printf "%s", held; held = ""; print }
' "$conf")" || return 1
printf '%s\n' "$content" > "$conf"
}
# fu_own_lock_hint
# Where face-unlock's lock screen has to be started from: the user's key and
# idle lock, which are theirs to change.
fu_own_lock_hint() {
# shellcheck disable=SC2088 # shown to the user, not a path to open
case "$FU_DESKTOP" in
hyprland)
if [[ -f $FU_XDG_CONFIG/hypr/hyprland.lua ]]; then
fu_note "$(fu_msg "To lock with it, add this to %s, and set %s in %s:" "~/.config/hypr/hyprland.lua" "lock_cmd = $FU_NAME lock" "hypridle.conf")"
fu_code "hl.bind(\"SUPER + L\", hl.dsp.exec_cmd(\"$FU_NAME lock\"))"
else
fu_note "$(fu_msg "To lock with it, add this to %s, and set %s in %s:" "~/.config/hypr/hyprland.conf" "lock_cmd = $FU_NAME lock" "hypridle.conf")"
fu_code "bind = SUPER, L, exec, $FU_NAME lock"
fi
;;
niri)
fu_note "$(fu_msg "To lock with it, add this to the binds in %s, and use %s in swayidle:" "~/.config/niri/config.kdl" "$FU_NAME lock")"
fu_code "Mod+Alt+L { spawn \"$FU_NAME\" \"lock\"; }"
;;
*)
fu_note "$(fu_msg "To lock with it, run %s where your lock screen is started now." "$FU_NAME lock")"
;;
esac
}
# fu_lock_style_set <own|yours>
fu_lock_style_set() {
# shellcheck disable=SC2088 # shown to the user, not a path to open
local conf="~/.config/hypr/hyprlock.conf"
case "$1" in
own)
fu_config_set LockScreenStyle own || { fu_bad "$(fu_msg "Could not save the setting.")"; return 1; }
fu_hyprlock_text_off
fu_ok "$(fu_msg "You lock with face-unlock's lock screen now.")"
fu_own_lock_hint
;;
yours)
fu_config_set LockScreenStyle yours || { fu_bad "$(fu_msg "Could not save the setting.")"; return 1; }
fu_hyprlock_text_on
case $? in
0) fu_ok "$(fu_msg "hyprlock shows what face unlock is doing at the top, from the next time it locks.")" ;;
1) fu_bad "$(fu_msg "Could not add the line to %s." "$conf")" ;;
2) fu_ok "$(fu_msg "Your lock screen stays as it is. Press Enter on the empty password field to scan.")" ;;
3) fu_note "$(fu_msg "hyprlock has no %s, so it cannot show the text." "$conf")" ;;
esac
;;
*) return 1 ;;
esac
}
# fu_lock_choose
# Asks in a window which lock screen to use, and carries it out. 1 when the
# window was closed or cannot open.
fu_lock_choose() {
local choice
[[ -n ${WAYLAND_DISPLAY:-} ]] || return 1
choice="$("$FU_AGENT" --choose-lock-screen 2> /dev/null)" || return 1
fu_lock_style_set "$choice"
}
fu_agent_disable() {
systemctl --user disable --now "$FU_UNIT_AGENT" > /dev/null 2>&1 || true
}