fix(headless/kde): start Xwayland + detect its display so X11 apps work
ci / web (push) Successful in 26s
ci / docs-site (push) Successful in 31s
apple / swift (push) Successful in 1m19s
ci / rust (push) Successful in 2m4s
ci / bench (push) Successful in 1m41s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 6s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 4s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 4s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 4s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 5s
deb / build-publish (push) Successful in 2m21s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 4m49s
docker / deploy-docs (push) Successful in 17s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Successful in 4m27s
ci / web (push) Successful in 26s
ci / docs-site (push) Successful in 31s
apple / swift (push) Successful in 1m19s
ci / rust (push) Successful in 2m4s
ci / bench (push) Successful in 1m41s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 6s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 4s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 4s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 4s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 5s
deb / build-publish (push) Successful in 2m21s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 4m49s
docker / deploy-docs (push) Successful in 17s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Successful in 4m27s
X11/Electron apps (Discord — "Missing X Server or $DISPLAY", Steam, many launchers) failed in the headless KWin session: `kwin_wayland --virtual` starts NO X server unless asked, and even with one KWin reserves the X11 display + starts Xwayland *on demand* (no Xwayland process or "Using public X11 display" log line until the first client connects) — so the old detection (pgrep the Xwayland process) found nothing and never exported DISPLAY. Two fixes: pass `--xwayland`, and detect the display from the reserved /tmp/.X11-unix/X<N> socket (with the log + process checks as fallbacks). Verified live on the Fedora 44 KDE box: DISPLAY=:0 lands in plasmashell + the activation env and xdpyinfo responds, so menu-launched X11 apps open a display. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -48,8 +48,12 @@ else
|
||||
fi
|
||||
|
||||
# kwin to its own log (so its EGL/GPU-init errors are captured, not lost to the terminal).
|
||||
# `--xwayland`: enable Xwayland so X11 apps (Discord/Electron, Steam, many launchers) work. Without
|
||||
# it `kwin_wayland --virtual` brings up NO X server at all (no display reserved), and those apps die
|
||||
# with "Missing X Server or $DISPLAY". KWin starts Xwayland on demand but reserves + logs the X11
|
||||
# display up front, which the detection below reads.
|
||||
KWIN_LOG="${TMPDIR:-/tmp}/punktfunk-kwin.log"
|
||||
kwin_wayland --virtual --width "$W" --height "$H" --no-lockscreen \
|
||||
kwin_wayland --virtual --xwayland --width "$W" --height "$H" --no-lockscreen \
|
||||
--socket "$WAYLAND_DISPLAY" >"$KWIN_LOG" 2>&1 &
|
||||
KWIN_PID=$!
|
||||
|
||||
@@ -78,13 +82,24 @@ echo "KWin ready."
|
||||
# is running — KWin sets DISPLAY only for its own children, not for apps launched via the
|
||||
# plasma menu / D-Bus activation. KWin brings Xwayland up a moment after itself; poll for it.
|
||||
DISPLAY_NUM=""
|
||||
for _ in $(seq 1 20); do
|
||||
# `|| true`: under `set -euo pipefail`, pgrep/grep exit non-zero when Xwayland isn't up yet
|
||||
for _ in $(seq 1 40); do
|
||||
# `|| true`: under `set -euo pipefail`, grep/pgrep exit non-zero when nothing's there yet
|
||||
# (common a few seconds into a systemd-launched boot), which would abort the WHOLE script —
|
||||
# killing KWin — on the first iteration instead of retrying. Tolerate it so the loop polls,
|
||||
# and so a session with no Xwayland at all still proceeds (DISPLAY just stays unset → warn).
|
||||
# Primary: KWin reserves + logs the X11 display ("Using public X11 display :N") up front, even
|
||||
# with Xwayland-on-demand (no Xwayland *process* until the first X client connects) — so the
|
||||
# old pgrep-the-process check found nothing and never set DISPLAY. Read the log; fall back to a
|
||||
# live Xwayland process for older KWin.
|
||||
d=$(grep -oE 'Using public X11 display :[0-9]+' "$KWIN_LOG" 2>/dev/null | grep -oE '[0-9]+' | head -1 || true)
|
||||
if [[ -n "$d" ]]; then DISPLAY_NUM="$d"; break; fi
|
||||
d=$(pgrep -a Xwayland 2>/dev/null | grep -oE ' :[0-9]+' | tr -d ' :' | head -1 || true)
|
||||
if [[ -n "$d" && -S "/tmp/.X11-unix/X$d" ]]; then DISPLAY_NUM="$d"; break; fi
|
||||
# Most reliable here: KWin --xwayland reserves the /tmp/.X11-unix/X<N> socket up front (Xwayland
|
||||
# starts on demand on first connect) and on this KWin neither logs the display nor runs a process
|
||||
# until then. The socket IS the signal — take it. (Fresh boot has a tmpfs /tmp, so no stale one.)
|
||||
s=$(ls /tmp/.X11-unix/X[0-9]* 2>/dev/null | head -1 || true)
|
||||
if [[ -n "$s" && -S "$s" ]]; then DISPLAY_NUM="${s##*/X}"; break; fi
|
||||
sleep 0.25
|
||||
done
|
||||
if [[ -n "$DISPLAY_NUM" ]]; then
|
||||
|
||||
Reference in New Issue
Block a user