fix freeze eww

This commit is contained in:
2026-09-11 22:40:11 +02:00
parent 98ac3a8844
commit c8251c6f6d
12 changed files with 76 additions and 26 deletions
+49 -21
View File
@@ -56,6 +56,9 @@ log() { printf 'eww-bar: %s\n' "$*" >&2; }
ewwc() { timeout 5 eww --no-daemonize "$@" 9>&-; }
ping_daemon() { ewwc ping >/dev/null 2>&1; }
# Empty when the daemon did not answer within the client's 100 ms deadline —
# its main thread is busy (a popup takes seconds to build) — as well as when
# nothing is open. Only a non-empty listing is authoritative.
list_windows() { ewwc active-windows 2>/dev/null || true; }
bar_open() { list_windows | grep -qx 'bar: bar'; }
@@ -69,6 +72,28 @@ wait_for_window() {
return 1
}
# window_state NAME [SECONDS] → open | closed (listed without NAME) |
# busy (nothing listed within SECONDS: main thread stuck, or nothing open)
window_state() {
local i n=$((${2:-5} * 5)) out
for ((i = 0; i < n; i++)); do
out=$(list_windows)
if [[ -n $out ]]; then
if grep -qx "$1: $1" <<<"$out"; then echo open; else echo closed; fi
return 0
fi
sleep 0.2
done
echo busy
}
# The compositor's view: does the daemon own any layer surface? Tells a
# daemon that is merely not answering from one with nothing on screen.
daemon_has_layer() {
hyprctl -j layers 2>/dev/null \
| jq -e --argjson pid "$(main_pid)" '[.. | objects | select(.pid? == $pid)] | length > 0' >/dev/null 2>&1
}
# ---------------------------------------------------------------- daemon ---
# nixpkgs wraps eww (wrapGAppsHook), so the running process is `.eww-wrapped`;
@@ -126,13 +151,13 @@ wait_for_daemon() {
start_unit() {
systemctl --user reset-failed "$unit" >/dev/null 2>&1 || true
systemctl --user start "$unit"
systemctl --user start --no-block "$unit"
}
restart_unit() {
log "restarting $unit"
systemctl --user reset-failed "$unit" >/dev/null 2>&1 || true
systemctl --user restart "$unit"
systemctl --user restart --no-block "$unit"
}
ensure() {
@@ -194,7 +219,7 @@ close_popups() {
# open_bar [--force] [SPEC]
open_bar() {
local force=0 spec screen
local force=0 spec screen state
if [[ ${1:-} == --force ]]; then force=1; shift; fi
spec=${1:-$(saved_screen)}
spec=${spec:-$default_screen}
@@ -210,17 +235,18 @@ open_bar() {
# client deadline), so the result is verified instead.
close_popups
ewwc open bar --screen "$screen" >/dev/null 2>&1 || true
if ! wait_for_window bar 5; then
if [[ $screen != "$default_screen" ]]; then
log "cannot open the bar on '$screen', using screen $default_screen"
screen=$default_screen
ewwc open bar --screen "$screen" >/dev/null 2>&1 || true
fi
if ! wait_for_window bar 5; then
log "the bar does not come up, restarting $unit"
restart_unit
exit 1
fi
state=$(window_state bar 10)
# Only an answered "no bar" means the screen was refused; busy just needs time.
if [[ $state == closed && $screen != "$default_screen" ]]; then
log "cannot open the bar on '$screen', using screen $default_screen"
screen=$default_screen
ewwc open bar --screen "$screen" >/dev/null 2>&1 || true
state=$(window_state bar 10)
fi
if [[ $state != open ]]; then
log "the bar does not come up ($state), restarting $unit"
restart_unit
exit 1
fi
printf '%s\n' "$spec" >"$screen_file"
printf '%s\n' "$screen" >"$current_file"
@@ -301,14 +327,16 @@ check() {
strike "daemon does not answer"
return 0
fi
if wait_for_window bar 3; then
rm -f "$fail_file"
return 0
fi
# Either nothing is open or the main loop is frozen (empty reply). Try to
# open the bar: a frozen daemon still won't list it afterwards.
case $(window_state bar 10) in
open) rm -f "$fail_file"; return 0 ;;
# Nothing listed for 10 s while something is on screen: the main loop is
# frozen or still building a popup. Leave the windows alone; a second
# miss restarts the unit.
busy) if daemon_has_layer; then strike "UI unresponsive"; return 0; fi ;;
esac
# Listed without the bar, or nothing on screen at all: it really is gone.
open_bar || true
if wait_for_window bar 3; then
if wait_for_window bar 5; then
rm -f "$fail_file"
log "bar was missing, reopened"
else