#!/usr/bin/env bash # Container entrypoint: run Claude Desktop and stop when its window is closed. # # Closing the window only hides the app (it keeps running for the tray icon, # which GNOME doesn't show), so the container would keep running invisibly. # This watches the app's X windows and quits the app once none of them is # open or minimized. The container then exits with it. set -u claude-desktop "$@" & app=$! stop_app() { kill -TERM "$app" 2>/dev/null; wait "$app"; exit $?; } trap stop_app TERM INT HUP host="$(hostname)" # True if any of this container's Claude windows is Normal (shown) or Iconic # (minimized). A closed window is Withdrawn or loses WM_STATE altogether. # WM_CLIENT_MACHINE filters out Claude windows from other containers or apps # on the same X server. window_open() { local w props for w in $(xwininfo -root -tree 2>/dev/null \ | awk '/\("com\.anthropic\.claude" "com\.anthropic\.Claude"\)/ {print $1}'); do props="$(xprop -id "$w" WM_CLIENT_MACHINE WM_STATE 2>/dev/null)" || continue [[ "$props" == *"WM_CLIENT_MACHINE(STRING) = \"$host\""* ]] || continue [[ "$props" =~ "window state: "(Normal|Iconic) ]] && return 0 done return 1 } seen=0 # only arm the check after the first window has appeared misses=0 # require a few consecutive misses to ride out brief remaps while kill -0 "$app" 2>/dev/null; do sleep 1 & wait $! if window_open; then seen=1 misses=0 elif (( seen )) && (( ++misses >= 3 )); then echo "launch-claude: window closed, quitting Claude Desktop" >&2 stop_app fi done wait "$app"