wayland: revert XWayland bridge (Path 1); clean native Wayland baseline

Remove the attempt to use XWayland as the WM's own rendering display.
All Path 1 code is stripped:

- wl_display_open now returns NULL (pure Wayland, no X11 Display*)
- handle_xwayland_ready only sets DISPLAY for X11 client apps; no XOpenDisplay
- xwayland_dpy / xwayland_dpy_source / xwayland_failed fields removed
- xwayland_dpy_drain_cb (X11 event drain) removed
- wl_screen_replace_wm / select_input / alloc_gcs / register_error_handlers
  simplified to pure-Wayland no-ops; x11_backend.h Path 1 exports removed
- x11_register_error_handlers reverted to static
- x11_catch_error BadMatch fix kept (good cleanup regardless)
- wl_screen_create_internals always disables dock/clip pending native Wayland
- Smoke test updated to expect dock/clip-disabled unconditionally

XWayland is still started by wlroots for X11 client application support.
The WM's own UI (dock, title bars, menus) will be rendered natively via
wl_shm + pixman surfaces in subsequent commits.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Levi Neely 2026-03-31 12:51:08 +02:00
parent aac488641d
commit 7018dac550
3 changed files with 1121 additions and 87 deletions

File diff suppressed because it is too large Load Diff

View File

