From d548b730e0c22f44724d31343a26f2fd10d38419 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Mon, 20 Jul 2026 08:15:09 -0700 Subject: [PATCH] Only run the clamshell poll while docked, not for every laptop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- bin/omarchy-hyprland-monitor-watch | 35 ++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/bin/omarchy-hyprland-monitor-watch b/bin/omarchy-hyprland-monitor-watch index 4353d300..e362f571 100755 --- a/bin/omarchy-hyprland-monitor-watch +++ b/bin/omarchy-hyprland-monitor-watch @@ -30,22 +30,39 @@ poll_clamshell_state() { 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 -# The socat watch below already reconciles clamshell state on monitor -# hotplug. The periodic poll only exists to catch laptop-lid transitions, -# so there is nothing for it to do on a machine that isn't a laptop. -if omarchy-hw-laptop; then - poll_clamshell_state & -fi - -socat -U - "UNIX-CONNECT:$SOCKET" | while read -r event; do +# 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 +done < <(socat -U - "UNIX-CONNECT:$SOCKET")