From 6ecb1dbb56f94a60eb15dac228f832ef7bd47799 Mon Sep 17 00:00:00 2001 From: Scott Jones Date: Fri, 24 Jul 2026 01:08:21 -0400 Subject: [PATCH 1/2] Run the screensaver on every monitor, not just the last one omarchy-launch-screensaver loops over the monitors, focusing each and spawning a terminal on it -- but the spawn is asynchronous. Slow-starting terminals mapped their windows after focus had already moved to the next monitor, so every screensaver landed on the last-focused monitor and the others got none (and the fullscreen rule applied inconsistently when two windows mapped at once). Listen on Hyprland's event socket and wait for each monitor's screensaver window to open before moving focus to the next one, so there is exactly one screensaver per monitor. The stream is opened before spawning so a fast-mapping window can't be missed, with a read timeout as a safety net. Co-Authored-By: Claude Opus 4.8 (1M context) --- bin/omarchy-launch-screensaver | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/bin/omarchy-launch-screensaver b/bin/omarchy-launch-screensaver index 3f8b82f8..66bb4d89 100755 --- a/bin/omarchy-launch-screensaver +++ b/bin/omarchy-launch-screensaver @@ -28,6 +28,23 @@ hypr_exec() { hyprctl dispatch "hl.dsp.exec_cmd([[$command]])" >/dev/null 2>&1 || hyprctl dispatch exec -- bash -lc "$command" >/dev/null } +SOCKET="$XDG_RUNTIME_DIR/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock" + +# Open Hyprland's event stream before spawning anything, so a terminal that maps +# quickly can't emit its openwindow event before we are listening for it. +exec {events}< <(socat -U - "UNIX-CONNECT:$SOCKET") + +# hypr_exec is async and a new window maps on whatever monitor is focused at that +# moment. Block until this monitor's screensaver actually opens before moving +# focus on -- otherwise slow-starting terminals all pile onto the last monitor. +# The read timeout is a safety net in case the window never appears. +wait_for_screensaver_window() { + local line + while IFS= read -r -t 5 -u "$events" line; do + [[ $line == openwindow\>\>*,org.omarchy.screensaver,* ]] && return 0 + done +} + for m in $(hyprctl monitors -j | jq -r '.[] | .name'); do hypr_focus_monitor "$m" @@ -46,8 +63,11 @@ for m in $(hyprctl monitors -j | jq -r '.[] | .name'); do ;; *) omarchy-notification-send -g ✋ "Screensaver only runs in Alacritty, Foot, Ghostty, or Kitty" + continue ;; esac + + wait_for_screensaver_window done hypr_focus_monitor "$focused" From 26630a979641c90fd428b26983156ca3d3d95288 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Fri, 24 Jul 2026 09:31:55 -0700 Subject: [PATCH 2/2] Check terminal support once and bound the window wait overall An unsupported terminal notified once per monitor and each monitor paid a wasted wait; check before the loop instead. The per-read timeout also let a chatty event stream extend the wait indefinitely, so spend the 5 seconds against one deadline. Co-Authored-By: Claude Fable 5 --- bin/omarchy-launch-screensaver | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/bin/omarchy-launch-screensaver b/bin/omarchy-launch-screensaver index 66bb4d89..77122efd 100755 --- a/bin/omarchy-launch-screensaver +++ b/bin/omarchy-launch-screensaver @@ -17,6 +17,14 @@ fi focused=$(omarchy-hyprland-monitor-focused) terminal=$(xdg-terminal-exec --print-id) +case $terminal in +*Alacritty* | *ghostty* | *foot* | *kitty*) ;; +*) + omarchy-notification-send -g ✋ "Screensaver only runs in Alacritty, Foot, Ghostty, or Kitty" + exit 1 + ;; +esac + hypr_focus_monitor() { hyprctl dispatch "hl.dsp.focus({ monitor = \"$1\" })" >/dev/null 2>&1 || hyprctl dispatch focusmonitor "$1" >/dev/null } @@ -37,10 +45,10 @@ exec {events}< <(socat -U - "UNIX-CONNECT:$SOCKET") # hypr_exec is async and a new window maps on whatever monitor is focused at that # moment. Block until this monitor's screensaver actually opens before moving # focus on -- otherwise slow-starting terminals all pile onto the last monitor. -# The read timeout is a safety net in case the window never appears. +# The deadline is a safety net in case the window never appears. wait_for_screensaver_window() { - local line - while IFS= read -r -t 5 -u "$events" line; do + local line deadline=$((SECONDS + 5)) + while ((SECONDS < deadline)) && IFS= read -r -t $((deadline - SECONDS)) -u "$events" line; do [[ $line == openwindow\>\>*,org.omarchy.screensaver,* ]] && return 0 done } @@ -61,10 +69,6 @@ for m in $(hyprctl monitors -j | jq -r '.[] | .name'); do *kitty*) hypr_exec kitty --class=org.omarchy.screensaver --override font_size=18 --override window_padding_width=0 -e omarchy-screensaver ;; - *) - omarchy-notification-send -g ✋ "Screensaver only runs in Alacritty, Foot, Ghostty, or Kitty" - continue - ;; esac wait_for_screensaver_window