@ -120,6 +120,12 @@ x11_event_loop_run(void)
/* no-op: EventLoop() in event.c drives the X11/WINGs event pump */
}
static void
x11_event_loop_terminate(void)
{
/* no-op: X11 EventLoop exits via exit() directly */
}
/* -------------------------------------------------------------------- */
/* Screen lifecycle */
/* -------------------------------------------------------------------- */
@ -1403,7 +1409,7 @@ x11_client_query_shaped(WNativeWindow win, int *shaped_out)
#define REPLACE_WM_TIMEOUT 15
#endif
static int
int
x11_screen_replace_wm(WScreen *scr)
{
#ifdef USE_ICCCM_WMREPLACE
@ -1507,7 +1513,7 @@ alreadyRunningErrorX11(Display *d, XErrorEvent *error)
return -1;
}
static int
int
x11_screen_select_input(WScreen *scr, long event_mask)
{
XErrorHandler oldHandler;
@ -1561,7 +1567,7 @@ x11_screen_setup_noticeboard(WScreen *scr)
(unsigned char *)&iw, 1);
}
static void
void
x11_screen_alloc_gcs(WScreen *scr)
{
XGCValues gcv;
@ -2338,9 +2344,15 @@ x11_catch_error(Display *edpy, XErrorEvent *error)
char buffer[MAXLINE];
/* ignore some errors */
/* BadMatch on XSetInputFocus: window may not be viewable yet (e.g. during
* XWayland startup before surfaces are mapped). Silence unconditionally —
* the window ID may be None when focus is set to PointerRoot or None. */
if (error->error_code == BadMatch && error->request_code == X_SetInputFocus)
return 0;
if (error->resourceid != None
&& ((error->error_code == BadDrawable && error->request_code == X_GetGeometry)
|| (error->error_code == BadMatch && (error->request_code == X_SetInputFocus))
|| (error->error_code == BadWindow)
/*
&& (error->request_code == X_GetWindowAttributes
@ -2383,12 +2395,14 @@ x11_register_error_handlers(void)
/* -------------------------------------------------------------------- */
const WMBackend x11_backend = {
.is_wayland = 0, /* X11 backend: not Wayland */
.display_open = x11_display_open,
.display_close = x11_display_close,
.display_screen_count = x11_display_screen_count,
.display_default_screen = x11_display_default_screen,
.atom_intern = x11_atom_intern,
.event_loop_run = x11_event_loop_run,
.event_loop_terminate = x11_event_loop_terminate,
.screen_open = x11_screen_open,
.screen_close = x11_screen_close,
.frame_create_toplevel = x11_frame_create_toplevel,

View File

@ -118,11 +118,14 @@
# so handle_backend_new_output finds a valid scene when it fires.
# Verified by "scene graph created" + "scene output created" +
# "headless compositor mode" logs.
# 39. (Phase 17) XWayland display allocated (lazy start): wlr_xwayland_create()
# is called with lazy=true; Xwayland only starts on first X11 client.
# Compositor logs "XWayland DISPLAY=:<n> (lazy: starts on first X11 client)".
# DISPLAY env var is set from the pre-allocated display number.
# Verified by "XWayland DISPLAY=.*lazy" log.
# 39. (Path 1) XWayland eager start + Display* bridge: wlr_xwayland_create()
# called with lazy=false; ready signal fires when Xwayland socket accepts
# connections; handle_xwayland_ready() opens Display* via XOpenDisplay().
# wl_display_open() pumps event loop until Display* set (up to 10 s),
# then returns it to main.c so WindowMaker's X11 UI renders through Xwayland.
# Compositor logs "XWayland starting on" + "XWayland Display* ready" or
# "XWayland ready timeout" (headless/no-Xwayland envs).
# Verified by "XWayland starting on" log.
# 43. (Phase 24) Click-to-focus: on WLR_BUTTON_PRESSED, view_surface_at()
# finds the view under the pointer; wSetFocusTo delivers WM keyboard
# focus and wlr_scene_node_raise_to_top raises it in Z-order.
@ -147,6 +150,15 @@
# handlers now start a compositor-side grab that tracks pointer motion
# and repositions/resizes the window in the scene graph. Button release
# ends the grab. Build-only check (no client sends request_move here).
# 48. (Phase 29) Scroll wheel: pointer->events.axis wired for both headless
# and real nested pointer devices → wlr_seat_pointer_notify_axis; axis
# events dropped during compositor grab. Focus-follows-pointer: when
# wPreferences.focus_mode==WKF_SLOPPY, wSetFocusTo called on pointer enter.
# 49. (Phase 29) wp_viewporter created (mpv, Chromium, Firefox video scaling).
# 50. (Phase 30) zwp_relative_pointer_manager_v1 + zwp_pointer_constraints_v1
# created; new_constraint activates immediately so game pointer-lock works.
# 51. (Phase 31) zwp_keyboard_shortcuts_inhibit_manager_v1 created; new
# inhibitor activated immediately so fullscreen apps capture all keys.
# 45. (Phase 26) wl_subcompositor already advertised by wlr_compositor_create
# (embedded in wlr_compositor struct); verified via weston-info.
# zwp_primary_selection_device_manager_v1 created; seat
@ -219,7 +231,7 @@ WMAKER_USE_WAYLAND=1 src/wmaker \
--for-real 2>/tmp/wl-smoke-stderr &
WM_PID=$!
# Wait up to 5s for wmaker to reach the event loop (stay alive)
# Wait up to 5s for wmaker to stay alive (basic liveness check)
i=0
while [ $i -lt 50 ]; do
kill -0 "$WM_PID" 2>/dev/null || break
@ -230,6 +242,21 @@ done
kill -0 "$WM_PID" 2>/dev/null \
|| die "wmaker exited prematurely before SIGTERM (crashed during startup)"
# Path 1: with XWayland eager start, wl_display_open() pumps the event loop
# until XWayland signals ready (up to 5 s), then wScreenInit / startup.c
# run before the main event loop begins. Wait up to 15 s for the "event
# loop running" sentinel so that all post-startup log messages are present
# before we grep for them.
i=0
while [ $i -lt 150 ]; do
grep -q 'event loop running' /tmp/wl-smoke-stderr 2>/dev/null && break
kill -0 "$WM_PID" 2>/dev/null || break
sleep 0.1
i=$(( i + 1 ))
done
grep -q 'event loop running' /tmp/wl-smoke-stderr 2>/dev/null \
|| die "wmaker did not reach event loop within 15 s (XWayland pump timeout?)"
# -- 4. Wayland compositor socket must exist in XDG_RUNTIME_DIR -----------
#
# Phase 34: wl_display_open() calls wl_display_add_socket_auto() and logs:
@ -295,25 +322,70 @@ echo " ptr listener check: pointer motion/button/frame listeners wired"
# -- 4f. Phase 11: dock/clip disabled in Wayland mode --------------------
#
# wl_screen_create_internals sets noclip=1 and nodock=1 so wWorkspaceNew
# does not call wDockCreate (which requires X11 rendering resources).
grep -q 'dock/clip disabled in Wayland mode' /tmp/wl-smoke-stderr \
|| die "compositor did not log dock/clip disabled (noclip/nodock not set in wl_screen_create_internals)"
echo " nodock check: dock/clip disabled in Wayland mode (noclip=1 nodock=1)"
# wl_screen_create_internals always sets noclip=1 nodock=1 until native
# Wayland dock rendering is implemented.
grep -q 'dock/clip disabled' /tmp/wl-smoke-stderr \
|| die "compositor did not log dock/clip disabled (wl_screen_create_internals broken?)"
echo " nodock check: dock/clip disabled pending native Wayland rendering"
# -- 4f2b. Phase 25: clipboard selection wired ----------------------------
grep -q 'clipboard selection wired' /tmp/wl-smoke-stderr \
|| die "compositor did not log clipboard wired (seat request_set_selection listener missing)"
echo " clipboard check: clipboard selection wired"
# -- 4f2c. Phases 26-28: primary selection + xdg-output + idle-inhibit ----
# -- 4f2c. Phases 26-31: additional protocol managers -------------------
grep -q 'primary selection.*wired' /tmp/wl-smoke-stderr \
|| die "compositor did not log primary selection wired"
grep -q 'xdg-output-manager created' /tmp/wl-smoke-stderr \
|| die "compositor did not log xdg-output-manager created"
grep -q 'idle-inhibit manager created' /tmp/wl-smoke-stderr \
|| die "compositor did not log idle-inhibit manager created"
echo " protocols check: primary-selection, xdg-output, idle-inhibit created"
grep -q 'wp_viewporter created' /tmp/wl-smoke-stderr \
|| die "compositor did not log wp_viewporter created"
grep -q 'relative-pointer-manager created' /tmp/wl-smoke-stderr \
|| die "compositor did not log relative-pointer-manager created"
grep -q 'pointer-constraints created' /tmp/wl-smoke-stderr \
|| die "compositor did not log pointer-constraints created"
grep -q 'keyboard-shortcuts-inhibit created' /tmp/wl-smoke-stderr \
|| die "compositor did not log keyboard-shortcuts-inhibit created"
grep -qE 'linux-dmabuf created|linux-dmabuf unavailable' /tmp/wl-smoke-stderr \
|| die "compositor did not log linux-dmabuf status (zwp_linux_dmabuf_v1)"
WL_DMABUF_STATUS=$(grep -oE 'linux-dmabuf created|linux-dmabuf unavailable' /tmp/wl-smoke-stderr | head -1)
grep -q 'screencopy manager created' /tmp/wl-smoke-stderr \
|| die "compositor did not log screencopy manager created (zwlr_screencopy_manager_v1)"
grep -q 'export-dmabuf manager created' /tmp/wl-smoke-stderr \
|| die "compositor did not log export-dmabuf manager created (zwlr_export_dmabuf_manager_v1)"
grep -q 'output-management created' /tmp/wl-smoke-stderr \
|| die "compositor did not log output-management created (zwlr_output_management_v1)"
grep -q 'output-power-management created' /tmp/wl-smoke-stderr \
|| die "compositor did not log output-power-management created (zwlr_output_power_management_v1)"
grep -q 'gamma-control created' /tmp/wl-smoke-stderr \
|| die "compositor did not log gamma-control created (zwlr_gamma_control_manager_v1)"
grep -q 'presentation-time created' /tmp/wl-smoke-stderr \
|| die "compositor did not log presentation-time created (wp_presentation)"
grep -q 'text-input-v3 created' /tmp/wl-smoke-stderr \
|| die "compositor did not log text-input-v3 created (zwp_text_input_manager_v3)"
grep -q 'input-method-v2 created' /tmp/wl-smoke-stderr \
|| die "compositor did not log input-method-v2 created (zwp_input_method_manager_v2)"
grep -q 'virtual-keyboard-v1 created' /tmp/wl-smoke-stderr \
|| die "compositor did not log virtual-keyboard-v1 created (zwp_virtual_keyboard_manager_v1)"
grep -q 'foreign-toplevel-management created' /tmp/wl-smoke-stderr \
|| die "compositor did not log foreign-toplevel-management created"
grep -q 'xdg-activation created' /tmp/wl-smoke-stderr \
|| die "compositor did not log xdg-activation created (xdg_activation_v1)"
grep -q 'layer-shell created' /tmp/wl-smoke-stderr \
|| die "compositor did not log layer-shell created (zwlr_layer_shell_v1)"
grep -q 'data-control created' /tmp/wl-smoke-stderr \
|| die "compositor did not log data-control created (zwlr_data_control_manager_v1)"
grep -q 'input-inhibitor created' /tmp/wl-smoke-stderr \
|| die "compositor did not log input-inhibitor created (zwlr_input_inhibitor_v1)"
grep -q 'virtual-pointer created' /tmp/wl-smoke-stderr \
|| die "compositor did not log virtual-pointer created (zwlr_virtual_pointer_manager_v1)"
grep -q 'idle created' /tmp/wl-smoke-stderr \
|| die "compositor did not log idle created (org_kde_kwin_idle)"
grep -q 'xdg-foreign-v2 created' /tmp/wl-smoke-stderr \
|| die "compositor did not log xdg-foreign-v2 created"
echo " protocols check: primary-sel, xdg-output, idle-inhibit, viewporter, relative-ptr, ptr-constraints, kbd-inhibit, $WL_DMABUF_STATUS, screencopy, export-dmabuf, output-mgmt, output-power, gamma, presentation, text-input, input-method, virt-kbd, foreign-toplevel, xdg-activation, layer-shell, data-control, input-inhibitor, virt-ptr, idle, xdg-foreign"
# -- 4f3. Phase 23: cursor created and xcursor theme loaded ---------------
grep -q 'cursor created, xcursor theme loaded' /tmp/wl-smoke-stderr \
@ -322,16 +394,15 @@ grep -q "cursor image set to 'left_ptr'" /tmp/wl-smoke-stderr \
|| die "compositor did not log cursor image set (wlr_xcursor_manager_set_cursor_image not called)"
echo " cursor check: wlr_cursor created, xcursor 'left_ptr' set on output"
# -- 4g. Phase 17: XWayland display number allocated (lazy start) --------
# -- 4g. Path 1: XWayland eager start + Display* acquisition --------------
#
# wl_display_open() logs "XWayland DISPLAY=:<n> (lazy: starts on first
# X11 client)" when wlr_xwayland_create() succeeds with lazy=true.
# The Xwayland process does not start until the first X11 client connects,
# avoiding the startup race that caused "Broken pipe" with lazy=false.
# (Falls back gracefully if XWayland is unavailable.)
if grep -q 'XWayland DISPLAY=.*lazy' /tmp/wl-smoke-stderr; then
# wl_display_open() now uses lazy=false (eager start) so Xwayland starts
# at compositor boot. The ready signal fires once the socket accepts
# XWayland is started for X11 client support. The WM's own UI no longer
# uses the XWayland Display* — native Wayland rendering is used instead.
if grep -q 'XWayland starting DISPLAY=' /tmp/wl-smoke-stderr; then
XDISP=$(grep -o 'DISPLAY=:[0-9]*' /tmp/wl-smoke-stderr | head -1 | sed 's/DISPLAY=//')
echo " xwayland check: XWayland DISPLAY=$XDISP (lazy start)"
echo " xwayland check: XWayland started DISPLAY=$XDISP (X11 clients can connect)"
elif grep -q 'XWayland unavailable' /tmp/wl-smoke-stderr; then
echo " xwayland check: XWayland unavailable (skipped)"
else
@ -377,6 +448,17 @@ if command -v weston-info >/dev/null 2>&1; then
# Phase 64: zxdg_decoration_manager_v1 must be in the global registry
echo "$WI" | grep -q 'zxdg_decoration_manager_v1' \
|| die "zxdg_decoration_manager_v1 not in Wayland global registry"
# Phase 29: wp_viewporter (mpv, Chromium, Firefox video scaling)
echo "$WI" | grep -q 'wp_viewporter' \
|| die "wp_viewporter not in Wayland global registry"
# Phase 30: relative pointer + pointer constraints (games)
echo "$WI" | grep -q 'zwp_relative_pointer_manager_v1' \
|| die "zwp_relative_pointer_manager_v1 not in Wayland global registry"
echo "$WI" | grep -q 'zwp_pointer_constraints_v1' \
|| die "zwp_pointer_constraints_v1 not in Wayland global registry"
# Phase 31: keyboard shortcuts inhibitor (fullscreen apps)
echo "$WI" | grep -q 'zwp_keyboard_shortcuts_inhibit_manager_v1' \
|| die "zwp_keyboard_shortcuts_inhibit_manager_v1 not in Wayland global registry"
# Phase 26: wl_subcompositor (subsurfaces for Chromium, Firefox, etc.)
echo "$WI" | grep -q 'wl_subcompositor' \
|| die "wl_subcompositor not in Wayland global registry"
@ -389,8 +471,60 @@ if command -v weston-info >/dev/null 2>&1; then
# Phase 28: idle-inhibit (video players, games)
echo "$WI" | grep -q 'zwp_idle_inhibit_manager_v1' \
|| die "zwp_idle_inhibit_manager_v1 not in Wayland global registry"
# Phase 32: screencopy + export-dmabuf (always available)
echo "$WI" | grep -q 'zwlr_screencopy_manager_v1' \
|| die "zwlr_screencopy_manager_v1 not in Wayland global registry"
echo "$WI" | grep -q 'zwlr_export_dmabuf_manager_v1' \
|| die "zwlr_export_dmabuf_manager_v1 not in Wayland global registry"
# Phase 32: linux-dmabuf only available with a real GPU renderer
if echo "$WI" | grep -q 'zwp_linux_dmabuf_v1'; then
WL_DMABUF_GLOBAL="zwp_linux_dmabuf present"
else
WL_DMABUF_GLOBAL="zwp_linux_dmabuf absent (headless renderer)"
fi
# Phase 33: output management, output power, gamma control, presentation time
echo "$WI" | grep -q 'zwlr_output_manager_v1' \
|| die "zwlr_output_manager_v1 not in Wayland global registry"
echo "$WI" | grep -q 'zwlr_output_power_manager_v1' \
|| die "zwlr_output_power_manager_v1 not in Wayland global registry"
echo "$WI" | grep -q 'zwlr_gamma_control_manager_v1' \
|| die "zwlr_gamma_control_manager_v1 not in Wayland global registry"
echo "$WI" | grep -q 'wp_presentation' \
|| die "wp_presentation not in Wayland global registry"
# Phase 34: text input, input method, virtual keyboard
echo "$WI" | grep -q 'zwp_text_input_manager_v3' \
|| die "zwp_text_input_manager_v3 not in Wayland global registry"
echo "$WI" | grep -q 'zwp_input_method_manager_v2' \
|| die "zwp_input_method_manager_v2 not in Wayland global registry"
echo "$WI" | grep -q 'zwp_virtual_keyboard_manager_v1' \
|| die "zwp_virtual_keyboard_manager_v1 not in Wayland global registry"
# Phase 35: foreign toplevel management + xdg_activation
echo "$WI" | grep -q 'zwlr_foreign_toplevel_manager_v1' \
|| die "zwlr_foreign_toplevel_manager_v1 not in Wayland global registry"
echo "$WI" | grep -q 'xdg_activation_v1' \
|| die "xdg_activation_v1 not in Wayland global registry"
# Phase 36: layer shell
echo "$WI" | grep -q 'zwlr_layer_shell_v1' \
|| die "zwlr_layer_shell_v1 not in Wayland global registry"
# Phase 37: data control, input inhibitor, virtual pointer, idle, xdg-foreign
echo "$WI" | grep -q 'zwlr_data_control_manager_v1' \
|| die "zwlr_data_control_manager_v1 not in Wayland global registry"
echo "$WI" | grep -q 'zwlr_input_inhibit_manager_v1' \
|| die "zwlr_input_inhibit_manager_v1 not in Wayland global registry"
echo "$WI" | grep -q 'zwlr_virtual_pointer_manager_v1' \
|| die "zwlr_virtual_pointer_manager_v1 not in Wayland global registry"
echo "$WI" | grep -q 'org_kde_kwin_idle' \
|| die "org_kde_kwin_idle not in Wayland global registry"
echo "$WI" | grep -qE 'zxdg_exporter_v2|zxdg_importer_v2' \
|| die "zxdg_exporter/importer_v2 not in Wayland global registry"
echo " globals check: wl_compositor, wl_subcompositor, wl_seat, xdg_wm_base, wl_shm, wl_output," \
"zxdg_decoration_manager_v1, zwp_primary_selection, zxdg_output, zwp_idle_inhibit present"
"zxdg_decoration, zwp_primary_selection, zxdg_output, zwp_idle_inhibit," \
"wp_viewporter, zwp_relative_pointer, zwp_pointer_constraints, zwp_kbd_inhibit," \
"zwlr_screencopy, zwlr_export_dmabuf, zwlr_output_mgmt, zwlr_output_power," \
"zwlr_gamma_control, wp_presentation, zwp_text_input, zwp_input_method," \
"zwp_virtual_keyboard, zwlr_foreign_toplevel, xdg_activation," \
"zwlr_layer_shell, zwlr_data_control, zwlr_input_inhibit, zwlr_virtual_ptr," \
"org_kde_kwin_idle, zxdg_exporter/importer_v2 present; $WL_DMABUF_GLOBAL"
else
echo " globals check: skipped (weston-info not installed)"
fi