summaryrefslogtreecommitdiff
path: root/niri
diff options
context:
space:
mode:
Diffstat (limited to 'niri')
-rwxr-xr-xniri/.config/niri/apply-colors.sh61
-rw-r--r--niri/.config/niri/config.kdl5
-rwxr-xr-xniri/.config/niri/theme-switcher.sh125
3 files changed, 133 insertions, 58 deletions
diff --git a/niri/.config/niri/apply-colors.sh b/niri/.config/niri/apply-colors.sh
index 339e134..505578c 100755
--- a/niri/.config/niri/apply-colors.sh
+++ b/niri/.config/niri/apply-colors.sh
@@ -22,46 +22,59 @@ if [ -z "$IMG" ] || [ ! -f "$IMG" ]; then
exit 1
fi
+# wait for the awww daemon to be ready (it is spawned next to this script at login)
+log "awww img $IMG"
+for _ in $(seq 1 10); do
+ if awww query >/dev/null 2>&1; then
+ break
+ fi
+ sleep 1
+done
+
+# set the wallpaper FIRST and unconditionally — this is the critical, must-work
+# step. Color generation below is best-effort: a failure there must never block
+# the wallpaper from changing (that coupling is what froze the wallpaper before).
+awww img "$IMG" || { log "awww img FAILED ($IMG)"; exit 1; }
+
+# blurred copy for the Overview backdrop (sibling or on-the-fly generation)
+"$SCRIPT_DIR/set-backdrop.sh" "$IMG" || log "set-backdrop FAILED ($IMG)"
+
# wallust: classic 16-color palette (foot, btop, ...)
# fastresize (the config default) is flaky on some images — always use resized.
-# A single attempt with honest error handling: the old retry loop swallowed
-# failures (case && break defeats set -e) and kept the stale light theme.
+# Best-effort: a wallust failure must not prevent the wallpaper from sticking.
log "wallust palette=$MODE $IMG"
case "$MODE" in
light|dark) WALLUST_PALETTE=("--palette" "$MODE") ;;
*) WALLUST_PALETTE=() ;;
esac
-if ! wallust run -b resized "${WALLUST_PALETTE[@]}" "$IMG"; then
- log "wallust FAILED ($IMG, mode=$MODE)"
- exit 1
+# wallust's `resized` backend is intermittently flaky on some images; retry a
+# few times, but ultimately tolerate failure.
+ok=0
+for attempt in 1 2 3; do
+ if wallust run -b resized "${WALLUST_PALETTE[@]}" "$IMG"; then
+ ok=1
+ break
+ fi
+ log "wallust attempt $attempt FAILED ($IMG, mode=$MODE)"
+ [ "$attempt" -lt 3 ] && sleep 2
+done
+if [ "$ok" -ne 1 ]; then
+ log "wallust FAILED after 3 attempts ($IMG, mode=$MODE) — continuing without wallust colors"
+else
+ # foot needs bare RRGGBB, not #RRGGBB — strip the leading '#'
+ sed -i 's/#\([0-9a-fA-F]\)/\1/g' ~/.cache/wallust/foot-theme.ini 2>/dev/null || true
fi
-# foot needs bare RRGGBB, not #RRGGBB — strip the leading '#'
-sed -i 's/#\([0-9a-fA-F]\)/\1/g' ~/.cache/wallust/foot-theme.ini 2>/dev/null || true
-
# matugen: Material You / M3 colors (niri focus ring, ...)
# --prefer is required for non-interactive runs (multiple source colors).
+# Best-effort: a matugen failure (e.g. bad config after an upgrade) must not
+# block the wallpaper.
log "matugen mode=$MODE $IMG"
case "$MODE" in
light) matugen image "$IMG" -m "light" --prefer saturation ;;
dark) matugen image "$IMG" -m "dark" --prefer saturation ;;
*) matugen image "$IMG" --prefer saturation ;;
-esac
-
-# wait for the awww daemon to be ready (it is spawned next to this script at login)
-log "awww img $IMG"
-for _ in $(seq 1 10); do
- if awww query >/dev/null 2>&1; then
- break
- fi
- sleep 1
-done
-
-# set the wallpaper
-awww img "$IMG"
-
-# blurred copy for the Overview backdrop (sibling or on-the-fly generation)
-"$SCRIPT_DIR/set-backdrop.sh" "$IMG"
+esac || log "matugen FAILED ($IMG, mode=$MODE) — continuing without matugen colors"
# reload consumers
killall -SIGUSR2 waybar 2>/dev/null || true
diff --git a/niri/.config/niri/config.kdl b/niri/.config/niri/config.kdl
index 05b2240..24b0896 100644
--- a/niri/.config/niri/config.kdl
+++ b/niri/.config/niri/config.kdl
@@ -1,4 +1,3 @@
-// Material You / Material Design 3 colors, generated by matugen (see theme-switcher.sh / apply-colors.sh)
include optional=true "/home/seraphim/.cache/matugen/theme.kdl"
spawn-at-startup "mako"
spawn-at-startup "xrdb" "-merge" "/home/seraphim/.Xresources"
@@ -11,7 +10,7 @@ spawn-at-startup "awww-daemon" "--namespace" "backdrop"
spawn-at-startup "/usr/libexec/hyprpolkitagent"
spawn-at-startup "dbus-update-activation-environment" "WAYLAND_DISPLAY" "DISPLAY" "XDG_CURRENT_DESKTOP"
spawn-at-startup "darkman" "run"
-spawn-at-startup "/home/seraphim/dotfiles-gentoo/niri/.config/niri/theme-switcher.sh"
+spawn-at-startup "/home/seraphim/dotfiles-gentoo/niri/.config/niri/theme-switcher.sh" "--daemon"
spawn-at-startup "sh" "-c" "NO_AT_BRIDGE=1 waybar"
spawn-at-startup "/usr/bin/Throne"
spawn-at-startup "mpd"
@@ -37,7 +36,7 @@ layer-rule {
place-within-backdrop true
}
input {
-// focus-follows-mouse max-scroll-amount="30%"
+ focus-follows-mouse max-scroll-amount="100%"
keyboard {
xkb {
diff --git a/niri/.config/niri/theme-switcher.sh b/niri/.config/niri/theme-switcher.sh
index 6b3b6e9..6d1f548 100755
--- a/niri/.config/niri/theme-switcher.sh
+++ b/niri/.config/niri/theme-switcher.sh
@@ -1,12 +1,19 @@
#!/bin/bash
+# Day/night theme switcher + wallpaper/color applier.
# Two wallpapers: day.jpg (9:00-18:00) and night.jpg (18:00-9:00).
-# To switch, just rename the files in ~/Pictures/wallpapers/.
+#
+# Usage:
+# ./theme-switcher.sh one-shot: apply based on current time, then exit
+# ./theme-switcher.sh day|light force light theme, then exit
+# ./theme-switcher.sh night|dark force dark theme, then exit
+# ./theme-switcher.sh --daemon continuous time-based loop (used at login)
WALLPAPERS="$HOME/Pictures/wallpapers"
STATE_FILE="/tmp/current_theme_state"
WALLPAPER_STATE_FILE="/tmp/current_wallpaper_state"
BACKDROP_STATE_FILE="/tmp/current_backdrop_state"
+PID_FILE="/tmp/theme-switcher.daemon.pid"
LOG="/tmp/theme-switcher.log"
SCRIPT_DIR="$(cd "$(dirname "$(realpath "$0")")" && pwd)"
SET_BACKDROP="$SCRIPT_DIR/set-backdrop.sh"
@@ -15,58 +22,114 @@ log() {
printf '%s %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" >>"$LOG"
}
-while true; do
- HOUR=$(date +%H)
- HOUR=$((10#$HOUR))
-
- if [ "$HOUR" -ge 9 ] && [ "$HOUR" -lt 18 ]; then
+# Resolve TARGET_STATE / MODE / WALLPAPER. Optional $1 forces day|night.
+resolve_target() {
+ local force="${1:-}"
+ if [ "$force" = "day" ] || [ "$force" = "light" ]; then
TARGET_STATE="light"
MODE="light"
WALLPAPER="$WALLPAPERS/day.jpg"
- else
+ elif [ "$force" = "night" ] || [ "$force" = "dark" ]; then
TARGET_STATE="dark"
MODE="dark"
WALLPAPER="$WALLPAPERS/night.jpg"
+ else
+ local HOUR
+ HOUR=$(date +%H)
+ HOUR=$((10#$HOUR))
+ if [ "$HOUR" -ge 9 ] && [ "$HOUR" -lt 18 ]; then
+ TARGET_STATE="light"
+ MODE="light"
+ WALLPAPER="$WALLPAPERS/day.jpg"
+ else
+ TARGET_STATE="dark"
+ MODE="dark"
+ WALLPAPER="$WALLPAPERS/night.jpg"
+ fi
fi
+}
+# Apply the resolved target once. Returns 0 on success.
+apply_target() {
if [ ! -f "$WALLPAPER" ]; then
- sleep 60
- continue
+ log "wallpaper missing: $WALLPAPER"
+ return 1
fi
+ local CURRENT_THEME CURRENT_WALLPAPER EXPECTED_BACKDROP ACTUAL_BACKDROP
+
CURRENT_THEME=$(cat "$STATE_FILE" 2>/dev/null || true)
+ # Already in the correct theme: don't re-run wallust/matugen every loop tick.
+ # Still self-heal a drifted backdrop below, then bail out.
+ if [ "$CURRENT_THEME" = "$TARGET_STATE" ]; then
+ EXPECTED_BACKDROP=$(cat "$BACKDROP_STATE_FILE" 2>/dev/null || true)
+ ACTUAL_BACKDROP=$(awww query -n backdrop -j 2>/dev/null | jq -r '.["backdrop"][0].displaying.image // empty')
+ if [ -n "$EXPECTED_BACKDROP" ] && [ "$ACTUAL_BACKDROP" != "$EXPECTED_BACKDROP" ]; then
+ "$SET_BACKDROP" "$WALLPAPER"
+ fi
+ return 0
+ fi
CURRENT_WALLPAPER=$(cat "$WALLPAPER_STATE_FILE" 2>/dev/null || true)
- # Self-heal the Overview backdrop
+ # Self-heal the Overview backdrop if it drifted from the expected image.
EXPECTED_BACKDROP=$(cat "$BACKDROP_STATE_FILE" 2>/dev/null || true)
ACTUAL_BACKDROP=$(awww query -n backdrop -j 2>/dev/null | jq -r '.["backdrop"][0].displaying.image // empty')
if [ -n "$EXPECTED_BACKDROP" ] && [ "$ACTUAL_BACKDROP" != "$EXPECTED_BACKDROP" ]; then
"$SET_BACKDROP" "$WALLPAPER"
fi
- if [ "$CURRENT_WALLPAPER" != "$WALLPAPER" ] || [ "$CURRENT_THEME" != "$TARGET_STATE" ]; then
- log "switching to $TARGET_STATE ($WALLPAPER)"
- if sh "$SCRIPT_DIR/apply-colors.sh" "$WALLPAPER" "$MODE"; then
- if [ "$CURRENT_THEME" != "$TARGET_STATE" ]; then
- darkman set "$TARGET_STATE"
- fi
+ log "switching to $TARGET_STATE ($WALLPAPER)"
+ if sh "$SCRIPT_DIR/apply-colors.sh" "$WALLPAPER" "$MODE"; then
+ if [ "$CURRENT_THEME" != "$TARGET_STATE" ]; then
+ darkman set "$TARGET_STATE"
+ fi
- ln -sf \
- "theme-${TARGET_STATE}.css" \
- "$HOME/dotfiles-gentoo/waybar/.config/waybar/theme.css"
+ ln -sf \
+ "theme-${TARGET_STATE}.css" \
+ "$HOME/dotfiles-gentoo/waybar/.config/waybar/theme.css"
- ln -sf \
- "settings-${TARGET_STATE}.ini" \
- "$HOME/dotfiles-gentoo/gtk/.config/gtk-3.0/settings.ini"
+ ln -sf \
+ "settings-${TARGET_STATE}.ini" \
+ "$HOME/dotfiles-gentoo/gtk/.config/gtk-3.0/settings.ini"
- echo "$TARGET_STATE" >"$STATE_FILE"
- echo "$WALLPAPER" >"$WALLPAPER_STATE_FILE"
- log "switched to $TARGET_STATE ($WALLPAPER)"
- else
- # State is intentionally NOT written so the next loop iteration retries.
- log "FAILED to apply $TARGET_STATE ($WALLPAPER), will retry"
- fi
+ echo "$TARGET_STATE" >"$STATE_FILE"
+ echo "$WALLPAPER" >"$WALLPAPER_STATE_FILE"
+ log "switched to $TARGET_STATE ($WALLPAPER)"
+ return 0
+ else
+ log "FAILED to apply $TARGET_STATE ($WALLPAPER)"
+ return 1
+ fi
+}
+
+daemon_loop() {
+ # Refuse to run a second daemon instance (e.g. manual run while one is alive).
+ if [ -f "$PID_FILE" ] && kill -0 "$(cat "$PID_FILE" 2>/dev/null)" 2>/dev/null; then
+ log "daemon already running (pid $(cat "$PID_FILE")), exiting"
+ exit 0
fi
+ echo $$ >"$PID_FILE"
+
+ while true; do
+ resolve_target
+ apply_target || true # failure is retried on the next loop, state is left untouched
+ sleep 60
+ done
+}
- sleep 60
-done
+case "${1:-}" in
+--daemon | -d) daemon_loop ;;
+"" | day | light | night | dark)
+ resolve_target "${1:-}"
+ apply_target
+ exit $?
+ ;;
+-h | --help)
+ echo "usage: $0 [day|night|--daemon]" >&2
+ exit 0
+ ;;
+*)
+ echo "usage: $0 [day|night|--daemon]" >&2
+ exit 1
+ ;;
+esac