Three root causes fixed:
1. RCreateContext crash: wScreenInit called RCreateContext(dpy=NULL).
Fix: add RCreateContextWayland() to wrlib — creates a minimal 32-bit
ARGB context without X11. Wayland path in screen.c now always taken
when is_wayland (removed incorrect XWayland fallthrough).
2. Color parsing: parse_color and get_color_for_colormap were no-ops.
Fix: implement real color parser in wl_backend supporting #RGB,
#RRGGBB, #RRRRGGGGBBBB, rgb:RR/GG/BB, and common named colors.
Texture creation (solid, gradient) now works in Wayland mode.
3. RConvertImage crash: wrlib tried XCreateImage with NULL display.
Fix: RConvertImage/RConvertImageMask return success with pixmap=0
when context->dpy is NULL. Callers don't use pixmaps in Wayland
mode (rendering goes through vtable slots to pixman buffers).
4. Workspace crash: Wayland path skipped wWorkspaceNew(), so
workspace_count=0 when menu tried to access workspace entries.
Fix: add wWorkspaceNew + netwm_init to Wayland screen init path.
Result: compositor starts, event loop runs, window is visible.
WMAKER_USE_WAYLAND=1 wmaker now shows a compositor window.
Replace dpy-based conditional in wScreenInit with root_win check.
Remaining dpy references in policy files are all in X11 mechanism
code (rendering functions, event handlers, XWayland setup) that is
only reached through the X11 backend path.
Add vtable slots: icon_select, icon_change_title, clip_icon_paint,
drawer_icon_paint, balloon_init, do_kaboom, menu_paint_entry,
menu_draw_frame.
Replace policy call sites with vtable dispatch. Make paintEntry and
drawFrame in menu.c non-static as wMenuPaintEntry/wMenuDrawFrame.
X11 backend calls the mechanism functions; Wayland backend is no-op.
wFrameWindowPaint now only reached through X11 backend's frame_paint.
- WMCreateScreenWithRContext: add Wayland path that skips all X11 calls
(no GCs, no atoms, no XListProperties, no XCreateGC)
- screen.c: skip RCreateContext in Wayland mode (pass NULL rcontext)
- Wayland path initializes: font/event/render backends, colors, fonts
Current issue: W_RealizeView tries to create X11 windows for WINGs
widgets. Need to make view realization work without X11 (views should
be pixman buffers in Wayland mode, not X windows).
The grey background + cursor render correctly. Startup reaches
WINGs init but crashes when widgets try to realize without a display.
- wScreenInit Wayland fast path now creates RContext on XWayland display
(needed for wTextureRenderImage and wraster image loading)
- Also creates WINGs screen (wmscreen) so WMDrawString/WMFontHeight work
- Add wl_get_x_display() accessor for screen.c to get XWayland Display*
- Remove if(dpy) guard around wScreenRestoreState in startup.c so dock,
clip, menus, and window management run in Wayland mode
Status: startup reaches menu creation but hangs in wMenuCreate due to
Xlib operations on XWayland during WINGs font/screen init. The pump
thread is running but something in the menu creation path is spinning.
Next step: identify and eliminate the remaining XWayland dependency in
the menu creation path.
Key changes in wl_backend.c:
- wl_atom_intern: call XInternAtom on XWayland display (was returning 0)
- Add wl_or_view struct to track override_redirect XWayland surfaces
- handle_xwayland_new_surface: composite OR surfaces via scene graph
- frame_create_toplevel/child: create real X11 windows on XWayland
- frame_destroy/configure: delegate to Xlib
- window_map/unmap/move/resize: fall through to Xlib for frame windows
- stacking_raise/lower: update scene graph + Xlib fallback
- event_flush/sync: call XFlush/XSync on XWayland display
- window_set_border/border_width/clear: delegate to Xlib
- window_get_rect: query XWayland geometry for non-toplevel windows
Note: frame creation via XWayland is a temporary bridge. The correct
architectural approach is native scene-buffer rendering with pixman.
Three related fixes to make the WM focus lifecycle work end-to-end in
the Wayland path:
1. window.c: set wwin->flags.mapped=1 for Wayland windows (the
wWindowMap call in wManageWindow is guarded by if(wwin->frame)
which is NULL in Wayland, leaving mapped=0 and causing wSetFocusTo
to take the no-focus branch immediately).
2. screen.c: call screen_create_internals in the Wayland goto path;
this was skipped by goto screen_done but is needed to set
auto_focus=1 and clear initial keyboard focus via wlr_seat.
3. wl_backend.c: implement wl_screen_create_internals (sets
no_focus_win=WNATIVE_NONE, auto_focus=1, clears seat focus);
wl_focus_set now calls wlr_seat_keyboard_clear_focus and logs
"focus_clear" when win==WNATIVE_NONE; remove the redundant direct
wl_focus_set call from handle_toplevel_map since wManageWindow now
handles focus via wSetFocusTo.
Smoke test: add check 20 verifying "focus_clear" is logged after the
last managed window unmaps.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
wScreenInit skips wWorkspaceNew (which calls wDockCreate, an X11
operation) via goto screen_done. This left workspace_count=0, causing
a divide-by-zero in wManageWindow when a window carries saved state
(workspace % scr->workspace_count). Allocate a minimal WWorkspace
directly before the goto so the Wayland path always has exactly one
workspace.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add display_default_screen, atom_intern, and event_loop_run vtable slots.
Guard all X11-only paths in startup.c/screen.c/shutdown.c/event.c/xdnd.c
with if (!dpy) so the Wayland path reaches wl_display_run() and exits
cleanly (exit 0) on SIGTERM. wl-smoke-test.sh now PASSES.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>