fix freeze eww
This commit is contained in:
@@ -39,6 +39,18 @@ detach() {
|
||||
systemd-run --user --collect --quiet "${unit[@]}" -- "$cmd" "$@"
|
||||
}
|
||||
|
||||
# eww kills a click handler that has not returned within the widget's
|
||||
# :timeout (200 ms) — less than the eww client calls most handlers make
|
||||
# (~50 ms each), let alone bluetoothctl or a station list fetch. Re-run
|
||||
# this script detached and return at once. Call it with the original
|
||||
# arguments, before anything with side effects.
|
||||
# detach_self "$@"
|
||||
detach_self() {
|
||||
[[ -n ${EWW_DETACHED-} ]] && return 0
|
||||
EWW_DETACHED=1 setsid -f "$0" "$@"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Event multiplexer for listener scripts. Producers run in the background
|
||||
# and write one line per event into a fifo; the main loop re-evaluates the
|
||||
# state on every event, coalescing bursts into a single refresh.
|
||||
|
||||
@@ -5,6 +5,7 @@ active() { rfkill list wifi 2>/dev/null | grep -q "Soft blocked: yes"; }
|
||||
case ${1:-} in
|
||||
status) active && echo true || echo false ;;
|
||||
*)
|
||||
detach_self "$@"
|
||||
if active; then
|
||||
rfkill unblock all
|
||||
state=false
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
case ${1:-} in
|
||||
status) dunstctl is-paused ;;
|
||||
*)
|
||||
detach_self "$@"
|
||||
dunstctl set-paused toggle
|
||||
state=$(dunstctl is-paused)
|
||||
eww update do-not-disturb="$state" 2>/dev/null
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
# Connect or disconnect the bluetooth device with MAC $1.
|
||||
mac=$1
|
||||
[[ -n $mac ]] || exit 64
|
||||
detach_self "$@"
|
||||
if bluetoothctl info "$mac" 2>/dev/null | grep -q "Connected: yes"; then
|
||||
bluetoothctl disconnect "$mac"
|
||||
else
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
# Needs the polkit rule from modules/nixos/system/network/wireguard.
|
||||
name=$1
|
||||
[[ -n $name ]] || exit 64
|
||||
detach_self "$@"
|
||||
if [[ -d /sys/class/net/$name ]]; then
|
||||
systemctl stop "wireguard-$name.service"
|
||||
else
|
||||
|
||||
@@ -8,6 +8,7 @@ active() { systemctl --user is-active --quiet "$unit" || pgrep -x wlsunset >/dev
|
||||
case ${1:-} in
|
||||
status) active && echo true || echo false ;;
|
||||
*)
|
||||
detach_self "$@"
|
||||
if active; then
|
||||
systemctl --user stop "$unit" 2>/dev/null
|
||||
pkill -x wlsunset
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
# reply can never spawn a second daemon).
|
||||
panel=$1
|
||||
[[ -n $panel ]] || exit 64
|
||||
detach_self "$@"
|
||||
|
||||
# One toggle at a time; the lock dies with this process. fd 9 is closed for
|
||||
# every eww call so nothing can inherit it.
|
||||
|
||||
@@ -5,6 +5,7 @@ active() { [[ $(powerprofilesctl get 2>/dev/null) == power-saver ]]; }
|
||||
case ${1:-} in
|
||||
status) active && echo true || echo false ;;
|
||||
*)
|
||||
detach_self "$@"
|
||||
if active; then
|
||||
powerprofilesctl set balanced 2>/dev/null
|
||||
state=false
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
# Toggle the full-screen power menu on the focused monitor. The open's exit
|
||||
# status is ignored: it exceeds the client's 100 ms reply deadline.
|
||||
detach_self "$@"
|
||||
eww close popup 2>/dev/null
|
||||
eww update active-panel= 2>/dev/null
|
||||
screen=$(eww-bar focused)
|
||||
|
||||
@@ -216,10 +216,10 @@ status_loop() {
|
||||
}
|
||||
|
||||
case ${1:-} in
|
||||
start) start "$2" ;;
|
||||
stop) stop ;;
|
||||
toggle) if playing; then stop; else start "$(current_id)"; fi ;;
|
||||
vol) set_volume "$2" ;;
|
||||
mute) toggle_mute ;;
|
||||
start) detach_self "$@"; start "$2" ;;
|
||||
stop) detach_self "$@"; stop ;;
|
||||
toggle) detach_self "$@"; if playing; then stop; else start "$(current_id)"; fi ;;
|
||||
vol) detach_self "$@"; set_volume "$2" ;;
|
||||
mute) detach_self "$@"; toggle_mute ;;
|
||||
*) status_loop ;;
|
||||
esac
|
||||
|
||||
@@ -8,6 +8,7 @@ active() { hyprctl getoption decoration:screen_shader 2>/dev/null | grep -qF "$s
|
||||
case ${1:-} in
|
||||
status) active && echo true || echo false ;;
|
||||
*)
|
||||
detach_self "$@"
|
||||
if active; then
|
||||
hyprctl eval 'hl.config({ decoration = { screen_shader = "" } })' >/dev/null
|
||||
hyprctl eval 'hl.config({ render = { use_fp16 = 2 } })' >/dev/null
|
||||
|
||||
+43
-15
@@ -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,18 +235,19 @@ 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
|
||||
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 ! wait_for_window bar 5; then
|
||||
log "the bar does not come up, restarting $unit"
|
||||
if [[ $state != open ]]; then
|
||||
log "the bar does not come up ($state), restarting $unit"
|
||||
restart_unit
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
printf '%s\n' "$spec" >"$screen_file"
|
||||
printf '%s\n' "$screen" >"$current_file"
|
||||
log "bar opened on screen $screen"
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user