foxygit / screensaver Log in
commit ebe89a8ca021d1c4769f066a99dd1ca6405643f5
Author:     MrJensK <jens.se@icloud.com>
AuthorDate: Wed Aug 12 20:02:21 2026 +0200
Commit:     MrJensK <jens.se@icloud.com>
CommitDate: Wed Aug 12 20:02:21 2026 +0200

    updates
---
 README.md          | 20 +++++++++++++++++++-
 screensaver-launch | 27 ++++++++++++++++++++-------
 screensaver-toggle | 17 +++++++++++++++++
 screensaverd       | 23 +++++++++++++++++++++--
 4 files changed, 77 insertions(+), 10 deletions(-)

diff --git a/README.md b/README.md
index 20c57cd..3695e6c 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,13 @@ istället för Hyprland.
 - `screensaver-launch` – hittar alla anslutna skärmar (`xrandr`) och öppnar ett
   fullskärms-kitty-fönster med `screensaver` på var och en.
 - `screensaverd` – bevakar inaktivitet via `xssstate` och startar/dödar
-  screensavern automatiskt.
+  screensavern automatiskt. Skjuter upp start (och avbryter en redan startad
+  screensaver) medan något spelar upp media, via `playerctl status` – kräver
+  `playerctl` (valfritt, hoppas bara över om det saknas) och stöd för MPRIS i
+  spelaren (mpv, VLC, Firefox/Chromium m.fl.).
+- `screensaver-toggle` – pausar/återupptar `screensaverd`. Kör en gång för att
+  pausa (avbryter screensavern direkt om den visas just då), kör igen för att
+  återuppta.

 ## Installation

@@ -61,6 +67,18 @@ Efter ändring i `sxwmrc`: logga ut och in igen (eller kör
 `call : mod + r : reload_config` — observera att `reload_config` läser om
 bindningar/inställningar men `exec`-raderna körs bara vid sxwm-start).

+### Pausa tillfälligt
+
+```sh
+screensaver-toggle   # pausa; kör igen för att återuppta
+```
+
+Styr det med en tangent genom att lägga till i `~/.config/sxwmrc`:
+
+```
+bind : mod + shift + s : "screensaver-toggle"
+```
+
 ## Byta ASCII-konst

 Peka `screensaver` mot en annan fil genom att sätta miljövariabeln innan start:
diff --git a/screensaver-launch b/screensaver-launch
index 7c4e5b4..7160c4d 100755
--- a/screensaver-launch
+++ b/screensaver-launch
@@ -28,6 +28,7 @@ for mon in $(xrandr --listmonitors | awk 'NR>1 {print $3}'); do
     --override font_size=18 \
     --override window_padding_width=0 \
     --override background_opacity=1 \
+    --override mouse_hide_wait=0.1 \
     -e "$SCRIPT_DIR/screensaver" &
   kpid=$!

@@ -46,16 +47,28 @@ for mon in $(xrandr --listmonitors | awk 'NR>1 {print $3}'); do

   if [[ -n "$newwin" ]]; then
     # The window may not be fully mapped/reparented yet right after it
-    # appears in `xdotool search`, so retry the placement a few times to
-    # ride out the occasional BadWindow race with the window manager.
-    for attempt in 1 2 3; do
+    # appears in `xdotool search`, so retry placement to ride out the
+    # occasional BadWindow race with the window manager. `wmctrl`
+    # returning success only means the fullscreen request was sent, not
+    # that the WM actually acted on it (e.g. it's silently dropped if the
+    # window isn't mapped yet in the WM's eyes) -- read the geometry back
+    # and keep retrying until it actually matches the monitor, instead of
+    # giving up after a fixed few tries and leaving it windowed.
+    for attempt in $(seq 1 30); do
       xdotool windowactivate --sync "$newwin" 2>/dev/null
