wallpaper

This commit is contained in:
2026-08-18 04:20:59 +09:00
parent c7627fa1b0
commit 94048ef8d5
9 changed files with 0 additions and 495 deletions
-1
View File
@@ -104,7 +104,6 @@
"interface.cli" "interface.cli"
"interface.labwc" "interface.labwc"
"interface.niri" "interface.niri"
"interface.wallpaperengine"
"networking.tailscale-client" "networking.tailscale-client"
"platform.intel-nvidia-desktop" "platform.intel-nvidia-desktop"
"security.secrets" "security.secrets"
@@ -1,167 +0,0 @@
# shellcheck shell=bash
set -o errexit -o nounset -o pipefail
playlist_file="$1"
default_id="$2"
configuration_id="$3"
shift 3
state_dir="${XDG_RUNTIME_DIR:?}/linux-wallpaperengine"
state_file="$state_dir/current"
usage() {
printf '%s\n' \
'Usage: wallpaperengine-wallpaper COMMAND [ID]' \
'' \
'Commands:' \
' select ID Select a declaratively configured ID for this session' \
' next Select the next configured ID' \
' previous Select the previous configured ID' \
' list List configured IDs and mark the selected one' \
' current Print the selected ID' \
' restart Restart the selected wallpaper' \
' stop Stop Wallpaper Engine for this session'
}
load_playlist() {
mapfile -t wallpaper_ids < <(awk '/^[0-9]+$/ && !seen[$0]++' "$playlist_file")
if [ "${#wallpaper_ids[@]}" -eq 0 ]; then
echo "wallpaperengine-wallpaper: no wallpaper IDs are configured in settings.nix" >&2
exit 1
fi
}
contains_id() {
local candidate="$1"
local id
for id in "${wallpaper_ids[@]}"; do
[ "$id" = "$candidate" ] && return 0
done
return 1
}
current_id() {
local saved_configuration=""
local saved_id=""
local -a saved_state=()
if [ -s "$state_file" ]; then
mapfile -t saved_state <"$state_file"
saved_configuration="${saved_state[0]:-}"
saved_id="${saved_state[1]:-}"
fi
if [ "$saved_configuration" = "$configuration_id" ] && contains_id "$saved_id"; then
printf '%s\n' "$saved_id"
else
printf '%s\n' "$default_id"
fi
}
select_id() {
local id="$1"
if ! contains_id "$id"; then
echo "wallpaperengine-wallpaper: ID is not declared in settings.nix: $id" >&2
exit 2
fi
mkdir -p "$state_dir"
printf '%s\n%s\n' "$configuration_id" "$id" >"$state_file"
systemctl --user restart linux-wallpaperengine.service
}
cycle() {
local step="$1"
local current
local index=0
local next_index
current=$(current_id)
for i in "${!wallpaper_ids[@]}"; do
if [ "${wallpaper_ids[$i]}" = "$current" ]; then
index="$i"
break
fi
done
next_index=$(((index + step + ${#wallpaper_ids[@]}) % ${#wallpaper_ids[@]}))
select_id "${wallpaper_ids[$next_index]}"
}
load_playlist
command="${1:-}"
if [ -z "$command" ]; then
usage
exit 2
fi
shift
case "$command" in
select)
[ "$#" -eq 1 ] || {
usage >&2
exit 2
}
select_id "$1"
;;
next)
[ "$#" -eq 0 ] || {
usage >&2
exit 2
}
cycle 1
;;
previous)
[ "$#" -eq 0 ] || {
usage >&2
exit 2
}
cycle -1
;;
list)
[ "$#" -eq 0 ] || {
usage >&2
exit 2
}
current=$(current_id)
for id in "${wallpaper_ids[@]}"; do
if [ "$id" = "$current" ]; then
printf '* %s\n' "$id"
else
printf ' %s\n' "$id"
fi
done
;;
current)
[ "$#" -eq 0 ] || {
usage >&2
exit 2
}
current_id
;;
restart)
[ "$#" -eq 0 ] || {
usage >&2
exit 2
}
systemctl --user restart linux-wallpaperengine.service
;;
stop)
[ "$#" -eq 0 ] || {
usage >&2
exit 2
}
systemctl --user stop linux-wallpaperengine.service
;;
help | -h | --help)
usage
;;
*)
usage >&2
exit 2
;;
esac
@@ -1,57 +0,0 @@
# shellcheck shell=bash
set -o errexit -o nounset -o pipefail
playlist_file="$1"
default_id="$2"
configuration_id="$3"
assets_dir="$4"
workshop_dir="$5"
scaling="$6"
shift 6
state_file="${XDG_RUNTIME_DIR:?}/linux-wallpaperengine/current"
wallpaper_id="$default_id"
saved_configuration=""
saved_id=""
saved_state=()
outputs=()
if [ -s "$state_file" ]; then
mapfile -t saved_state <"$state_file"
saved_configuration="${saved_state[0]:-}"
saved_id="${saved_state[1]:-}"
if [ "$saved_configuration" = "$configuration_id" ] &&
awk -v id="$saved_id" '$0 == id { found = 1 } END { exit !found }' "$playlist_file"; then
wallpaper_id="$saved_id"
fi
fi
wallpaper_path="$workshop_dir/$wallpaper_id"
if [ ! -d "$wallpaper_path" ]; then
echo "linux-wallpaperengine: missing declared wallpaper: $wallpaper_path" >&2
exit 1
fi
if [ ! -d "$assets_dir" ]; then
echo "linux-wallpaperengine: missing Wallpaper Engine assets: $assets_dir" >&2
exit 1
fi
mapfile -t outputs < <(wlr-randr --json | jq -r '.[] | select(.enabled == true) | .name')
if [ "${#outputs[@]}" -eq 0 ]; then
echo "linux-wallpaperengine: no enabled Wayland outputs were detected" >&2
exit 1
fi
engine_args=("$@" --assets-dir "$assets_dir")
for output in "${outputs[@]}"; do
engine_args+=(
--screen-root "$output"
--bg "$wallpaper_path"
--scaling "$scaling"
)
done
exec linux-wallpaperengine "${engine_args[@]}"
@@ -1,229 +0,0 @@
{
config,
lib,
pkgs,
...
}:
let
settings = import ../settings.nix;
inherit (settings)
assetsDirectory
fps
mute
scaling
selectedWallpaperId
switchIntervalSeconds
wallpaperIds
workshopDirectory
;
resolveHomePath =
path:
if lib.hasPrefix "~/" path then
"${config.home.homeDirectory}/${lib.removePrefix "~/" path}"
else if lib.hasPrefix "/" path then
path
else
"${config.home.homeDirectory}/${path}";
hasWallpapers = wallpaperIds != [ ];
defaultWallpaperId =
if selectedWallpaperId != null then
selectedWallpaperId
else if hasWallpapers then
lib.head wallpaperIds
else
"";
configurationId = builtins.hashString "sha256" (builtins.toJSON settings);
resolvedAssetsDirectory = resolveHomePath assetsDirectory;
resolvedWorkshopDirectory = resolveHomePath workshopDirectory;
playlist = pkgs.writeText "linux-wallpaperengine-playlist" (
lib.concatMapStringsSep "\n" (id: id) wallpaperIds + "\n"
);
engineArguments = lib.optional mute "--silent" ++ [
"--fps"
(toString fps)
];
controller = pkgs.writeShellApplication {
name = "wallpaperengine-wallpaper";
runtimeInputs = [
pkgs.coreutils
pkgs.gawk
pkgs.systemd
];
text = ''
exec ${lib.getExe pkgs.bash} ${./controller.sh} \
${lib.escapeShellArg playlist} \
${lib.escapeShellArg defaultWallpaperId} \
${lib.escapeShellArg configurationId} \
"$@"
'';
};
mkVicinaeScript =
{
name,
title,
description,
command,
mode ? "compact",
message ? null,
}:
{
name = "vicinae/scripts/wallpaper-engine/${name}";
value = {
executable = true;
text = ''
#!${lib.getExe pkgs.bash}
# @vicinae.schemaVersion 1
# @vicinae.title ${title}
# @vicinae.description ${description}
# @vicinae.mode ${mode}
# @vicinae.icon 🖼️
${lib.getExe controller} ${lib.escapeShellArg command}
${lib.optionalString (message != null) "printf '%s\\n' ${lib.escapeShellArg message}"}
'';
};
};
launcher = pkgs.writeShellApplication {
name = "linux-wallpaperengine-launcher";
runtimeInputs = [
pkgs.coreutils
pkgs.gawk
pkgs.jq
pkgs.linux-wallpaperengine
pkgs.wlr-randr
];
text = ''
exec ${lib.getExe pkgs.bash} ${./launcher.sh} \
${lib.escapeShellArg playlist} \
${lib.escapeShellArg defaultWallpaperId} \
${lib.escapeShellArg configurationId} \
${lib.escapeShellArg resolvedAssetsDirectory} \
${lib.escapeShellArg resolvedWorkshopDirectory} \
${lib.escapeShellArg scaling} \
${lib.escapeShellArgs engineArguments}
'';
};
in
assert lib.assertMsg (lib.all (
id: builtins.isString id && builtins.match "[0-9]+" id != null
) wallpaperIds) "linux-wallpaperengine: wallpaperIds must contain only numeric strings";
assert lib.assertMsg (
lib.unique wallpaperIds == wallpaperIds
) "linux-wallpaperengine: wallpaperIds must not contain duplicates";
assert lib.assertMsg (
selectedWallpaperId == null || builtins.elem selectedWallpaperId wallpaperIds
) "linux-wallpaperengine: selectedWallpaperId must be null or a member of wallpaperIds";
assert lib.assertMsg (
switchIntervalSeconds == null || (builtins.isInt switchIntervalSeconds && switchIntervalSeconds > 0)
) "linux-wallpaperengine: switchIntervalSeconds must be null or a positive integer";
assert lib.assertMsg (
builtins.isInt fps && fps > 0
) "linux-wallpaperengine: fps must be a positive integer";
assert lib.assertMsg (
builtins.isString assetsDirectory && assetsDirectory != ""
) "linux-wallpaperengine: assetsDirectory must be a non-empty string";
assert lib.assertMsg (
builtins.isString workshopDirectory && workshopDirectory != ""
) "linux-wallpaperengine: workshopDirectory must be a non-empty string";
assert lib.assertMsg (builtins.elem scaling [
"default"
"fill"
"fit"
"stretch"
]) "linux-wallpaperengine: scaling must be default, fill, fit, or stretch";
{
home.packages = [
controller
pkgs.linux-wallpaperengine
];
xdg.dataFile = builtins.listToAttrs [
(mkVicinaeScript {
name = "reload";
title = "Reload Wallpaper Engine";
description = "Restart the active Wallpaper Engine background";
command = "restart";
message = "Wallpaper Engine reloaded";
})
(mkVicinaeScript {
name = "next";
title = "Next Wallpaper Engine Wallpaper";
description = "Switch to the next configured Wallpaper Engine background";
command = "next";
message = "Switched to the next Wallpaper Engine wallpaper";
})
(mkVicinaeScript {
name = "previous";
title = "Previous Wallpaper Engine Wallpaper";
description = "Switch to the previous configured Wallpaper Engine background";
command = "previous";
message = "Switched to the previous Wallpaper Engine wallpaper";
})
(mkVicinaeScript {
name = "list";
title = "List Wallpaper Engine Wallpapers";
description = "Show the configured Wallpaper Engine backgrounds";
command = "list";
mode = "fullOutput";
})
(mkVicinaeScript {
name = "current";
title = "Current Wallpaper Engine Wallpaper";
description = "Show the active Wallpaper Engine background";
command = "current";
})
(mkVicinaeScript {
name = "stop";
title = "Stop Wallpaper Engine";
description = "Stop Wallpaper Engine for this session";
command = "stop";
message = "Wallpaper Engine stopped";
})
];
systemd.user.services = lib.optionalAttrs hasWallpapers {
linux-wallpaperengine = {
Unit = {
Description = "Linux Wallpaper Engine";
After = [ "graphical-session.target" ];
PartOf = [ "graphical-session.target" ];
};
Service = {
ExecStart = lib.getExe launcher;
Restart = "on-abnormal";
};
Install.WantedBy = [ "graphical-session.target" ];
};
linux-wallpaperengine-switch = {
Unit.Description = "Switch Linux Wallpaper Engine wallpaper";
Service = {
Type = "oneshot";
ExecStart = "${lib.getExe controller} next";
};
};
};
systemd.user.timers =
lib.optionalAttrs
(hasWallpapers && builtins.length wallpaperIds > 1 && switchIntervalSeconds != null)
{
linux-wallpaperengine-switch = {
Unit = {
Description = "Periodically switch Linux Wallpaper Engine wallpaper";
PartOf = [ "graphical-session.target" ];
};
Timer = {
OnActiveSec = "${toString switchIntervalSeconds}s";
OnUnitActiveSec = "${toString switchIntervalSeconds}s";
Unit = "linux-wallpaperengine-switch.service";
};
Install.WantedBy = [ "graphical-session.target" ];
};
};
}
@@ -1,3 +0,0 @@
{
description = "Wallpaper Engine backgrounds for Linux";
}
@@ -1,23 +0,0 @@
{
assetsDirectory = "~/.local/share/Steam/steamapps/common/wallpaper_engine/assets";
workshopDirectory = "~/.local/share/Steam/steamapps/workshop/content/431960";
wallpaperIds = [
"2833810156"
"2834355367"
"2836628501"
"2845095254"
"2859848175"
"2861661119"
"2982896307"
];
# null selects the first ID above.
selectedWallpaperId = null;
# Set a number such as 300 to rotate through multiple IDs.
switchIntervalSeconds = 300;
fps = 30;
mute = true;
scaling = "fill";
}
-5
View File
@@ -30,7 +30,6 @@ required on every supported host.
| `interface.linux-desktop` | NixOS with Home Manager | | `interface.linux-desktop` | NixOS with Home Manager |
| `interface.labwc` | NixOS with Home Manager | | `interface.labwc` | NixOS with Home Manager |
| `interface.niri` | NixOS with Home Manager | | `interface.niri` | NixOS with Home Manager |
| `interface.wallpaperengine` | NixOS with Home Manager |
| `platform.nixos` | NixOS | | `platform.nixos` | NixOS |
| `platform.desktop` | Physical NixOS desktop | | `platform.desktop` | Physical NixOS desktop |
| `platform.intel-nvidia-desktop` | Intel/NVIDIA physical NixOS desktop | | `platform.intel-nvidia-desktop` | Intel/NVIDIA physical NixOS desktop |
@@ -59,10 +58,6 @@ selects labwc. A daily-use macOS development machine can combine
`interface.macos`, `workload.development`, and `workload.personal`. Hardware `interface.macos`, `workload.development`, and `workload.personal`. Hardware
support does not implicitly select an interface or workload. support does not implicitly select an interface or workload.
`interface.wallpaperengine` is an opt-in Linux desktop appearance profile. It
enables Wallpaper Engine and disables Noctalia's wallpaper surface, so hosts
without this profile retain Noctalia's configured wallpaper.
`workload.personal` provides Pear Desktop on both NixOS and macOS. Home Manager `workload.personal` provides Pear Desktop on both NixOS and macOS. Home Manager
enables performance improvements, synced lyrics, tracker blocking, the album enables performance improvements, synced lyrics, tracker blocking, the album
color theme, and custom output-device selection while preserving user-owned color theme, and custom output-device selection while preserving user-owned
@@ -1,3 +0,0 @@
{
programs.noctalia.settings.wallpaper.enabled = false;
}
@@ -1,7 +0,0 @@
{
description = "Wallpaper Engine backgrounds for Linux desktop sessions";
includes = [
"applications.linux-wallpaperengine"
];
}