#!/usr/bin/env bash # ============================================================================== # Motion Wallpaper — auto-pause watcher. # # Subscribes to Hyprland's event socket (socket2) and toggles mpv pause/resume # via the IPC socket that mpvpaper was started with. Replaces mpvpaper's own # --auto-pause / -p flag, which is unreliable on recent Hyprland releases. # # This script runs as a background sibling to mpvpaper. The main toggle script # starts it and kills it. # ============================================================================== set -euo pipefail RUNTIME_DIR="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}" MPV_IPC="$RUNTIME_DIR/motion-wallpaper-mpv.sock" LOG_FILE="${XDG_CACHE_HOME:-$HOME/.cache}/motion-wallpaper.log" log() { printf '[%s] watcher: %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" >> "$LOG_FILE" } his="${HYPRLAND_INSTANCE_SIGNATURE:-}" if [ -z "$his" ] || [ ! -d "$RUNTIME_DIR/hypr/$his" ]; then # HIS is missing or stale (points to a dead session). Recover from the # live signature reported by `hyprctl instances`. sig="$(hyprctl instances 2>/dev/null | awk '/^instance /{sub(/:$/,"",$2); print $2; exit}')" if [ -n "$sig" ]; then export HYPRLAND_INSTANCE_SIGNATURE="$sig" log "using HYPRLAND_INSTANCE_SIGNATURE=$sig (was: ${his:-unset})" else log "HYPRLAND_INSTANCE_SIGNATURE not usable and no live instance found — exiting" exit 0 fi fi HYPR_SOCK="$RUNTIME_DIR/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock" if [ ! -S "$HYPR_SOCK" ]; then log "hyprland event socket not found ($HYPR_SOCK) — exiting" exit 0 fi if ! command -v socat >/dev/null 2>&1; then log "socat not installed — exiting" exit 0 fi send_mpv() { # Best-effort — silently no-op if mpv's IPC socket isn't up yet. [ -S "$MPV_IPC" ] || return 0 printf '%s\n' "$1" | socat - "UNIX-CONNECT:$MPV_IPC" >/dev/null 2>&1 || true } pause_mpv() { send_mpv '{ "command": ["set_property", "pause", true] }'; } resume_mpv() { send_mpv '{ "command": ["set_property", "pause", false] }'; } log "watching $HYPR_SOCK" # Kill socat child on exit so it doesn't spam "Broken pipe" to the log when # the watcher is killed by the main toggle script. cleanup() { # `[ ] && kill` short-circuits to non-zero when SOCAT_PID is unset, which # under `set -e` would abort the trap before `exit 0` — wrap safely. if [ -n "${SOCAT_PID:-}" ]; then kill "$SOCAT_PID" 2>/dev/null || true fi exit 0 } trap cleanup EXIT INT TERM # Hyprland socket2 emits newline-separated "EVENT>>DATA" lines. We only care # about the fullscreen state. `fullscreen>>1` = entered, `fullscreen>>0` = left. # socat stderr is dropped so EPIPE on shutdown doesn't bloat the log. coproc SOCAT { socat -u "UNIX-CONNECT:$HYPR_SOCK" - 2>/dev/null; } # Bash auto-exports SOCAT_PID from `coproc SOCAT`; used in cleanup trap. while IFS= read -r line <&"${SOCAT[0]}"; do case "$line" in fullscreen\>\>1) log "fullscreen entered — pause" pause_mpv ;; fullscreen\>\>0) log "fullscreen left — resume" resume_mpv ;; esac done