From 0c5171df6dae34ea289fc6d9334e7d66c5635d7d Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 11 May 2026 23:41:22 +0000 Subject: [PATCH] fix(walls,screensaver): work on IM6, dismissable mpv, loud errors stoa-walls.sh and stoa-screensaver.sh hard-required ImageMagick 7 (`magick`) and bailed on systems with only IM6 (`convert`), even though the gradient/draw/CLUT/plasma syntax they use is identical across both versions. Detect either binary at runtime and use it. stoa-walls.sh: fall back across reasonable mono font family names ("JetBrains Mono" with space is the canonical fontconfig family; the hyphenated form often fails to resolve and silently drops the text). stoa-screensaver.sh: - Check imagemagick/ffmpeg/mpv up front and report what's missing instead of producing a 0-byte video. - Stop hiding ffmpeg stderr; surface errors so policy/codec issues are diagnosable. - mpv was launched with --no-input-default-bindings AND an empty input-conf, which made the screensaver impossible to dismiss with the keyboard. Generate a minimal input.conf that maps any key / mouse click to quit, and drop the deprecated --input-vo-keyboard option. - Guard brightnessctl calls behind a command -v check. --- scripts/stoa-screensaver.sh | 129 ++++++++++++++++++++++-------------- scripts/stoa-walls.sh | 45 +++++++++---- 2 files changed, 112 insertions(+), 62 deletions(-) diff --git a/scripts/stoa-screensaver.sh b/scripts/stoa-screensaver.sh index 4c6131a..9e00c4e 100755 --- a/scripts/stoa-screensaver.sh +++ b/scripts/stoa-screensaver.sh @@ -15,6 +15,17 @@ STOA_SS_CONF="${XDG_CONFIG_HOME:-$HOME/.config}/stoa/screensaver.conf" STOA_SS_VIDEO="${STOA_SS_DIR}/marble-flow.mp4" STOA_SS_LOCK="${XDG_RUNTIME_DIR:-/tmp}/stoa-screensaver-${UID}.lock" +# ── ImageMagick detection ── +# Support both IM7 (`magick`) and IM6 (`convert`). The plasma/CLUT/draw +# syntax used below is identical across both versions. +if command -v magick &>/dev/null; then + IM=(magick) +elif command -v convert &>/dev/null; then + IM=(convert) +else + IM=() +fi + # ── Stoa Palette ── BG="#211e19" BG_LIGHT="#2d2921" @@ -51,11 +62,9 @@ _ss_get() { # ── Generation ── _gen_gradient_clut() { - # Create a color lookup table from Stoa palette - # This maps plasma grayscale → Stoa colors with smooth transitions local clut_path="${STOA_SS_DIR}/stoa-clut.png" - magick -size 1x1 xc:"$BG" xc:"$BG_LIGHT" xc:"$STONE" xc:"$BRONZE" xc:"$GOLD" xc:"$OLIVE" \ + "${IM[@]}" -size 1x1 xc:"$BG" xc:"$BG_LIGHT" xc:"$STONE" xc:"$BRONZE" xc:"$GOLD" xc:"$OLIVE" \ +append -filter Cubic -resize 256x1! \ "$clut_path" @@ -63,10 +72,9 @@ _gen_gradient_clut() { } _gen_warm_clut() { - # Warm variant: bg → terracotta → bronze → gold local clut_path="${STOA_SS_DIR}/stoa-clut-warm.png" - magick -size 1x1 xc:"$BG" xc:"#1a1714" xc:"$TERRACOTTA" xc:"$BRONZE" xc:"$GOLD" xc:"$FG" \ + "${IM[@]}" -size 1x1 xc:"$BG" xc:"#1a1714" xc:"$TERRACOTTA" xc:"$BRONZE" xc:"$GOLD" xc:"$FG" \ +append -filter Cubic -resize 256x1! \ "$clut_path" @@ -74,10 +82,9 @@ _gen_warm_clut() { } _gen_cool_clut() { - # Cool variant: bg → stone → olive → bronze local clut_path="${STOA_SS_DIR}/stoa-clut-cool.png" - magick -size 1x1 xc:"$BG" xc:"#1a1714" xc:"$STONE" xc:"$OLIVE" xc:"$BRONZE" xc:"$BG_LIGHT" \ + "${IM[@]}" -size 1x1 xc:"$BG" xc:"#1a1714" xc:"$STONE" xc:"$OLIVE" xc:"$BRONZE" xc:"$BG_LIGHT" \ +append -filter Cubic -resize 256x1! \ "$clut_path" @@ -88,6 +95,17 @@ generate() { local style="${1:-marble}" mkdir -p "$STOA_SS_DIR" + # Dependency check — fail loudly instead of producing an empty video. + local missing=() + [ ${#IM[@]} -eq 0 ] && missing+=("imagemagick (magick or convert)") + command -v ffmpeg &>/dev/null || missing+=("ffmpeg") + if [ ${#missing[@]} -gt 0 ]; then + echo " ERROR: missing dependencies:" >&2 + printf ' - %s\n' "${missing[@]}" >&2 + echo " Install on Arch: sudo pacman -S imagemagick ffmpeg" >&2 + return 1 + fi + echo " Generating Stoa screensaver ($style)..." echo "" @@ -138,7 +156,7 @@ generate() { # 3. Map grayscale to Stoa colors via CLUT # 4. Add subtle vignette for depth # 5. Scale to full HD - magick -size ${gen_w}x${gen_h} -seed "$seed" plasma: \ + if ! "${IM[@]}" -size ${gen_w}x${gen_h} -seed "$seed" plasma: \ -blur 0x${blur_sigma} \ -modulate "$((85 + phase % 20)),70,100" \ "$current_clut" -clut \ @@ -149,7 +167,13 @@ generate() { -compose multiply -composite \ -resize 1920x1080! \ -quality 92 \ - "$(printf '%s/frame_%04d.jpg' "$frame_dir" "$i")" + "$(printf '%s/frame_%04d.jpg' "$frame_dir" "$i")"; then + echo "" >&2 + echo " ERROR: ImageMagick failed rendering frame $i." >&2 + echo " Check /etc/ImageMagick-*/policy.xml for disabled coders (plasma)." >&2 + rm -rf "$frame_dir" + return 1 + fi # Progress progress=$(( (i + 1) * 100 / total_frames )) @@ -161,13 +185,18 @@ generate() { echo "" echo " Encoding video..." - # Encode with ffmpeg — high quality, smooth looping - ffmpeg -y -framerate "$fps" \ + # Encode with ffmpeg — high quality, smooth looping. + # Keep stderr visible so codec/policy issues are diagnosable. + if ! ffmpeg -y -hide_banner -loglevel error -framerate "$fps" \ -i "${frame_dir}/frame_%04d.jpg" \ -c:v libx264 -preset slow -crf 18 \ -pix_fmt yuv420p \ -movflags +faststart \ - "$STOA_SS_VIDEO" 2>/dev/null + "$STOA_SS_VIDEO"; then + echo " ERROR: ffmpeg failed encoding $STOA_SS_VIDEO" >&2 + rm -rf "$frame_dir" + return 1 + fi # Clean up frames rm -rf "$frame_dir" @@ -188,52 +217,56 @@ start() { return fi + if ! command -v mpv &>/dev/null; then + echo "stoa-screensaver: mpv not installed." >&2 + return 1 + fi + # Generate if not exists if [ ! -f "$STOA_SS_VIDEO" ]; then - generate + if ! generate; then + return 1 + fi fi # Dim the screen slightly before starting - local original_brightness - original_brightness=$(brightnessctl get 2>/dev/null) - - if [ -n "$WAYLAND_DISPLAY" ]; then - # Wayland: mpv fullscreen, any key/mouse exits - mpv --fullscreen --loop-file=inf --no-audio \ - --no-input-default-bindings \ - --input-conf=/dev/null \ - --osd-level=0 \ - --no-osc --no-terminal \ - --input-vo-keyboard=yes \ - --force-window=yes \ - --idle=no \ - "$STOA_SS_VIDEO" & - local mpv_pid=$! - echo "$mpv_pid" > "$STOA_SS_LOCK" - - # Wait for any input event to kill it - # mpv will catch keyboard via its window - wait "$mpv_pid" 2>/dev/null - else - # Xorg: same approach - mpv --fullscreen --loop-file=inf --no-audio \ - --no-input-default-bindings \ - --input-conf=/dev/null \ - --osd-level=0 \ - --no-osc --no-terminal \ - --input-vo-keyboard=yes \ - --force-window=yes \ - --idle=no \ - "$STOA_SS_VIDEO" & - local mpv_pid=$! - echo "$mpv_pid" > "$STOA_SS_LOCK" - wait "$mpv_pid" 2>/dev/null + local original_brightness="" + if command -v brightnessctl &>/dev/null; then + original_brightness=$(brightnessctl get 2>/dev/null) fi + # Minimal keybindings: any key (or mouse click) exits. + # We use --input-conf with a tiny generated file rather than disabling + # bindings entirely (the previous version made the screensaver impossible + # to dismiss with the keyboard). + local mpv_conf="${STOA_SS_DIR}/mpv-input.conf" + cat > "$mpv_conf" <<'EOF' +ANY_UNICODE quit +ESC quit +ENTER quit +SPACE quit +MBTN_LEFT quit +MBTN_RIGHT quit +MBTN_MID quit +EOF + + mpv --fullscreen --loop-file=inf --no-audio \ + --no-config \ + --input-conf="$mpv_conf" \ + --osd-level=0 \ + --no-osc --no-terminal \ + --cursor-autohide=always \ + --force-window=yes \ + --idle=no \ + "$STOA_SS_VIDEO" & + local mpv_pid=$! + echo "$mpv_pid" > "$STOA_SS_LOCK" + wait "$mpv_pid" 2>/dev/null + rm -f "$STOA_SS_LOCK" # Restore brightness - if [ -n "$original_brightness" ]; then + if [ -n "$original_brightness" ] && command -v brightnessctl &>/dev/null; then brightnessctl set "$original_brightness" -q 2>/dev/null fi } diff --git a/scripts/stoa-walls.sh b/scripts/stoa-walls.sh index df42dd7..16a7791 100755 --- a/scripts/stoa-walls.sh +++ b/scripts/stoa-walls.sh @@ -11,25 +11,45 @@ mkdir -p "$WALLDIR" WIDTH=1920 HEIGHT=1080 -# Require ImageMagick 7 (`magick`). ImageMagick 6 (`convert`) is not -# supported because the rectangle/gradient syntax we use below differs. -if ! command -v magick &>/dev/null; then - echo "stoa-walls: 'magick' (ImageMagick 7) not found." >&2 +# Use ImageMagick 7 (`magick`) when available, fall back to IM6 (`convert`). +# The rectangle/gradient/CLUT syntax we use below is identical in both. +if command -v magick &>/dev/null; then + IM=(magick) +elif command -v convert &>/dev/null; then + IM=(convert) +else + echo "stoa-walls: ImageMagick not found (neither 'magick' nor 'convert')." >&2 echo " Install: sudo pacman -S imagemagick" >&2 exit 1 fi +# Pick a usable mono font for the 'memento' wallpaper. ImageMagick matches +# fontconfig families: 'JetBrains Mono' (space) is the canonical name; the +# hyphenated form some docs show is not always resolved. Fall back gracefully. +_pick_font() { + local candidates=("JetBrains Mono" "JetBrainsMono-Regular" "JetBrains-Mono" \ + "DejaVu Sans Mono" "DejaVu-Sans-Mono" "monospace") + for f in "${candidates[@]}"; do + if "${IM[@]}" -list font 2>/dev/null | grep -qiE "^[[:space:]]*(Font:[[:space:]]*)?${f}\$"; then + echo "$f"; return + fi + done + # Last resort: let IM pick its default + echo "" +} +FONT=$(_pick_font) + echo "Generating Stoic wallpapers..." # 1. Marble — subtle gradient -magick -size ${WIDTH}x${HEIGHT} \ +"${IM[@]}" -size ${WIDTH}x${HEIGHT} \ gradient:"#2d2921-#1a1714" \ -blur 0x2 \ "$WALLDIR/marble.png" echo " [+] marble.png" # 2. Parchment — warm tone -magick -size ${WIDTH}x${HEIGHT} \ +"${IM[@]}" -size ${WIDTH}x${HEIGHT} \ gradient:"#211e19-#1a1714" \ -fill "#c49a5c" -draw "rectangle 0,$((HEIGHT/2-1)),${WIDTH},$((HEIGHT/2+1))" \ -blur 0x40 \ @@ -37,7 +57,7 @@ magick -size ${WIDTH}x${HEIGHT} \ echo " [+] parchment.png" # 3. Columns — minimalist vertical lines -magick -size ${WIDTH}x${HEIGHT} \ +"${IM[@]}" -size ${WIDTH}x${HEIGHT} \ xc:"#1a1714" \ -fill "#2d2921" \ -draw "rectangle $((WIDTH/2-60)),0,$((WIDTH/2-58)),${HEIGHT}" \ @@ -49,13 +69,10 @@ magick -size ${WIDTH}x${HEIGHT} \ echo " [+] columns.png" # 4. Minimalist with text -magick -size ${WIDTH}x${HEIGHT} \ - xc:"#1a1714" \ - -gravity center \ - -font "JetBrains-Mono" -pointsize 18 \ - -fill "#4a4540" \ - -annotate +0+0 "MEMENTO MORI" \ - "$WALLDIR/memento.png" +memento_args=(-size ${WIDTH}x${HEIGHT} xc:"#1a1714" -gravity center) +[ -n "$FONT" ] && memento_args+=(-font "$FONT") +memento_args+=(-pointsize 18 -fill "#4a4540" -annotate +0+0 "MEMENTO MORI" "$WALLDIR/memento.png") +"${IM[@]}" "${memento_args[@]}" echo " [+] memento.png" echo ""