{ config, pkgs, lib, flakeRoot, ... }: let # Repo folder that gets copied to ~/nixos_conf/wallpaperstuff repoWallpaperDir = flakeRoot + "/assets/conf/desktop/wallpaper"; userRelRoot = "nixos_conf/wallpaperstuff"; userAbsRoot = "${config.home.homeDirectory}/${userRelRoot}"; # Your actual layout: # ~/nixos_conf/wallpaperstuff/pictures/wallpaper{1..9}.jpg picturesDir = "${userAbsRoot}/pictures"; stateDir = "${userAbsRoot}/current"; symlinkPath = "${stateDir}/workspace.jpg"; scriptRel = "hypr/scripts/wpaperd-workspace-1to9.sh"; wpaperdConfRel = "wpaperd/config.toml"; in { home.packages = [ pkgs.wpaperd pkgs.socat pkgs.jq ]; # Copy wallpapers from repo → ~/nixos_conf/wallpaperstuff (includes pictures/) home.file."${userRelRoot}" = { source = repoWallpaperDir; recursive = true; }; # Ensure wpaperd config points to the global symlink (not per-monitor, not rotating) xdg.configFile."${wpaperdConfRel}".text = '' [default] mode = "stretch" [any] path = "${symlinkPath}" ''; # Script: global wallpaper per workspace (focused workspace), via symlink + reload-wallpaper xdg.configFile."${scriptRel}" = { executable = true; text = '' #!/usr/bin/env bash set -euo pipefail log() { echo "[wpaperd-ws] $*" >&2; } PICTURES_DIR="${picturesDir}" STATE_DIR="${stateDir}" SYMLINK="${symlinkPath}" XDG_CONFIG_HOME="''${XDG_CONFIG_HOME:-$HOME/.config}" WPAPERD_DIR="$XDG_CONFIG_HOME/wpaperd" CONF="$WPAPERD_DIR/config.toml" : "''${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" mkdir -p "$STATE_DIR" "$WPAPERD_DIR" # Wait for Hyprland socket so we don't exit too early for i in $(seq 1 120); do [[ -S "$SOCK" ]] && break sleep 0.1 done [[ -S "$SOCK" ]] || { log "Hyprland socket not found: $SOCK"; exit 1; } ws_num() { local w="''${1%%:*}" [[ "$w" =~ ^[0-9]+$ ]] || return 1 printf '%s\n' "$w" } img_for_ws() { local n="$1" case "$n" in 1|2|3|4|5|6|7|8|9) printf '%s/wallpaper%s.jpg\n' "$PICTURES_DIR" "$n" ;; *) return 1 ;; esac } ensure_config() { # keep config stable and always pointing to the symlink cat >"$CONF" </dev/null 2>&1 || true } apply_workspace() { local ws_raw="$1" local n img n="$(ws_num "$ws_raw")" || { log "Ignoring non-numeric workspace: $ws_raw"; return 0; } img="$(img_for_ws "$n")" || return 0 if [[ ! -f "$img" ]]; then log "Missing image for ws=$n: $img" return 0 fi # If already set, skip if [[ -L "$SYMLINK" ]] && [[ "$(readlink -f "$SYMLINK")" == "$(readlink -f "$img")" ]]; then return 0 fi ln -sf "$img" "$SYMLINK" log "Workspace $n -> $img" ensure_config reload_wallpaper } apply_initial() { local ws ws="$(${pkgs.hyprland}/bin/hyprctl -j monitors | ${pkgs.jq}/bin/jq -r '.[] | select(.focused==true) | .activeWorkspace.name' | head -n1)" if [[ -n "$ws" && "$ws" != "null" ]]; then apply_workspace "$ws" else log "Could not determine initial focused workspace" fi } handle_line() { case "$1" in workspace\>\>*) apply_workspace "''${1#workspace>>}" ;; workspacev2\>\>*) local payload="''${1#workspacev2>>}" apply_workspace "''${payload#*,}" ;; focusedmon\>\>*) local payload="''${1#focusedmon>>}" local ws="''${payload#*,}" apply_workspace "$ws" ;; esac } ensure_config apply_initial log "Listening on $SOCK" exec ${pkgs.socat}/bin/socat -U - "UNIX-CONNECT:$SOCK" \ | while IFS= read -r line; do handle_line "$line" || true done ''; }; # wpaperd daemon systemd.user.services.wpaperd = { Unit = { Description = "wpaperd wallpaper daemon"; After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; }; Service = { ExecStart = "${pkgs.wpaperd}/bin/wpaperd"; Restart = "on-failure"; RestartSec = 1; }; Install.WantedBy = [ "graphical-session.target" ]; }; # listener systemd.user.services.wpaperd-workspace-wallpaper = { Unit = { Description = "Global wallpaper per workspace (1..9)"; After = [ "graphical-session.target" "wpaperd.service" ]; PartOf = [ "graphical-session.target" ]; }; Service = { ExecStart = "${pkgs.bash}/bin/bash ${config.xdg.configHome}/${scriptRel}"; Restart = "on-failure"; RestartSec = 1; }; Install.WantedBy = [ "graphical-session.target" ]; }; }