From 74de04faa4c51cf2a9442dcfe246dc04d1f8d19a Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Fri, 16 Oct 2026 10:07:26 +0200 Subject: fix(user): the avatar is ~/.user-icon.jpg, as hyprlock and SDDM use The page showed AccountsService's icon, an older picture than the one the rest of the desktop uses: hyprlock, the udt SDDM theme (pointed at it by udt-accent) and the rofi power menu all read ~/.user-icon.jpg. get now prefers that file, and set converts the pick to JPEG there, through a temp file and a rename, before handing it to AccountsService so both agree. Co-Authored-By: Claude Opus 5.5 --- desktop/modules/user/README.md | 5 ++--- desktop/modules/user/test-userctl.sh | 19 +++++++++++++++++-- desktop/modules/user/userctl | 15 +++++++++++++-- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/desktop/modules/user/README.md b/desktop/modules/user/README.md index 7a09c07..6e67b50 100644 --- a/desktop/modules/user/README.md +++ b/desktop/modules/user/README.md @@ -7,7 +7,7 @@ it opens, which edits the user's details where other programs read them. | --- | --- | | name | AccountsService `RealName` (which also rewrites the passwd GECOS that LibreOffice prefills from), `~/.config/emaildefaults` `FullName`, git `user.name` with the surname as an initial | | email | AccountsService `Email`, emaildefaults `EmailAddress`, git `user.email` | -| avatar | AccountsService `IconFile`; the daemon copies the file in and SDDM shows it | +| avatar | `~/.user-icon.jpg` (converted to JPEG with `magick`), which hyprlock, the udt SDDM theme and the rofi power menu read; then AccountsService `IconFile`, so its consumers agree | | language, location | AccountsService | | signing key | git `user.signingkey`; None unsets it | @@ -25,6 +25,5 @@ Checks: `./test-userctl.sh` (stubs every store) and `node desktop/modules/user/test_user.js`. Not here: the password (`passwd` in a terminal; changing it also leaves the -login keyring on the old one), `~/.face.icon` (SDDM reads the -AccountsService icon), social links (nothing reads them). Values are read +login keyring on the old one), `~/.face.icon` (nothing here reads it), social links (nothing reads them). Values are read when the page opens, not watched. diff --git a/desktop/modules/user/test-userctl.sh b/desktop/modules/user/test-userctl.sh index 02a6e0c..33d50a2 100755 --- a/desktop/modules/user/test-userctl.sh +++ b/desktop/modules/user/test-userctl.sh @@ -34,11 +34,12 @@ case "$n" in busctl) [[ " $* " == *" get-property "* ]] && printf '{"type":"s","data":"%s"}\n' "${@: -1}" ;; git) [[ " $* " == *" --get "* ]] && { [[ -n "${GIT_VALUE:-}" ]] && echo "$GIT_VALUE" || exit 1; } ;; gpg) cat "$GPG_FIXTURE" ;; + magick) : > "${@: -1}" ;; esac exit 0 EOF chmod +x "$tmp/bin/stub" -for n in busctl kwriteconfig6 git gpg; do ln -s stub "$tmp/bin/$n"; done +for n in busctl kwriteconfig6 git gpg magick; do ln -s stub "$tmp/bin/$n"; done export PATH="$tmp/bin:$PATH" HOME="$tmp" LOG="$tmp/log" obj="/org/freedesktop/Accounts/User$(id -u)" @@ -66,6 +67,11 @@ language=Language location=Location signingkey=ABCDEF" "$("$ctl" get)" +# The desktop's avatar file, once it exists, wins over AccountsService's. +: > "$HOME/.user-icon.jpg" +check "get prefers ~/.user-icon.jpg" "avatar=$HOME/.user-icon.jpg" "$("$ctl" get | grep '^avatar=')" +rm "$HOME/.user-icon.jpg" + # keys: the primary fingerprint and first uid of each secret key; subkey # fingerprints and later uids are skipped. reset @@ -111,12 +117,21 @@ kwriteconfig6 [--file] [emaildefaults] [--group] [PROFILE_Default] [--key] [Emai git [config] [--global] [user.email] [jane@example.org]" "$(cat "$LOG")" # AccountsService only. -for pair in avatar:SetIconFile language:SetLanguage location:SetLocation; do +for pair in language:SetLanguage location:SetLocation; do reset "$ctl" set "${pair%%:*}" v >/dev/null check "set ${pair%%:*} writes" "$acc [${pair#*:}] [s] [v]" "$(cat "$LOG")" done +# avatar: converted to ~/.user-icon.jpg through a temp file, then handed to +# AccountsService, so the greeter, hyprlock and the login screen agree. +reset +"$ctl" set avatar /pics/me.png >/dev/null +check "set avatar writes" "magick [/pics/me.png] [-auto-orient] [-strip] [$HOME/.user-icon.jpg.tmp.jpg] +$acc [SetIconFile] [s] [$HOME/.user-icon.jpg]" "$(cat "$LOG")" +check "set avatar leaves the file" "yes" "$([[ -e "$HOME/.user-icon.jpg" && ! -e "$HOME/.user-icon.jpg.tmp.jpg" ]] && echo yes)" +rm -f "$HOME/.user-icon.jpg" + # signingkey: a fingerprint is written; empty unsets, but only if one is set. reset "$ctl" set signingkey ABCD >/dev/null diff --git a/desktop/modules/user/userctl b/desktop/modules/user/userctl index d9720d8..5ad31d1 100755 --- a/desktop/modules/user/userctl +++ b/desktop/modules/user/userctl @@ -18,7 +18,9 @@ # userctl set write one field to every store holding it # # Stores: AccountsService (and through SetRealName the passwd GECOS that -# LibreOffice reads), KDE's ~/.config/emaildefaults, the global git config. +# LibreOffice reads), KDE's ~/.config/emaildefaults, the global git config, +# and ~/.user-icon.jpg, the avatar hyprlock, the SDDM theme and the rofi +# power menu read (udt-accent points the greeter at it). # Polkit lets a user change their own AccountsService entry without a prompt. # # set prints nothing on success. On a failing write it prints the command and @@ -30,6 +32,7 @@ set -u # Character-wise ${x:0:1}, so an accented initial is not cut in half. export LC_ALL=C.UTF-8 +AVATAR="$HOME/.user-icon.jpg" ACC=org.freedesktop.Accounts OBJ="/org/freedesktop/Accounts/User$(id -u)" IFACE=org.freedesktop.Accounts.User @@ -77,6 +80,8 @@ case "$1" in # Read everything first: one error line and exit 1, never blank fields. for p in RealName:name Email:email IconFile:avatar Language:language Location:location; do val="$(prop "${p%%:*}")" || { printf 'error=%s\n' "$val"; exit 1; } + # The desktop's avatar wins; AccountsService's is the fallback. + [[ "${p#*:}" == avatar && -e "$AVATAR" ]] && val="$AVATAR" out+="${p#*:}=$val"$'\n' done printf '%s' "$out" @@ -104,7 +109,13 @@ case "$1" in kde EmailAddress "$v" run git config --global user.email "$v" ;; - avatar) acc SetIconFile "$v" ;; + avatar) + # Converted, so the .jpg name is true whatever was picked; + # renamed into place, so no reader sees half a file. + run magick "$v" -auto-orient -strip "$AVATAR.tmp.jpg" + run mv -f "$AVATAR.tmp.jpg" "$AVATAR" + acc SetIconFile "$AVATAR" + ;; language) acc SetLanguage "$v" ;; location) acc SetLocation "$v" ;; signingkey) -- cgit v1.2.3