From 6935bde5e94f913b04556558aa9fe4437dafe505 Mon Sep 17 00:00:00 2001 From: Don Williams Date: Sun, 8 Feb 2026 20:59:51 -0500 Subject: Added alternative RainbowBorders-low-cpu script to lower CPU Based on code from DemiGoD Updated and some additions to lower CPU overhead further On branch development Your branch is up to date with 'origin/development'. Changes to be committed: modified: CHANGELOG.md new file: config/hypr/UserScripts/RainbowBorders-low-cpu.sh --- config/hypr/UserScripts/RainbowBorders-low-cpu.sh | 177 ++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100755 config/hypr/UserScripts/RainbowBorders-low-cpu.sh (limited to 'config/hypr/UserScripts/RainbowBorders-low-cpu.sh') diff --git a/config/hypr/UserScripts/RainbowBorders-low-cpu.sh b/config/hypr/UserScripts/RainbowBorders-low-cpu.sh new file mode 100755 index 00000000..894c4848 --- /dev/null +++ b/config/hypr/UserScripts/RainbowBorders-low-cpu.sh @@ -0,0 +1,177 @@ +#!/usr/bin/env bash +# RainbowBorders-low-gpu.sh — low-overhead animated rainbow border for Hyprland +# +# Goal +# Animate Hyprland's active border with a rotating rainbow gradient while +# minimizing CPU usage on older systems by: +# - Using a modest update rate (default 1.0s) and larger angle steps +# - Avoiding subshell-heavy work inside the loop +# - Using a persistent Hyprland command socket (socat) when available +# - Quoting/validating inputs and suppressing noisy output +# - Preventing multiple concurrent instances +# - Optionally restoring the previous border value on exit +# +# Credits +# Initial source/idea by: DemiGoD +# Adaptation and optimization for low-CPU usage by: Hyprland-Dots maintainers +# +# Usage +# You can customize behavior via environment variables when launching: +# RB_INTERVAL Float seconds between updates (default: 1.0) +# RB_STEP_DEG Integer degrees per tick (default: 10) +# RB_START_DEG Integer starting angle (default: 0) +# RB_TARGET Hypr option to update (default: general:col.active_border) +# RB_COLORS Space-separated color list (default: 10-color rainbow below) +# RB_RESTORE If "1", attempt to restore previous value on exit (default: 1) +# RB_LOCKFILE Path to a PID lock file (default: /tmp/hypr-rainbowborders.lock) +# RB_TRANSPORT auto|socat|hyprctl (default: auto) +# - socat: send each command via Hyprland's command socket +# using socat (one short-lived connection per tick) +# - hyprctl: spawn hyprctl each tick +# - auto: prefer socat if possible, otherwise hyprctl +# +# Example (slower animation): +# RB_INTERVAL=1.5 RB_STEP_DEG=12 ~/.config/hypr/UserScripts/RainbowBorders-low-gpu.sh & +# +# Notes +# - This focuses on the active border only. Animating inactive borders too +# will increase updates and CPU usage. +# - Higher RB_INTERVAL (e.g., 1.0–2.0s) and larger RB_STEP_DEG (10–20) +# reduce per-second work substantially. + +set -u + +# Defaults (can be overridden by env vars) +RB_INTERVAL="${RB_INTERVAL:-1.0}" +RB_STEP_DEG="${RB_STEP_DEG:-10}" +RB_START_DEG="${RB_START_DEG:-0}" +RB_TARGET="${RB_TARGET:-general:col.active_border}" +RB_COLORS_DEFAULT="0xffff0000 0xffff8000 0xffffff00 0xff80ff00 0xff00ff00 0xff00ff80 0xff00ffff 0xff0080ff 0xff0000ff 0xff8000ff" +RB_COLORS="${RB_COLORS:-$RB_COLORS_DEFAULT}" +RB_RESTORE="${RB_RESTORE:-1}" +RB_LOCKFILE="${RB_LOCKFILE:-/tmp/hypr-rainbowborders.lock}" +RB_TRANSPORT="${RB_TRANSPORT:-auto}" + +# ---------- helpers ---------- +log() { printf '[RainbowBorders-low-gpu] %s\n' "$*" >&2; } + +die() { log "ERROR: $*"; exit 1; } + +is_float() { [[ "$1" =~ ^[0-9]+(\.[0-9]+)?$|^\.[0-9]+$ ]]; } + +is_int() { [[ "$1" =~ ^[0-9]+$ ]]; } + +# ---------- validation ---------- +if ! is_float "$RB_INTERVAL"; then + log "WARN: RB_INTERVAL='$RB_INTERVAL' invalid; defaulting to 1.0" + RB_INTERVAL="1.0" +fi +if ! is_int "$RB_STEP_DEG"; then + log "WARN: RB_STEP_DEG='$RB_STEP_DEG' invalid; defaulting to 10" + RB_STEP_DEG="10" +fi +if ! is_int "$RB_START_DEG"; then + log "WARN: RB_START_DEG='$RB_START_DEG' invalid; defaulting to 0" + RB_START_DEG="0" +fi + +# ---------- single-instance lock (PID file) ---------- +cleanup_lock() { [[ -f "$RB_LOCKFILE" ]] && rm -f "$RB_LOCKFILE"; } + +if [[ -f "$RB_LOCKFILE" ]]; then + oldpid="$(cat "$RB_LOCKFILE" 2>/dev/null || true)" + if [[ -n "${oldpid:-}" ]] && kill -0 "$oldpid" 2>/dev/null; then + log "Another instance is running (pid=$oldpid). Exiting." + exit 0 + else + # Stale lock + rm -f "$RB_LOCKFILE" || true + fi +fi +printf '%d' "$$" >"$RB_LOCKFILE" 2>/dev/null || die "Cannot write lockfile $RB_LOCKFILE" + +# ---------- transport (socat persistent socket vs hyprctl) ---------- +RB_MODE="" +RB_SOCK="" + +open_transport() { + local want="$RB_TRANSPORT" + local uid; uid=$(id -u 2>/dev/null || echo 0) + local base="${XDG_RUNTIME_DIR:-/run/user/$uid}" + local sig="${HYPRLAND_INSTANCE_SIGNATURE:-}" + if [[ -n "$sig" ]]; then + RB_SOCK="$base/hypr/$sig/.socket.sock" + fi + + # Prefer socat if requested/allowed and socket is available + if [[ "$want" == "socat" || "$want" == "auto" ]]; then + if command -v socat >/dev/null 2>&1 && [[ -n "$RB_SOCK" && -S "$RB_SOCK" ]]; then + RB_MODE="socat" + return 0 + elif [[ "$want" == "socat" ]]; then + die "RB_TRANSPORT=socat requested but 'socat' or Hyprland socket is unavailable" + fi + fi + + # Fallback to hyprctl: require presence and connectivity + command -v hyprctl >/dev/null 2>&1 || die "hyprctl not found and socat transport unavailable" + if ! hyprctl monitors >/dev/null 2>&1; then + die "hyprctl cannot reach a running Hyprland instance" + fi + RB_MODE="hyprctl" + return 0 +} + +open_transport || exit 1 +log "Using transport: $RB_MODE" + +# ---------- optional restore of previous border value ---------- +PREV_VALUE="" +if [[ "$RB_RESTORE" == "1" ]]; then + if command -v hyprctl >/dev/null 2>&1; then + # hyprctl getoption prints various formats; try common keys + PREV_VALUE="$(hyprctl getoption "$RB_TARGET" 2>/dev/null \ + | sed -n 's/^.*str:[[:space:]]\+//p; s/^.*string:[[:space:]]\+//p; s/^.*value:[[:space:]]\+//p' \ + | tail -n1)" + fi +fi + +restore_previous() { + if [[ "$RB_RESTORE" == "1" && -n "${PREV_VALUE:-}" ]]; then + if [[ "$RB_MODE" == "socat" ]]; then + printf 'keyword %s %s\n' "$RB_TARGET" "$PREV_VALUE" | socat - "UNIX-CONNECT:$RB_SOCK" >/dev/null 2>&1 || true + else + hyprctl keyword "$RB_TARGET" "$PREV_VALUE" >/dev/null 2>&1 || true + fi + fi +} + +on_exit() { + restore_previous + cleanup_lock +} +trap on_exit INT TERM EXIT + +# ---------- main loop ---------- +angle=$(( RB_START_DEG % 360 )) +STEP=$(( RB_STEP_DEG % 360 )) +(( STEP == 0 )) && STEP=10 + +write_border() { + local a="$1" + if [[ "$RB_MODE" == "socat" ]]; then + printf 'keyword %s %s %sdeg\n' "$RB_TARGET" "$RB_COLORS" "$a" | socat - "UNIX-CONNECT:$RB_SOCK" >/dev/null 2>&1 || true + else + hyprctl keyword "$RB_TARGET" "$RB_COLORS ${a}deg" >/dev/null 2>&1 || true + fi +} + +# Prime first write (avoid waiting one interval) +write_border "$angle" || log "WARN: initial write failed" + +while :; do + # Advance angle and write; failures are non-fatal to keep CPU use minimal + angle=$(( (angle + STEP) % 360 )) + write_border "$angle" + sleep "$RB_INTERVAL" +done -- cgit v1.2.3 From 704f8b46c04d008b33cf85575d8b85f720cb0ab0 Mon Sep 17 00:00:00 2001 From: Don Williams Date: Sun, 8 Feb 2026 21:12:05 -0500 Subject: Added -h/--help and --run-once to set borders but no animation It's a nice effect w/o the annoying color changes all the time On branch development Your branch is up to date with 'origin/development'. Changes to be committed: modified: CHANGELOG.md modified: config/hypr/UserScripts/RainbowBorders-low-cpu.sh --- CHANGELOG.md | 2 + config/hypr/UserScripts/RainbowBorders-low-cpu.sh | 92 ++++++++++++++++++----- 2 files changed, 75 insertions(+), 19 deletions(-) (limited to 'config/hypr/UserScripts/RainbowBorders-low-cpu.sh') diff --git a/CHANGELOG.md b/CHANGELOG.md index a1403ebb..c4cda124 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,8 @@ - Based on code from `DemiGoD` - I added variables for finer control - Some tweaks to lower CPU further + - Added `-h/--help` + - Added `--run-once` to set RainbowBorders but no animation ## v2.3.20 diff --git a/config/hypr/UserScripts/RainbowBorders-low-cpu.sh b/config/hypr/UserScripts/RainbowBorders-low-cpu.sh index 894c4848..bc0ab9ef 100755 --- a/config/hypr/UserScripts/RainbowBorders-low-cpu.sh +++ b/config/hypr/UserScripts/RainbowBorders-low-cpu.sh @@ -1,12 +1,12 @@ #!/usr/bin/env bash -# RainbowBorders-low-gpu.sh — low-overhead animated rainbow border for Hyprland +# RainbowBorders-low-cpu.sh — low-overhead animated rainbow border for Hyprland # # Goal # Animate Hyprland's active border with a rotating rainbow gradient while # minimizing CPU usage on older systems by: # - Using a modest update rate (default 1.0s) and larger angle steps # - Avoiding subshell-heavy work inside the loop -# - Using a persistent Hyprland command socket (socat) when available +# - Using Hyprland's command socket via socat when available # - Quoting/validating inputs and suppressing noisy output # - Preventing multiple concurrent instances # - Optionally restoring the previous border value on exit @@ -22,16 +22,17 @@ # RB_START_DEG Integer starting angle (default: 0) # RB_TARGET Hypr option to update (default: general:col.active_border) # RB_COLORS Space-separated color list (default: 10-color rainbow below) -# RB_RESTORE If "1", attempt to restore previous value on exit (default: 1) -# RB_LOCKFILE Path to a PID lock file (default: /tmp/hypr-rainbowborders.lock) +# RB_RESTORE If "1", attempt to restore previous value on exit (loop mode; default: 1) +# RB_LOCKFILE Path to a PID lock file (loop mode; default: /tmp/hypr-rainbowborders.lock) # RB_TRANSPORT auto|socat|hyprctl (default: auto) # - socat: send each command via Hyprland's command socket # using socat (one short-lived connection per tick) # - hyprctl: spawn hyprctl each tick # - auto: prefer socat if possible, otherwise hyprctl +# RB_ONCE 1 to apply once and exit (no animation; default: 0) # # Example (slower animation): -# RB_INTERVAL=1.5 RB_STEP_DEG=12 ~/.config/hypr/UserScripts/RainbowBorders-low-gpu.sh & +# RB_INTERVAL=1.5 RB_STEP_DEG=12 ~/.config/hypr/UserScripts/RainbowBorders-low-cpu.sh & # # Notes # - This focuses on the active border only. Animating inactive borders too @@ -51,16 +52,57 @@ RB_COLORS="${RB_COLORS:-$RB_COLORS_DEFAULT}" RB_RESTORE="${RB_RESTORE:-1}" RB_LOCKFILE="${RB_LOCKFILE:-/tmp/hypr-rainbowborders.lock}" RB_TRANSPORT="${RB_TRANSPORT:-auto}" +RB_ONCE="${RB_ONCE:-0}" # ---------- helpers ---------- -log() { printf '[RainbowBorders-low-gpu] %s\n' "$*" >&2; } +log() { printf '[RainbowBorders-low-cpu] %s\n' "$*" >&2; } die() { log "ERROR: $*"; exit 1; } +usage() { + cat <<'EOF' +Usage: RainbowBorders-low-cpu.sh [options] + +Options: + -h, --help Show this help and exit + --once, --run-once, -1 + Apply the current gradient once and exit (no animation). + In this mode, RB_RESTORE is ignored (the color persists). + +Environment overrides: + RB_INTERVAL Seconds between updates (default: 1.0) + RB_STEP_DEG Degrees per tick (default: 10) + RB_START_DEG Starting angle (default: 0) + RB_TARGET Hypr option to update (default: general:col.active_border) + RB_COLORS Space-separated colors (default: 10-color rainbow) + RB_RESTORE 1 to restore previous value on exit (loop mode only; default: 1) + RB_LOCKFILE PID lock path (loop mode only; default: /tmp/hypr-rainbowborders.lock) + RB_TRANSPORT auto|socat|hyprctl (default: auto) + RB_ONCE 1 for one-shot mode (same as --once) + +Examples: + Animate (light CPU): + RB_INTERVAL=1.5 RB_STEP_DEG=12 ./RainbowBorders-low-cpu.sh & + + Set a static rainbow once (no animation): + ./RainbowBorders-low-cpu.sh --once +EOF +} + is_float() { [[ "$1" =~ ^[0-9]+(\.[0-9]+)?$|^\.[0-9]+$ ]]; } is_int() { [[ "$1" =~ ^[0-9]+$ ]]; } +# ---------- parse CLI flags ---------- +while (( $# )); do + case "$1" in + -h|--help) usage; exit 0 ;; + --once|--run-once|-1) RB_ONCE=1 ;; + *) log "Unknown option: $1"; usage; exit 2 ;; + esac + shift +done + # ---------- validation ---------- if ! is_float "$RB_INTERVAL"; then log "WARN: RB_INTERVAL='$RB_INTERVAL' invalid; defaulting to 1.0" @@ -78,19 +120,21 @@ fi # ---------- single-instance lock (PID file) ---------- cleanup_lock() { [[ -f "$RB_LOCKFILE" ]] && rm -f "$RB_LOCKFILE"; } -if [[ -f "$RB_LOCKFILE" ]]; then - oldpid="$(cat "$RB_LOCKFILE" 2>/dev/null || true)" - if [[ -n "${oldpid:-}" ]] && kill -0 "$oldpid" 2>/dev/null; then - log "Another instance is running (pid=$oldpid). Exiting." - exit 0 - else - # Stale lock - rm -f "$RB_LOCKFILE" || true +if [[ "$RB_ONCE" != "1" ]]; then + if [[ -f "$RB_LOCKFILE" ]]; then + oldpid="$(cat "$RB_LOCKFILE" 2>/dev/null || true)" + if [[ -n "${oldpid:-}" ]] && kill -0 "$oldpid" 2>/dev/null; then + log "Another instance is running (pid=$oldpid). Exiting." + exit 0 + else + # Stale lock + rm -f "$RB_LOCKFILE" || true + fi fi + printf '%d' "$$" >"$RB_LOCKFILE" 2>/dev/null || die "Cannot write lockfile $RB_LOCKFILE" fi -printf '%d' "$$" >"$RB_LOCKFILE" 2>/dev/null || die "Cannot write lockfile $RB_LOCKFILE" -# ---------- transport (socat persistent socket vs hyprctl) ---------- +# ---------- transport (socat vs hyprctl) ---------- RB_MODE="" RB_SOCK="" @@ -127,7 +171,7 @@ log "Using transport: $RB_MODE" # ---------- optional restore of previous border value ---------- PREV_VALUE="" -if [[ "$RB_RESTORE" == "1" ]]; then +if [[ "$RB_RESTORE" == "1" && "$RB_ONCE" != "1" ]]; then if command -v hyprctl >/dev/null 2>&1; then # hyprctl getoption prints various formats; try common keys PREV_VALUE="$(hyprctl getoption "$RB_TARGET" 2>/dev/null \ @@ -150,9 +194,13 @@ on_exit() { restore_previous cleanup_lock } -trap on_exit INT TERM EXIT -# ---------- main loop ---------- +# In loop mode, set traps for cleanup/restore +if [[ "$RB_ONCE" != "1" ]]; then + trap on_exit INT TERM EXIT +fi + +# ---------- main logic ---------- angle=$(( RB_START_DEG % 360 )) STEP=$(( RB_STEP_DEG % 360 )) (( STEP == 0 )) && STEP=10 @@ -166,6 +214,12 @@ write_border() { fi } +if [[ "$RB_ONCE" == "1" ]]; then + # Single write and exit; do not restore previous (intended to persist) + write_border "$angle" || log "WARN: one-shot write failed" + exit 0 +fi + # Prime first write (avoid waiting one interval) write_border "$angle" || log "WARN: initial write failed" -- cgit v1.2.3