{ config, lib, pkgs, flakeRoot, ... }: let # Repo inputs (same as you had) repoWallpaperDir = flakeRoot + "/assets/conf/desktop/wallpaper"; # Where we sync assets to (writable) userRelRoot = "nixos_conf/wallpaperstuff"; userAbsRoot = "${config.home.homeDirectory}/${userRelRoot}"; picturesDir = "${userAbsRoot}/pictures"; # Sync everything in repoWallpaperDir to ~/nixos_conf/wallpaperstuff repoWallpapersOnly = lib.cleanSourceWith { src = repoWallpaperDir; filter = path: type: true; }; # Workspace→wallpaper listener script wsScriptRel = "hypr/scripts/hyprpaper-workspace-1to9.sh"; in { home.packages = [ pkgs.hyprpaper pkgs.socat pkgs.jq ]; # 1) Sync your wallpaper assets + scripts into a writable location home.file."${userRelRoot}" = { source = repoWallpapersOnly; recursive = true; }; # 2) hyprpaper config (read-only is fine; hyprpaper doesn't need to write it) # Location per wiki: ~/.config/hypr/hyprpaper.conf :contentReference[oaicite:1]{index=1} xdg.configFile."hypr/hyprpaper.conf".text = '' # Managed by Home Manager ipc = true splash = false # Fallback wallpaper (only used for monitors that never got a specific one yet) wallpaper { monitor = path = ${picturesDir} fit_mode = fill timeout = 3600 } ''; # 3) Install the listener script at ~/.config/hypr/scripts/... xdg.configFile."${wsScriptRel}".executable = true; xdg.configFile."${wsScriptRel}".text = '' #!/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 (fill ≈ stretch) :contentReference[oaicite:2]{index=2} # Track focused monitor (workspace events do not include monitor name) :contentReference[oaicite:3]{index=3} FOCUSED_MON="" pick_wall_for_ws() { local ws="$1" # Prefer exact matches like 1.png / 1.jpg / 1.webp / 1.jxl etc. # Pick first match; if none, return empty. local f f="$(ls -1 "${PICTURES_DIR}/${ws}."* 2>/dev/null | head -n 1 || true)" echo "$f" } apply_wallpaper() { local mon="$1" local ws="$2" local file file="$(pick_wall_for_ws "$ws")" [[ -n "$file" ]] || return 0 # hyprpaper IPC via hyprctl: hyprctl hyprpaper wallpaper '[mon], [path], [fit_mode]' :contentReference[oaicite:4]{index=4} # Note: wiki shows commas + optional fit_mode; keep it explicit. hyprctl hyprpaper wallpaper "${mon}, ${file}, ${FIT_MODE}" >/dev/null } # Initial state # focused monitor from hyprctl monitors FOCUSED_MON="$(hyprctl -j monitors | jq -r '.[] | select(.focused==true) | .name' | head -n 1)" # workspace name (may be "1" or "1:something") CUR_WS="$(hyprctl -j activeworkspace | jq -r '.name' | head -n 1)" CUR_WS="''${CUR_WS%%:*}" [[ -n "$FOCUSED_MON" && -n "$CUR_WS" ]] && apply_wallpaper "$FOCUSED_MON" "$CUR_WS" handle() { case "$1" in focusedmon* ) # format: focusedmon>>MONNAME,WORKSPACENAME :contentReference[oaicite:5]{index=5} local payload="''${1#*>>}" FOCUSED_MON="''${payload%%,*}" ;; workspace* ) # format: workspace>>WORKSPACENAME :contentReference[oaicite:6]{index=6} local ws="''${1#*>>}" ws="''${ws%%:*}" ws="''${ws%% *}" # trim trailing space if present [[ -n "$FOCUSED_MON" && -n "$ws" ]] && apply_wallpaper "$FOCUSED_MON" "$ws" ;; esac } # Listen to socket2 events via socat (wiki example) :contentReference[oaicite:7]{index=7} socat -U - UNIX-CONNECT:"$SOCK" | while read -r line; do handle "$line" || true done ''; # 4) Start hyprpaper + the workspace listener as user 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-workspace-wallpapers = { Unit = { Description = "Hyprpaper workspace wallpapers (socket2 listener)"; PartOf = [ "graphical-session.target" ]; After = [ "graphical-session.target" "hyprpaper.service" ]; }; Service = { ExecStart = "${pkgs.bash}/bin/bash ${config.xdg.configHome}/${wsScriptRel} ${picturesDir}"; Restart = "on-failure"; RestartSec = 1; }; Install = { WantedBy = [ "graphical-session.target" ]; }; }; }