diff --git a/dotfiles/config/hypr/hyprland.lua b/dotfiles/config/hypr/hyprland.lua index fd992b98..fa6663c5 100644 --- a/dotfiles/config/hypr/hyprland.lua +++ b/dotfiles/config/hypr/hyprland.lua @@ -2092,6 +2092,7 @@ bind(hyper .. " + backslash", exec("/home/imalison/dotfiles/dotfiles/lib/functio bind(hyper .. " + SHIFT + backslash", workspacehistory("debug")) bind(hyper .. " + O", exec("rofi_paswitch")) bind(hyper .. " + comma", exec("rofi_wallpaper.sh")) +bind(hyper .. " + SHIFT + comma", exec("/home/imalison/dotfiles/dotfiles/lib/bin/neowall-wallpaper toggle")) bind(hyper .. " + Y", exec("rofi_agentic_skill")) bind(main_mod .. " + R", exec("hyprctl reload")) diff --git a/dotfiles/config/neowall/config.vibe b/dotfiles/config/neowall/config.vibe new file mode 100644 index 00000000..985389df --- /dev/null +++ b/dotfiles/config/neowall/config.vibe @@ -0,0 +1,7 @@ +default { + shader /run/current-system/sw/share/neowall/shaders/train_journey_optimized.glsl + shader_speed 0.7 + shader_fps 30 + mode fill + duration 0 +} diff --git a/dotfiles/config/neowall/screensaver.vibe b/dotfiles/config/neowall/screensaver.vibe new file mode 100644 index 00000000..267500cd --- /dev/null +++ b/dotfiles/config/neowall/screensaver.vibe @@ -0,0 +1,7 @@ +default { + shader /run/current-system/sw/share/neowall/shaders/matrix_rain.glsl + shader_speed 0.85 + shader_fps 30 + mode fill + duration 0 +} diff --git a/dotfiles/lib/bin/hypr-screensaver b/dotfiles/lib/bin/hypr-screensaver index 86711e1c..904e9ad5 100755 --- a/dotfiles/lib/bin/hypr-screensaver +++ b/dotfiles/lib/bin/hypr-screensaver @@ -4,12 +4,15 @@ set -euo pipefail state_dir="${XDG_RUNTIME_DIR:-/tmp}/hypr-screensaver" pid_file="$state_dir/mpvpaper.pid" +neowall_pid_file="$state_dir/neowall.pid" event_log="$state_dir/events.log" mkdir -p "$state_dir" title_prefix="hypr-screensaver:" +backend="${HYPR_SCREENSAVER_BACKEND:-mpvpaper}" screensaver_dir="${HYPR_SCREENSAVER_DIR:-/var/lib/syncthing/sync/Screensaver}" screensaver_use_dir="${HYPR_SCREENSAVER_USE_DIR:-$screensaver_dir/use}" +neowall_config="${HYPR_SCREENSAVER_NEOWALL_CONFIG:-${XDG_CONFIG_HOME:-$HOME/.config}/neowall/screensaver.vibe}" usage() { cat <<'EOF' @@ -44,6 +47,13 @@ with: HYPR_SCREENSAVER_HDR_MODE=auto HYPR_SCREENSAVER_HDR_MODE=sdr HYPR_SCREENSAVER_HDR_MODE=hdr + +Backend selection: + HYPR_SCREENSAVER_BACKEND=mpvpaper + HYPR_SCREENSAVER_BACKEND=neowall + +The neowall backend is a wallpaper-layer experiment. It does not cover existing +windows like mpvpaper's overlay layer. EOF } @@ -64,6 +74,11 @@ legacy_screensaver_window_pids() { } is_running() { + if [ "$backend" = "neowall" ]; then + neowall_is_running + return + fi + local pid if [ -f "$pid_file" ]; then pid="$(<"$pid_file")" @@ -76,6 +91,19 @@ is_running() { return 1 } +neowall_is_running() { + if [ -f "$neowall_pid_file" ]; then + local pid + pid="$(<"$neowall_pid_file")" + if kill -0 "$pid" 2>/dev/null; then + return 0 + fi + rm -f "$neowall_pid_file" + fi + + return 1 +} + default_source() { local size width height size="$( @@ -174,7 +202,44 @@ run_mpvpaper() { exec nix shell nixpkgs#mpvpaper --command mpvpaper "$@" } -start() { +run_neowall() { + if command -v neowall >/dev/null 2>&1; then + neowall "$@" + return + fi + + nix shell nixpkgs#neowall --command neowall "$@" +} + +start_neowall() { + local pid + + if neowall_is_running; then + log_event "neowall start ignored: already running pid=$(<"$neowall_pid_file")" + exit 0 + fi + + if [ ! -r "$neowall_config" ]; then + printf 'NeoWall screensaver config not found: %s\n' "$neowall_config" >&2 + return 1 + fi + + stop + systemctl --user stop hyprpaper.service >/dev/null 2>&1 || true + run_neowall -c "$neowall_config" >>"$state_dir/neowall.log" 2>&1 + + sleep 0.2 + pid="$(pgrep -n -x neowall || true)" + if [ -z "$pid" ]; then + log_event "neowall start failed: no neowall process found" + return 1 + fi + + printf '%s\n' "$pid" > "$neowall_pid_file" + log_event "neowall start ok pid=$pid config=$neowall_config" +} + +start_mpvpaper() { local source output layer options pid if is_running; then @@ -212,7 +277,22 @@ start() { log_event "start ok pid=$pid" } -stop() { +start() { + case "$backend" in + mpvpaper) + start_mpvpaper + ;; + neowall) + start_neowall + ;; + *) + printf 'Invalid HYPR_SCREENSAVER_BACKEND=%s; expected mpvpaper or neowall\n' "$backend" >&2 + exit 2 + ;; + esac +} + +stop_mpvpaper() { local pid legacy_pid if [ -f "$pid_file" ]; then @@ -231,6 +311,20 @@ stop() { done } +stop_neowall() { + if [ -f "$neowall_pid_file" ]; then + log_event "neowall stop pid=$(<"$neowall_pid_file")" + run_neowall kill >/dev/null 2>&1 || pkill -TERM -x neowall >/dev/null 2>&1 || true + rm -f "$neowall_pid_file" + systemctl --user start hyprpaper.service >/dev/null 2>&1 || true + fi +} + +stop() { + stop_mpvpaper + stop_neowall +} + status() { is_running } diff --git a/dotfiles/lib/bin/neowall-wallpaper b/dotfiles/lib/bin/neowall-wallpaper new file mode 100755 index 00000000..154b054f --- /dev/null +++ b/dotfiles/lib/bin/neowall-wallpaper @@ -0,0 +1,107 @@ +#!/usr/bin/env bash + +set -euo pipefail + +config_dir="${XDG_CONFIG_HOME:-$HOME/.config}/neowall" +config="${NEOWALL_WALLPAPER_CONFIG:-$config_dir/config.vibe}" + +usage() { + cat <<'EOF' +Usage: neowall-wallpaper + +Commands: + start Stop hyprpaper and start NeoWall with ~/.config/neowall/config.vibe. + stop Stop NeoWall and restart hyprpaper. + toggle Switch between NeoWall and hyprpaper. + status Exit 0 if NeoWall is running, otherwise exit 1. + next Ask NeoWall to advance to the next configured wallpaper. + list List NeoWall's current cycle. + current Show NeoWall's current wallpaper. + static Alias for stop. + +Override the config with: + NEOWALL_WALLPAPER_CONFIG=/path/to/config.vibe neowall-wallpaper start +EOF +} + +notify() { + if command -v notify-send >/dev/null 2>&1; then + notify-send "NeoWall" "$1" + else + printf '%s\n' "$1" >&2 + fi +} + +run_neowall() { + if command -v neowall >/dev/null 2>&1; then + neowall "$@" + return + fi + + nix shell nixpkgs#neowall --command neowall "$@" +} + +is_running() { + pgrep -x neowall >/dev/null 2>&1 +} + +stop_hyprpaper() { + systemctl --user stop hyprpaper.service >/dev/null 2>&1 || true +} + +start_hyprpaper() { + systemctl --user start hyprpaper.service >/dev/null 2>&1 || true +} + +stop_neowall() { + if is_running; then + run_neowall kill >/dev/null 2>&1 || pkill -TERM -x neowall >/dev/null 2>&1 || true + fi +} + +start() { + if [ ! -r "$config" ]; then + notify "Config not found: $config" + exit 1 + fi + + stop_hyprpaper + stop_neowall + run_neowall -c "$config" + notify "Live wallpaper started" +} + +stop() { + stop_neowall + start_hyprpaper + notify "Static wallpaper restored" +} + +case "${1:-}" in + start) + start + ;; + stop|static) + stop + ;; + toggle) + if is_running; then + stop + else + start + fi + ;; + status) + is_running + ;; + next|list|current) + run_neowall "$1" + ;; + ""|-h|--help|help) + usage + ;; + *) + usage >&2 + exit 2 + ;; +esac diff --git a/nixos/hyprland.nix b/nixos/hyprland.nix index 44bc3253..324a5add 100644 --- a/nixos/hyprland.nix +++ b/nixos/hyprland.nix @@ -256,6 +256,7 @@ [ # Hyprland utilities hyprpaper # Wallpaper + neowall # Shader wallpaper hypridle # Idle daemon hyprlock # Screen locker hyprcursor # Cursor themes