#!/bin/bash # Day/night theme switcher + wallpaper/color applier. # Two wallpapers: day.jpg (9:00-18:00) and night.jpg (18:00-9:00). # # 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" log() { printf '%s %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" >>"$LOG" } # 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" 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 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 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 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 \ "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)" 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 } 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