The reconciliation poll (added in "Fix clamshell display recovery") is a backstop for lid transitions the Hyprland switch binds can miss across suspend/resume. But the internal panel is only ever disabled while the laptop is docked — lid shut with an external monitor active — so the poll has nothing to reconcile when undocked. Running it 24/7 on every laptop wakes the CPU every 2s for no reason, which is exactly the case where battery matters most. Start the poll when an external monitor is present and stop it when the last one goes away (driven by the socat monitor-add/remove watch), gated on omarchy-hw-laptop. Undocked laptops and desktops now never poll; a docked laptop keeps the 2s recovery poll. Switch the event reader from a pipe to process substitution so it runs in the main shell and can manage the poll's lifetime. Desktop verified: no poll runs even with external monitors attached. The docked-laptop start/stop path needs a check on real laptop hardware. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
69 lines
1.9 KiB
Bash
Executable File
69 lines
1.9 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# omarchy:summary=Watch Hyprland monitor events and recover monitor toggles when a monitor is removed
|
|
|
|
SOCKET="$XDG_RUNTIME_DIR/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock"
|
|
LOCK="${XDG_RUNTIME_DIR:-/tmp}/omarchy-monitor-clamshell.lock"
|
|
|
|
sync_clamshell() {
|
|
(
|
|
flock -n 9 || exit 0
|
|
omarchy-hyprland-monitor-clamshell
|
|
) 9>"$LOCK"
|
|
}
|
|
|
|
sync_clamshell_after_monitor_change() {
|
|
sync_clamshell
|
|
|
|
(
|
|
for delay in 1 3 7; do
|
|
sleep "$delay"
|
|
sync_clamshell
|
|
done
|
|
) &
|
|
}
|
|
|
|
poll_clamshell_state() {
|
|
while true; do
|
|
sleep 2
|
|
sync_clamshell
|
|
done
|
|
}
|
|
|
|
# The internal panel is only ever disabled while a laptop is docked (lid shut
|
|
# with an external monitor active), so the reconciliation poll only has anything
|
|
# to reconcile in that window. Run it while docked, stop it when undocked, and
|
|
# never on a machine without a lid. Lid open/close itself is handled by the
|
|
# Hyprland "switch:*:Lid Switch" binds; this poll is the recovery backstop for
|
|
# drift those binds can miss (e.g. across suspend/resume).
|
|
poll_pid=""
|
|
sync_poll_state() {
|
|
if omarchy-hw-laptop && omarchy-hyprland-monitor-external-active; then
|
|
if [[ -z $poll_pid ]] || ! kill -0 "$poll_pid" 2>/dev/null; then
|
|
poll_clamshell_state &
|
|
poll_pid=$!
|
|
fi
|
|
elif [[ -n $poll_pid ]]; then
|
|
kill "$poll_pid" 2>/dev/null
|
|
poll_pid=""
|
|
fi
|
|
}
|
|
|
|
sync_clamshell_after_monitor_change
|
|
sync_poll_state
|
|
|
|
# Process substitution (not a pipe) keeps this loop in the main shell, so
|
|
# sync_poll_state can start and stop the background poll as monitors come and go.
|
|
while read -r event; do
|
|
case "$event" in
|
|
monitoradded\>\>*|monitoraddedv2\>\>*)
|
|
sync_clamshell_after_monitor_change
|
|
sync_poll_state
|
|
;;
|
|
monitorremoved\>\>*|monitorremovedv2\>\>*)
|
|
sync_clamshell_after_monitor_change
|
|
sync_poll_state
|
|
;;
|
|
esac
|
|
done < <(socat -U - "UNIX-CONNECT:$SOCKET")
|