-      if xdotool windowmove "$newwin" "$x" "$y" 2>/dev/null \
-        && xdotool windowsize "$newwin" "$w" "$h" 2>/dev/null \
-        && wmctrl -ir "$newwin" -b add,fullscreen 2>/dev/null; then
+      xdotool windowmove "$newwin" "$x" "$y" 2>/dev/null
+      xdotool windowsize "$newwin" "$w" "$h" 2>/dev/null
+      wmctrl -ir "$newwin" -b add,fullscreen 2>/dev/null
+
+      geo="$(xdotool getwindowgeometry --shell "$newwin" 2>/dev/null)"
+      gx="$(grep -m1 '^X=' <<<"$geo" | cut -d= -f2)"
+      gy="$(grep -m1 '^Y=' <<<"$geo" | cut -d= -f2)"
+      gw="$(grep -m1 '^WIDTH=' <<<"$geo" | cut -d= -f2)"
+      gh="$(grep -m1 '^HEIGHT=' <<<"$geo" | cut -d= -f2)"
+      if [[ "$gx" == "$x" && "$gy" == "$y" && "$gw" == "$w" && "$gh" == "$h" ]]; then
         break
       fi
-      sleep 0.2
+      sleep 0.1
     done
   fi
 done
diff --git a/screensaver-toggle b/screensaver-toggle
new file mode 100755
index 0000000..b0bd488
--- /dev/null
+++ b/screensaver-toggle
@@ -0,0 +1,17 @@
+#!/bin/bash
+# Pauses/resumes screensaverd's idle detection. Run once to pause (also
+# stops the screensaver immediately if it's showing right now), run again
+# to resume. State is a flag file screensaverd polls every second, so
+# toggling takes effect within ~1s regardless of what screensaverd is
+# doing at the time.
+set -u
+
+PAUSE_FILE="${XDG_RUNTIME_DIR:-/tmp}/screensaver-paused"
+
+if [[ -e "$PAUSE_FILE" ]]; then
+  rm -f "$PAUSE_FILE"
+  echo "screensaver: återupptagen"
+else
+  touch "$PAUSE_FILE"
+  echo "screensaver: pausad"
+fi
diff --git a/screensaverd b/screensaverd
index 0d20a4e..ec1edf2 100755
--- a/screensaverd
+++ b/screensaverd
@@ -11,11 +11,30 @@ export PATH="$HOME/.local/bin:$PATH"
 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 IDLE_SECONDS="${SCREENSAVER_IDLE_SECONDS:-150}"
 WIN_CLASS="screensaver"
+PAUSE_FILE="${XDG_RUNTIME_DIR:-/tmp}/screensaver-paused"

 is_running() {
   xdotool search --class "^${WIN_CLASS}\$" >/dev/null 2>&1
 }

+# Set by screensaver-toggle. Checked fresh every loop iteration (not just
+# at launch time) so toggling pause while the screensaver is already
+# showing kills it immediately, same as real input would.
+is_paused() {
+  [[ -e "$PAUSE_FILE" ]]
+}
+
+# xssstate only tracks keyboard/mouse input, so a video playing quietly
+# (no input for the whole runtime) still counts as "idle" and would get
+# covered by the screensaver. playerctl (already a dependency for the
+# media keybindings) reports MPRIS playback state for players that
+# support it (mpv, VLC, Firefox/Chromium, ...), so use that as an extra
+# "really idle" check.
+media_playing() {
+  command -v playerctl >/dev/null 2>&1 || return 1
+  [ "$(playerctl status 2>/dev/null)" = "Playing" ]
+}
+
 stop_screensaver() {
   pkill -f "$SCRIPT_DIR/screensaver\$" 2>/dev/null
   pkill -x tte 2>/dev/null
@@ -28,9 +47,9 @@ while true; do
   idle_ms=$(xssstate -i)
   idle_s=$((idle_ms / 1000))

-  if (( idle_s >= IDLE_SECONDS )) && ! is_running; then
+  if (( idle_s >= IDLE_SECONDS )) && ! is_running && ! media_playing && ! is_paused; then
     "$SCRIPT_DIR/screensaver-launch"
-  elif (( idle_s < 1 )) && is_running; then
+  elif is_running && { (( idle_s < 1 )) || media_playing || is_paused; }; then
     stop_screensaver
   fi