nixos: unify wallpapers via syncthing

Start hyprpaper via a user service and set wallpaper via IPC on session start.\nPoint xmonad random-background at the same Syncthing wallpaper directory (X11 only).
This commit is contained in:
2026-02-05 18:37:37 -08:00
committed by Kat Huang
parent 9f3f5c5a9d
commit 789b1d96b5
2 changed files with 117 additions and 1 deletions

View File

@@ -4,6 +4,120 @@
./emacs.nix
];
# Hyprland config starts this target on login (see `dotfiles/config/hypr/hyprland.conf`).
systemd.user.targets.hyprland-session = {
Unit = {
Description = "Hyprland session (custom)";
};
};
systemd.user.services.hyprpaper = let
wallpaperDir = "/var/lib/syncthing/sync/Wallpaper";
waitForWayland = pkgs.writeShellScript "wait-for-wayland" ''
# Hyprpaper needs a Wayland socket. systemd "Condition*" checks are
# brittle here (they skip the unit entirely, with no retry) and also
# don't support expanding $WAYLAND_DISPLAY in paths.
for _ in {1..50}; do
if [ -n "$WAYLAND_DISPLAY" ] && [ -n "$XDG_RUNTIME_DIR" ] && [ -S "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" ]; then
exit 0
fi
${pkgs.coreutils}/bin/sleep 0.1
done
echo "Wayland socket not ready: WAYLAND_DISPLAY=$WAYLAND_DISPLAY XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR" >&2
exit 1
'';
setWallpaper = pkgs.writeShellScript "set-hyprpaper-wallpaper" ''
# hyprpaper 0.8.x doesn't seem to apply `wallpaper = ...` entries from
# its config on startup reliably. Explicitly set the wallpaper via IPC
# once the hyprpaper socket is ready.
#
# NOTE: hyprctl hyprpaper currently ignores `--instance` and uses
# $HYPRLAND_INSTANCE_SIGNATURE to find hyprpaper's socket, so we rely on
# the environment imported by Hyprland on login.
set -u
runtimeDir="''${XDG_RUNTIME_DIR:-}"
sig="''${HYPRLAND_INSTANCE_SIGNATURE:-}"
sockPath=""
if [ -n "$runtimeDir" ] && [ -n "$sig" ]; then
sockPath="$runtimeDir/hypr/$sig/.hyprpaper.sock"
fi
# Don't fail the service if env isn't available yet.
if [ -z "$sockPath" ]; then
echo "set-hyprpaper-wallpaper: missing XDG_RUNTIME_DIR/HYPRLAND_INSTANCE_SIGNATURE" >&2
exit 0
fi
for _ in {1..50}; do
if [ -S "$sockPath" ]; then
break
fi
${pkgs.coreutils}/bin/sleep 0.1
done
if [ ! -S "$sockPath" ]; then
echo "set-hyprpaper-wallpaper: hyprpaper socket not ready at $sockPath" >&2
exit 0
fi
if [ ! -d "${wallpaperDir}" ]; then
echo "set-hyprpaper-wallpaper: wallpaper directory missing: ${wallpaperDir}" >&2
exit 0
fi
wallpaper="$(${pkgs.findutils}/bin/find "${wallpaperDir}" -type f -regextype posix-extended -iregex '.*\.(png|jpe?g|webp)$' -print0 | ${pkgs.coreutils}/bin/shuf -z -n 1 | ${pkgs.coreutils}/bin/tr -d '\0')"
if [ -z "$wallpaper" ]; then
echo "set-hyprpaper-wallpaper: no wallpapers found in ${wallpaperDir}" >&2
exit 0
fi
# Apply to all current monitors.
mons=$(/run/current-system/sw/bin/hyprctl -j monitors 2>/dev/null | ${pkgs.jq}/bin/jq -r '.[].name' 2>/dev/null || true)
if [ -z "$mons" ]; then
# Fallback to parsing non-JSON output.
mons=$(/run/current-system/sw/bin/hyprctl monitors 2>/dev/null | ${pkgs.gnugrep}/bin/grep -oE '^Monitor [^ ]+' | ${pkgs.coreutils}/bin/cut -d' ' -f2 || true)
fi
for mon in $mons; do
# The socket file can exist before hyprpaper is actually ready to
# accept connections, so retry briefly.
for _ in {1..50}; do
if /run/current-system/sw/bin/hyprctl hyprpaper wallpaper "$mon,$wallpaper" >/dev/null 2>&1; then
break
fi
${pkgs.coreutils}/bin/sleep 0.1
done
done
exit 0
'';
hyprpaperConf = pkgs.writeText "hyprpaper.conf" ''
ipc = true
splash = false
'';
in {
Unit = {
Description = "Hyprpaper (managed by home-manager)";
PartOf = [ "hyprland-session.target" ];
After = [ "hyprland-session.target" ];
};
Service = {
ExecStartPre = waitForWayland;
ExecStart = "${pkgs.hyprpaper}/bin/hyprpaper -c ${hyprpaperConf}";
ExecStartPost = setWallpaper;
Restart = "on-failure";
RestartSec = 1;
};
Install = {
WantedBy = [ "hyprland-session.target" ];
};
};
xdg.desktopEntries.google-chrome-devtools = {
name = "Google Chrome (DevTools)";
genericName = "Web Browser";

View File

@@ -42,8 +42,10 @@ makeEnable config "myModules.xmonad" true {
enable = true;
display = "fill";
interval = "1h";
imageDirectory = "/var/lib/syncthing/sync/Wallpaper/";
imageDirectory = "/var/lib/syncthing/sync/Wallpaper";
};
# This service uses feh (X11), so don't run it in Wayland sessions.
systemd.user.services.random-background.Unit.ConditionEnvironment = "XDG_SESSION_TYPE=x11";
services.xsettingsd.enable = true;