{ config, lib, pkgs, flakeRoot, ... }: let # Where your numbered wallpapers live (1.*, 2.*, ... 9.*) userRelRoot = "nixos_conf/wallpaperstuff"; userAbsRoot = "${config.home.homeDirectory}/${userRelRoot}"; picturesDir = "${userAbsRoot}/pictures"; # (Optional) still sync your repo wallpapers/scripts into ~/nixos_conf/wallpaperstuff repoWallpaperDir = flakeRoot + "/assets/conf/desktop/wallpaper"; repoWallpapersOnly = lib.cleanSourceWith { src = repoWallpaperDir; filter = path: type: true; }; daemonRel = "hypr/scripts/hyprpaper-ws-daemon.sh"; setRel = "hypr/scripts/set-wallpaper.sh"; in { home.packages = [ pkgs.hyprpaper pkgs.socat pkgs.jq pkgs.findutils pkgs.coreutils pkgs.gnused pkgs.gawk ]; # Keep your existing "sync wallpapers into a writable dir" pattern home.file."${userRelRoot}" = { source = repoWallpapersOnly; recursive = true; }; # Hyprpaper config (hyprpaper reads this; it does NOT need to write it) # `ipc = true` enables `hyprctl hyprpaper ...` commands. :contentReference[oaicite:0]{index=0} xdg.configFile."hypr/hyprpaper.conf".text = lib.mkForce '' ipc = true splash = false ''; xdg.configFile."hypr/hyprpaper.conf".backup = lib.mkForce false; # Workspace wallpaper daemon: listens to socket2, applies w-=... mapping # Uses workspacev2 to get numeric workspace id. :contentReference[oaicite:1]{index=1} xdg.configFile."${daemonRel}" = { executable = true; text = lib.mkForce '' #!/usr/bin/env bash set -euo pipefail : "''${XDG_RUNTIME_DIR:?XDG_RUNTIME_DIR not set}" : "''${HYPRLAND_INSTANCE_SIGNATURE:?HYPRLAND_INSTANCE_SIGNATURE not set}" SOCK="''${XDG_RUNTIME_DIR}/hypr/''${HYPRLAND_INSTANCE_SIGNATURE}/.socket2.sock" [[ -S "$SOCK" ]] || { echo "Hyprland socket not found: $SOCK" >&2; exit 1; } PICTURES_DIR="''${1:-${picturesDir}}" FIT_MODE="fill" # hyprpaper fit_mode: contain|cover|tile|fill :contentReference[oaicite:2]{index=2} HYPR_DIR="''${XDG_CONFIG_HOME:-$HOME/.config}/hypr" MAP_ROOT="''${HYPR_DIR}/hyprpaper/config" focused_monitor() { hyprctl -j monitors | jq -r '.[] | select(.focused==true) | .name' | head -n 1 } map_file_for_monitor() { local mon="''${1}" echo "''${MAP_ROOT}/''${mon}/defaults.conf" } ensure_map_file() { local mon="''${1}" local f f="$(map_file_for_monitor "''${mon}")" mkdir -p "$(dirname "''${f}")" if [[ ! -f "''${f}" ]]; then # Seed with 1..9 from picturesDir if present, else empty entries { for i in 1 2 3 4 5 6 7 8 9; do seed="$(ls -1 "''${PICTURES_DIR}/''${i}."* 2>/dev/null | head -n 1 || true)" echo "w-''${i}= ''${seed}" done } > "''${f}" fi echo "''${f}" } get_wall_for_ws() { local mon="''${1}" local wsid="''${2}" local f key val f="$(ensure_map_file "''${mon}")" key="w-''${wsid}" # accept "w-1=/path" or "w-1= /path" val="$(awk -F= -v k="''${key}" '$1==k {sub(/^[[:space:]]+/, "", $2); print $2; exit}' "''${f}" || true)" echo "''${val}" } apply_wallpaper() { local mon="''${1}" local wsid="''${2}" local file file="$(get_wall_for_ws "''${mon}" "''${wsid}")" [[ -n "''${file}" ]] || return 0 [[ -f "''${file}" ]] || return 0 # Apply via IPC # hyprpaper “wallpaper { monitor path fit_mode }” model is per monitor. :contentReference[oaicite:3]{index=3} hyprctl hyprpaper wallpaper "''${mon}, ''${file}, ''${FIT_MODE}" >/dev/null } # Initial apply on startup mon="$(focused_monitor || true)" wsid="$(hyprctl -j activeworkspace | jq -r '.id' | head -n 1 || true)" [[ -n "''${mon}" && -n "''${wsid}" ]] && apply_wallpaper "''${mon}" "''${wsid}" handle() { local line="''${1}" case "''${line}" in workspacev2* ) # workspacev2>>ID,NAME :contentReference[oaicite:4]{index=4} local payload wsid payload="''${line#*>>}" wsid="''${payload%%,*}" mon="$(focused_monitor || true)" [[ -n "''${mon}" && -n "''${wsid}" ]] && apply_wallpaper "''${mon}" "''${wsid}" ;; focusedmon* ) # focusedmon>>MON,WORKSPACENAME :contentReference[oaicite:5]{index=5} # When monitor focus changes, re-apply for the active workspace id. mon="$(focused_monitor || true)" wsid="$(hyprctl -j activeworkspace | jq -r '.id' | head -n 1 || true)" [[ -n "''${mon}" && -n "''${wsid}" ]] && apply_wallpaper "''${mon}" "''${wsid}" ;; esac } socat -U - UNIX-CONNECT:"''${SOCK}" | while read -r line; do handle "''${line}" || true done ''; backup = lib.mkForce false; }; # CLI setter in the style of your inspiration script. # Usage: set-wallpaper.sh [wallpaper] xdg.configFile."${setRel}" = { executable = true; text = lib.mkForce '' #!/usr/bin/env bash set -euo pipefail HYPR_DIR="''${XDG_CONFIG_HOME:-$HOME/.config}/hypr" MAP_ROOT="''${HYPR_DIR}/hyprpaper/config" usage() { echo "Usage: set-wallpaper.sh [wallpaper_path]" } wsid="''${1:-}" mon="''${2:-}" wp="''${3:-}" [[ -n "''${wsid}" ]] || { usage; exit 1; } [[ -n "''${mon}" ]] || { usage; exit 1; } cfg="''${MAP_ROOT}/''${mon}/defaults.conf" mkdir -p "$(dirname "''${cfg}")" [[ -f "''${cfg}" ]] || touch "''${cfg}" if [[ -z "''${wp}" ]]; then # Random pick from your defaults folder if you want; adjust path if needed: wp="$(find "$HOME/.config/wallpapers/defaults" -type f 2>/dev/null | shuf -n 1 || true)" [[ -n "''${wp}" ]] || { echo "No wallpaper found (random). Provide a path as arg 3."; exit 1; } fi # Ensure key exists; if not, append it key="w-''${wsid}" if ! grep -q "^''${key}=" "''${cfg}"; then echo "''${key}=" >> "''${cfg}" fi # Set mapping ${pkgs.gnused}/bin/sed -i "s|^''${key}=.*|''${key}= ''${wp}|g" "''${cfg}" # If this monitor is currently showing that workspace id, apply immediately curws="$(hyprctl -j monitors | jq -r --arg m "''${mon}" '.[] | select(.name==$m) | .activeWorkspace.id' | head -n 1 || true)" if [[ "''${curws}" == "''${wsid}" ]]; then hyprctl hyprpaper wallpaper "''${mon}, ''${wp}, fill" >/dev/null fi ''; backup = lib.mkForce false; }; # Services systemd.user.services.hyprpaper = { Unit = { Description = "hyprpaper wallpaper daemon"; PartOf = [ "graphical-session.target" ]; After = [ "graphical-session.target" ]; }; Service = { ExecStart = "${pkgs.hyprpaper}/bin/hyprpaper"; Restart = "on-failure"; RestartSec = 1; }; Install = { WantedBy = [ "graphical-session.target" ]; }; }; systemd.user.services.hyprpaper-ws-daemon = { Unit = { Description = "Workspace->wallpaper mapping daemon (hyprpaper + socket2)"; PartOf = [ "graphical-session.target" ]; After = [ "graphical-session.target" "hyprpaper.service" ]; }; Service = { ExecStart = "${pkgs.bash}/bin/bash ${config.xdg.configHome}/${daemonRel} ${picturesDir}"; Restart = "on-failure"; RestartSec = 1; }; Install = { WantedBy = [ "graphical-session.target" ]; }; }; }