227 lines
6.2 KiB
Nix
227 lines
6.2 KiB
Nix
{ config, pkgs, lib, ... }:
|
|
|
|
let
|
|
cfg = config.dataPro.wallpaper; # custom namespace
|
|
|
|
# Where we keep a runtime-editable config for the user.
|
|
runtimeConfDir = "${config.xdg.configHome}/wallpaper";
|
|
runtimeConfPath = "${runtimeConfDir}/wallpaper.conf";
|
|
|
|
rotateScript = pkgs.writeShellScript "wallpaper-rotate" ''
|
|
set -euo pipefail
|
|
|
|
export PATH=${lib.makeBinPath [
|
|
pkgs.coreutils
|
|
pkgs.findutils
|
|
pkgs.gnugrep
|
|
pkgs.gawk
|
|
pkgs.util-linux
|
|
pkgs.swww
|
|
]}
|
|
|
|
# Defaults (can be overridden by wallpaper.conf)
|
|
SOURCE_DIR="${cfg.sourceDir}"
|
|
TARGET_DIR="${cfg.targetDir}"
|
|
ROTATION_DIR="${cfg.rotationDir}"
|
|
TRANSITION_TYPE="fade"
|
|
TRANSITION_DURATION="2.5"
|
|
TRANSITION_FPS="60"
|
|
PICK_MODE="random" # random | sequential
|
|
LAST_FILE="${config.xdg.stateHome}/wallpaper/last.txt"
|
|
|
|
# Load user config if present (KEY=VALUE lines; '#' comments allowed)
|
|
if [ -f "${runtimeConfPath}" ]; then
|
|
# shellcheck disable=SC1090
|
|
. "${runtimeConfPath}"
|
|
fi
|
|
|
|
mkdir -p "$TARGET_DIR" "${config.xdg.stateHome}/wallpaper"
|
|
|
|
# Ensure swww-daemon is running
|
|
if ! pgrep -x swww-daemon >/dev/null 2>&1; then
|
|
swww-daemon >/dev/null 2>&1 &
|
|
sleep 0.3
|
|
fi
|
|
|
|
# Pick image
|
|
if [ ! -d "$ROTATION_DIR" ]; then
|
|
echo "Rotation directory does not exist: $ROTATION_DIR" >&2
|
|
exit 0
|
|
fi
|
|
|
|
# Build list once per run
|
|
mapfile -d '' -t imgs < <(
|
|
find "$ROTATION_DIR" -type f \
|
|
\( -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.png' -o -iname '*.webp' \) \
|
|
-print0
|
|
)
|
|
|
|
if [ "${#imgs[@]}" -eq 0 ]; then
|
|
echo "No images found in: $ROTATION_DIR" >&2
|
|
exit 0
|
|
fi
|
|
|
|
img=""
|
|
if [ "$PICK_MODE" = "sequential" ]; then
|
|
last=""
|
|
if [ -f "$LAST_FILE" ]; then
|
|
last="$(cat "$LAST_FILE" || true)"
|
|
fi
|
|
|
|
# Sort for stable order
|
|
IFS=$'\n' sorted=($(printf '%s\n' "${imgs[@]}" | sort))
|
|
unset IFS
|
|
|
|
# Find next after last
|
|
next=""
|
|
found_last=0
|
|
for f in "${sorted[@]}"; do
|
|
if [ "$found_last" -eq 1 ]; then
|
|
next="$f"
|
|
break
|
|
fi
|
|
if [ "$f" = "$last" ]; then
|
|
found_last=1
|
|
fi
|
|
done
|
|
if [ -z "$next" ]; then
|
|
next="${sorted[0]}"
|
|
fi
|
|
img="$next"
|
|
printf '%s' "$img" > "$LAST_FILE"
|
|
else
|
|
# random
|
|
img="$(printf '%s\0' "${imgs[@]}" | shuf -z -n 1 | tr -d '\0')"
|
|
fi
|
|
|
|
# Smooth transition wallpaper set
|
|
swww img "$img" \
|
|
--transition-type "$TRANSITION_TYPE" \
|
|
--transition-duration "$TRANSITION_DURATION" \
|
|
--transition-fps "$TRANSITION_FPS"
|
|
'';
|
|
in
|
|
{
|
|
options.dataPro.wallpaper = {
|
|
enable = lib.mkEnableOption "Hourly wallpaper rotation with swww (Hyprland/Wayland)";
|
|
|
|
# You asked to make this easy to change:
|
|
sourceDir = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "${config.home.homeDirectory}/nixos/files/wallpaper/picture";
|
|
description = "Folder containing wallpapers to rotate (source of truth).";
|
|
};
|
|
|
|
targetDir = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "${config.home.homeDirectory}/wallpaper";
|
|
description = "Folder in the user's home where wallpapers are copied to.";
|
|
};
|
|
|
|
rotationDir = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "${config.home.homeDirectory}/wallpaper/picture";
|
|
description = "Folder used by the rotator to pick wallpapers from (usually inside targetDir).";
|
|
};
|
|
};
|
|
|
|
config = lib.mkIf cfg.enable {
|
|
home.packages = [
|
|
pkgs.swww
|
|
pkgs.coreutils
|
|
pkgs.findutils
|
|
pkgs.gnugrep
|
|
pkgs.gawk
|
|
pkgs.util-linux
|
|
];
|
|
|
|
# Copy wallpapers from sourceDir into rotationDir (real copy) at activation.
|
|
home.activation.wallpaperCopy = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
|
|
set -euo pipefail
|
|
mkdir -p "${cfg.targetDir}" "${cfg.rotationDir}"
|
|
|
|
if [ -d "${cfg.sourceDir}" ]; then
|
|
# Copy source into rotationDir (contents only).
|
|
cp -a "${cfg.sourceDir}/." "${cfg.rotationDir}/"
|
|
fi
|
|
'';
|
|
|
|
# Install a runtime-editable config into ~/.config/wallpaper/wallpaper.conf
|
|
# First-time copy from repo if present; then never overwrite if user edited it.
|
|
home.activation.wallpaperConf = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
|
|
set -euo pipefail
|
|
mkdir -p "${runtimeConfDir}"
|
|
|
|
if [ ! -f "${runtimeConfPath}" ]; then
|
|
if [ -f "${config.home.homeDirectory}/nixos/files/conf/wallpaper/wallpaper.conf" ]; then
|
|
cp -a "${config.home.homeDirectory}/nixos/files/conf/wallpaper/wallpaper.conf" "${runtimeConfPath}"
|
|
else
|
|
cat > "${runtimeConfPath}" <<'EOF'
|
|
# wallpaper.conf — runtime settings for the wallpaper rotator (swww)
|
|
# Lines are KEY=VALUE. '#' starts a comment.
|
|
|
|
# Folder to copy wallpapers from (source of truth)
|
|
#SOURCE_DIR="$HOME/nixos/files/wallpaper/picture"
|
|
|
|
# Where wallpapers are copied to (a folder in your home)
|
|
#TARGET_DIR="$HOME/wallpaper"
|
|
|
|
# Folder used for rotation (where images are selected from)
|
|
#ROTATION_DIR="$HOME/wallpaper/picture"
|
|
|
|
# random | sequential
|
|
#PICK_MODE="random"
|
|
|
|
# swww transition settings
|
|
#TRANSITION_TYPE="fade"
|
|
#TRANSITION_DURATION="2.5"
|
|
#TRANSITION_FPS="60"
|
|
EOF
|
|
fi
|
|
fi
|
|
'';
|
|
|
|
# Start swww daemon on graphical session start
|
|
systemd.user.services.swww-daemon = {
|
|
Unit = {
|
|
Description = "swww wallpaper daemon";
|
|
After = [ "graphical-session.target" ];
|
|
PartOf = [ "graphical-session.target" ];
|
|
};
|
|
Service = {
|
|
ExecStart = "${pkgs.swww}/bin/swww-daemon";
|
|
Restart = "on-failure";
|
|
};
|
|
Install = {
|
|
WantedBy = [ "graphical-session.target" ];
|
|
};
|
|
};
|
|
|
|
# Rotate wallpaper hourly
|
|
systemd.user.services.wallpaper-rotate = {
|
|
Unit = {
|
|
Description = "Rotate wallpaper (hourly)";
|
|
After = [ "swww-daemon.service" ];
|
|
};
|
|
Service = {
|
|
Type = "oneshot";
|
|
ExecStart = "${rotateScript}";
|
|
};
|
|
};
|
|
|
|
systemd.user.timers.wallpaper-rotate = {
|
|
Unit = {
|
|
Description = "Hourly wallpaper rotation timer";
|
|
};
|
|
Timer = {
|
|
OnBootSec = "2m";
|
|
OnUnitActiveSec = "1h";
|
|
Unit = "wallpaper-rotate.service";
|
|
};
|
|
Install = {
|
|
WantedBy = [ "timers.target" ];
|
|
};
|
|
};
|
|
};
|
|
}
|