From fc08e505b26159b391c06e36eb8c8056f9826a9f Mon Sep 17 00:00:00 2001 From: Storm Dragon Date: Mon, 14 Sep 2026 08:23:49 -0400 Subject: [PATCH] Attempt to improve the watchdog because it has failed on some systems. --- scripts/i3_watchdog.sh | 94 ++++++++++++++++++++++++++++-------------- 1 file changed, 63 insertions(+), 31 deletions(-) diff --git a/scripts/i3_watchdog.sh b/scripts/i3_watchdog.sh index face703..d03c7f8 100755 --- a/scripts/i3_watchdog.sh +++ b/scripts/i3_watchdog.sh @@ -17,9 +17,40 @@ checkInterval=3 # Check every 3 seconds timeoutSeconds=2 # Consider i3 locked if it doesn't respond within 2 seconds pidFile="${HOME}/.config/i3/i3_watchdog.pid" +logFile="/tmp/i38-i3-watchdog-${UID}.log" +maxLogBytes=262144 + +rotate_log() { + local logSize + + [[ -f "$logFile" ]] || return 0 + logSize=$(wc -c < "$logFile") + if ((logSize >= maxLogBytes)); then + mv -f -- "$logFile" "${logFile}.old" + fi +} log_message() { - echo "[i3-watchdog] $*" + local message + + message="[i3-watchdog] $* - $(date '+%Y-%m-%d %H:%M:%S')" + + rotate_log + printf '%s\n' "$message" + printf '%s\n' "$message" >> "$logFile" +} + +check_health() { + ipcWorks=0 + focusWorks=0 + + if timeout "$timeoutSeconds" i3-msg -t get_version > /dev/null 2>&1; then + ipcWorks=1 + fi + + if timeout 1 xdotool getwindowfocus > /dev/null 2>&1; then + focusWorks=1 + fi } # Kill any existing watchdog instances @@ -50,17 +81,7 @@ while true; do fi # Try to communicate with i3 IPC AND check X focus - ipcWorks=0 - focusWorks=0 - - if timeout "$timeoutSeconds" i3-msg -t get_version > /dev/null 2>&1; then - ipcWorks=1 - fi - - # Also check if X focus is working (use current DISPLAY, not hardcoded) - if timeout 1 xdotool getwindowfocus > /dev/null 2>&1; then - focusWorks=1 - fi + check_health # Both must work for system to be healthy if [[ $ipcWorks -eq 1 ]] && [[ $focusWorks -eq 1 ]]; then @@ -101,7 +122,7 @@ while true; do fi # Try to get i3 socket info - i3Socket=$(i3 --get-socketpath 2>/dev/null) + i3Socket=$(timeout "$timeoutSeconds" i3 --get-socketpath 2>/dev/null) log_message "i3 socket path: $i3Socket" if [[ -n "$i3Socket" ]] && [[ -S "$i3Socket" ]]; then @@ -112,43 +133,54 @@ while true; do fi # Check if this is a focus issue (Wine keyboard grab bug) - focusCheck=$(xdotool getwindowfocus 2>&1) + focusCheck=$(timeout 1 xdotool getwindowfocus 2>&1) log_message "Focus check result: $focusCheck" # Try to reset focus to i3 log_message "Attempting to reset X focus..." - xdotool key --clearmodifiers Super_L 2>/dev/null + timeout 1 xdotool key --clearmodifiers Super_L 2>/dev/null sleep 0.5 # Try to focus on i3's root window - i3RootWindow=$(xdotool search --class "i3" | head -1) + i3RootWindow=$(timeout 1 xdotool search --class "i3" 2>/dev/null | head -1) if [[ -n "$i3RootWindow" ]]; then log_message "Focusing i3 root window: $i3RootWindow" - xdotool windowfocus "$i3RootWindow" 2>/dev/null + timeout 1 xdotool windowfocus "$i3RootWindow" 2>/dev/null fi # Try i3-msg to focus something log_message "Using i3-msg to focus workspace..." - i3-msg workspace number 1 >/dev/null 2>&1 + timeout "$timeoutSeconds" i3-msg workspace number 1 >/dev/null 2>&1 sleep 0.5 - i3-msg focus output primary >/dev/null 2>&1 + timeout "$timeoutSeconds" i3-msg focus output primary >/dev/null 2>&1 sleep 1 - # Check if focus is actually fixed now - if timeout 1 xdotool getwindowfocus >/dev/null 2>&1; then - log_message "Focus recovery successful!" + # Recovery is successful only if both i3 IPC and X focus work. + check_health + if [[ $ipcWorks -eq 1 ]] && [[ $focusWorks -eq 1 ]]; then + log_message "Recovery successful" + lastSuccessTime=$(date +%s) + consecutiveFailures=0 else - log_message "Focus still broken - restarting i3..." - i3-msg -t run_command restart - log_message "Restart command sent" + log_message "Recovery incomplete - IPC:$ipcWorks Focus:$focusWorks; restarting i3" + if timeout "$timeoutSeconds" i3-msg -t run_command restart >/dev/null 2>&1; then + log_message "Restart command accepted" + else + log_message "Restart command failed or timed out" + fi + + # Wait for restart to complete, then verify it actually recovered. + sleep 5 + check_health + if [[ $ipcWorks -eq 1 ]] && [[ $focusWorks -eq 1 ]]; then + log_message "i3 healthy after restart" + lastSuccessTime=$(date +%s) + consecutiveFailures=0 + else + log_message "i3 still unhealthy after restart - IPC:$ipcWorks Focus:$focusWorks" + fi fi - # Wait for restart to complete - sleep 5 - - # Reset counters - lastSuccessTime=$(date +%s) - consecutiveFailures=0 fi fi done