36 KiB
Wayland Port — Concrete Action Plan
Correlated with WAYLAND_ROADMAP.md phases and the abstraction leak analysis.
How to Read This Plan
Each task is mechanical: it names the exact file(s), the exact Xlib calls or X11 types to eliminate, and the exact replacement mechanism. Tasks are grouped by roadmap phase and ordered by dependency.
Task format:
- ID:
{Phase}.{Number} - File(s): exact source files
- Operation: what to do
- Xlib calls eliminated: count
- Blocked by: prerequisite tasks
Wave 1 Complete (2026-05-18)
All 8 signature change tasks completed (changes since commit 9943c05):
| Task | Description | Status |
|---|---|---|
| A5.1 | wSwitchPanelHandleEvent: XEvent* → WMEvent* |
✅ |
| A5.2 | Remove XEvent synthesis in cycling.c |
✅ |
| B.3 | wDockReceiveDNDDrop: XEvent* → WMEvent* |
✅ |
| E.3 | wRootMenuPerformShortcut: XEvent* → WMEvent* |
✅ |
| E.4 | wClientConfigure/wClientCheckProperty: X11 types → WMEvent* |
✅ |
| R.1 | framewin.c: _x11_raw → WMEvent |
✅ |
| R.2 | icon.c: _x11_raw → WMEvent |
✅ |
| R.3 | menu.c: _x11_raw → WMEvent |
✅ |
Results:
_x11_rawsites insrc/: 16 → 9 (7 eliminated in policy code)- Build verified clean (no new warnings, no regressions)
- Crash regression (use-after-free on modal dialog close) fixed:
W_IsValidView()validates stale_view_targetagainstview_tableat fetch boundary inwevent_wl.c, plus defense-in-depth inwview.candwevent.c- Scene graph cleanup:
wl_destroy()callsW_ViewDestroyBackingFn→wl_view_destroy_backing_impl()to destroywlr_scene_nodeandwlr_buffer_dropwhen WINGs toplevels close
Wave 2 Complete (2026-05-18)
All 4 mechanical elimination tasks completed (changes since commit 0950b22):
| Task | Description | Status |
|---|---|---|
| A4.1 | workspace.c: remove 5 USE_XINERAMA guards |
✅ |
| B.1 | appicon.c: XClearArea → wm_backend->window_clear |
✅ |
| R.5 | usermenu.c: XStringToKeysym → xkb_keysym_from_name, XSendEvent → dpy guard |
✅ |
| R.7 | window.c: remove 4 USE_XSHAPE guards |
✅ |
Results:
_x11_rawsites insrc/: 9 → 9 (no new _x11_raw; these tasks eliminated X11 calls, not _x11_raw)- Build verified clean (no new warnings, no regressions)
- C.1 skipped: XOR rubber-band drawing in
moveres.cis inside#if 0— dead code, no action needed
Bug Fixes
Native XDG client rendering fix (commit 8d963e7)
Problem: Native XDG clients (e.g. foot terminal, gedit) would render once on initial map but never re-render on buffer commits. The compositor received wl_surface.commit events but did not schedule output frame refreshes.
Root cause: surface_commit_listener in wl_backend.c was registered but did not call wlr_output_schedule_frame(). Without this call, the compositor never redrew the output after the initial frame.
Fix: The surface_commit_listener callback now calls wlr_output_schedule_frame() on every buffer commit, ensuring the compositor redraws the output and picks up the new buffer content.
Phase F: wrlib Wayland Integration
Do this first — other phases depend on wrlib working without X11.
DONE F.1 Remove gratuitous #include <X11/Xlib.h> from pure files
#include <X11/Xlib.h> from pure files- Files:
wrlib/color.c,wrlib/convolve.c,wrlib/flip.c,wrlib/load.c,wrlib/load_ppm.c,wrlib/misc.c,wrlib/raster.c,wrlib/rotate.c,wrlib/save.c,wrlib/scale.c - Operation: Each file includes
X11/Xlib.hbut makes zero Xlib calls. They get it transitively via#include "wraster.h". The include is inwraster.h.initself (line 47), so these files can't avoid it without changing the public header. Two options:- (a) Guard the X11 includes in
wraster.h.inwith#ifndef WRLIB_NO_X11and define that in Wayland builds, OR - (b) Accept the transitive include (it's a type definition header, not a link dependency) and move on.
- (a) Guard the X11 includes in
- Recommendation: Option (b) — this is cosmetic. Skip and move to substantive tasks.
- Xlib calls eliminated: 0 (cosmetic only)
F.2 Verify RCreateContextWayland() completeness ✅
RCreateContextWayland() completenessStatus: DONE — all fields verified correct, no issues.
- File:
wrlib/context.c:725-775 - Operation: Read
RCreateContextWayland(). Verify it sets all fields thatRConvertImageand image loaders need:depth,vclass,red_offset,green_offset,blue_offset,black,white,convert_image,convert_image_mask. Verifydpy,cmap,copy_gc,visual,drawableare NULL/0. - Test: Call
RCreateContextWayland(1920, 1080, NULL), thenRLoadImage(ctx, "test.png", 0), thenRConvertImage(ctx, img, &pixmap). Confirm the pixmap is apixman_image_t*cast toPixmap. - Blocked by: nothing
F.3 Verify wl_convert_image / wl_convert_image_mask ✅
wl_convert_image / wl_convert_image_maskStatus: DONE — RGBA→ARGB32 conversion correct, alpha handling correct, no bugs.
- File:
wrlib/convert_wl.c(58 lines) - Operation: Read the implementation. Verify RGBA→ARGB32 byte order conversion is correct. Verify alpha channel handling for
RRGBFormat(no alpha) vsRRGBAFormat. Verify the returnedPixmapis(Pixmap)(uintptr_t)pixman_image_t*. - Test: Load a PNG with alpha, convert, verify pixel values in the pixman image.
- Blocked by: F.2
F.4 Verify image format loaders are X11-independent ✅
Status: DONE — all 7 loaders verified X11-independent, zero dpy/cmap/visual references.
- Files:
wrlib/load_png.c,wrlib/load_jpeg.c,wrlib/load_gif.c,wrlib/load_tiff.c,wrlib/load_webp.c,wrlib/load_ppm.c,wrlib/load_xpm_normalized.c - Operation: Confirm each loader takes
RContext*only for error reporting (or not at all) and returnsRImage*without touchingctx->dpy. Grep each file for->dpy,->cmap,->visual. - Expected result: All clean except
load_xpm.c(usesXParseColor). - Blocked by: nothing
F.5 Provide Wayland-safe XPM loading path ✅
Status: DONE — already wired up at load.c:199-204 — ctx->dpy==NULL check dispatches to RLoadXPMNormalized.
- File:
wrlib/load_xpm.c(180 lines) — usesXParseColorfor color name→RGB - Operation:
load_xpm_normalized.c(459 lines) already exists as a pure-C XPM parser that doesn't need X11. Verify thatRLoadImage()inwrlib/load.cdispatches toload_xpm_normalized.cwhenctx->dpy == NULL. If not, add a check:if (ctx->dpy == NULL) return RLoadXPMNormalized(ctx, file); else return RLoadXPM(ctx, file); - Xlib calls eliminated: 2 (in the Wayland path)
- Blocked by: F.2
Phase F Summary
All five Phase F tasks verified — the wrlib Wayland integration path is complete with zero code changes required:
| Task | Result |
|---|---|
| F.1 | Gratuitous #include <X11/Xlib.h> in 10 pure files — cosmetic only, accepted per option (b). |
| F.2 | RCreateContextWayland() — all fields verified correct. depth=32, TrueColor, RGBA offsets, black/white, convert function pointers all set. dpy/cmap/visual/drawable NULL'd. |
| F.3 | wl_convert_image / wl_convert_image_mask — RGBA→ARGB32 byte order correct, alpha handling correct for both RRGBFormat and RRGBAFormat, mask thresholding with stride-aware indexing, Pixmap cast idiomatic. No bugs. |
| F.4 | All 7 image format loaders verified X11-independent — zero references to ->dpy, ->cmap, ->visual. |
| F.5 | Wayland-safe XPM loading already wired at load.c:199-204 — dpy == NULL check dispatches to RLoadXPMNormalized (pure-C parser) vs RLoadXPM (X11/XParseColor). |
Key architecture point: wrlib's convert_image function pointer (context->convert_image) is the single abstraction seam — set to wl_convert_image by RCreateContextWayland() and x11_convert_image by RCreateContext(). Everything else is either pure image manipulation (portable) or hardcoded X11 (xutil.c, xpixmap.c, convert_x11.c) that is dead code on the Wayland path.
Phase A: Core Window Management Gaps
A4: Workspace Switching
A4.1 Eliminate USE_XINERAMA guards in workspace.c ✅
USE_XINERAMA guards in workspace.c- File:
src/workspace.c— 5#ifdef USE_XINERAMAsites (lines 252, 280, 295, 303, 328) - Operation: Each guard selects between per-monitor and whole-screen geometry for workspace name display. The monitor geometry should come from
WScreenfields (already populated by the backend), not from Xinerama calls. For each site:- Read the
#ifdef USE_XINERAMAblock and the#elseblock - Replace both with code that reads
wGetHeadForPointerLocation(scr)or equivalent backend-neutral monitor query (these functions already exist and are backend-abstracted) - Delete the
#ifdef
- Read the
- Xlib calls eliminated: 0 (these are compile-time guards, not direct Xlib calls; the Xinerama calls are in the backend)
- Blocked by: nothing
A5: Alt-Tab Window Cycling
A5.1 Change wSwitchPanelHandleEvent signature from XEvent* to WMEvent* ✅
wSwitchPanelHandleEvent signature from XEvent* to WMEvent*- Files:
src/switchpanel.c:684,src/switchpanel.h:33 - Operation:
- Change function signature from
WWindow *wSwitchPanelHandleEvent(WSwitchPanel *panel, XEvent *event)toWWindow *wSwitchPanelHandleEvent(WSwitchPanel *panel, WMEvent *event) - Inside the function, replace all
event->xmotion.xfield accesses withevent->u.motion.x(the backend-neutral WMEvent fields) - Replace all
event->xbutton.buttonwithevent->u.button.button, etc. - Replace
event->type == MotionNotifywithevent->type == WME_MOTION, etc.
- Change function signature from
- Blocked by: nothing
A5.2 Remove XEvent synthesis in cycling.c ✅
cycling.c- File:
src/cycling.c:227-259 - Operation: After A5.1, the
wSwitchPanelHandleEventtakesWMEvent*. Delete the entire XEvent synthesis block (lines 227-259) and replace with:
Pass thetmp = wSwitchPanelHandleEvent(swpanel, &ev);WMEvent evdirectly instead of synthesizing anXEvent. - Xlib calls eliminated: 5 (XEvent type references)
- Blocked by: A5.1
Phase B: Dock & App Icons
B.1 Eliminate XClearArea in appicon.c ✅
XClearArea in appicon.c- File:
src/appicon.c:371 - Operation: Replace
XClearArea(dpy, dicon->icon->core->window, 2, 2, 50, ...)withwm_backend->window_clear_area(dicon->icon->core->window, 2, 2, 50, ...)orwm_backend->frame_paint(...)to trigger a repaint. Check if awindow_clear_areavtable slot exists; if not, useframe_painton the icon's frame. - Xlib calls eliminated: 1
- Blocked by: nothing
B.2 Eliminate USE_DOCK_XDND guards in appicon.c
- File:
src/appicon.c— 4 sites (lines 52, 131, 315, 338) - Operation: The XDND setup and handling code is X11-specific. It should be moved behind a vtable slot:
- Lines 52, 131: Move
#include "xdnd.h"andwXDNDMakeAwareness()call into the X11 backend'sappicon_showimplementation - Lines 315, 338: The DND event handling in
iconDblClick/iconMouseDownshould dispatch throughwm_backend->xdnd_process_client_message(already exists) - Remove all
#ifdef USE_DOCK_XDNDfromappicon.c
- Lines 52, 131: Move
- Xlib calls eliminated: 0 (guards only; actual Xlib calls are in
xdnd.c) - Blocked by: nothing
B.3 Change wDockReceiveDNDDrop signature from XEvent* to WMEvent* ✅
wDockReceiveDNDDrop signature from XEvent* to WMEvent*- Files:
src/dock.c:2009,src/dock.h:97 - Operation: Same pattern as A5.1. Change
int wDockReceiveDNDDrop(WScreen *scr, XEvent *event)to takeWMEvent*. Update the single call site inevent.c:782to pass theWMEventinstead of casting_x11_raw. - Xlib calls eliminated: 1
_x11_rawaccess inevent.c - Blocked by: nothing
Phase C: Visual Polish & Animations
C.1 Eliminate XOR rubber-band drawing in moveres.c ⏭️ (inside #if 0 — dead code, skip)
moveres.c- File:
src/moveres.c— 6 Xlib calls (lines 145-151) - Operation: Replace
XSetForeground+XDrawLinecalls withwm_backend->overlay_draw_line()vtable calls (slot exists atbackend.h:797):
Do this for all 4// Before: XSetForeground(dpy, lgc, scr->line_pixel); XDrawLine(dpy, scr->root_win, lgc, 0, y-1, scr->scr_width, y-1); // After: wm_backend->overlay_draw_line(scr, 0, y-1, scr->scr_width, y-1);XDrawLinecalls and theXSetForeground. - Xlib calls eliminated: 6
- Blocked by: nothing (vtable slots exist, X11 backend implements them as XDrawLine, Wayland backend implements as pixman overlay)
C.3 Verify balloon tooltip vtable slots
- Files:
src/backend/backend.h(line 1772:balloon_show),src/balloon.c - Operation: Confirm
balloon_show/balloon_hidevtable slots exist and are called fromballoon.c. Confirmballoon.chas zero direct Xlib calls (our analysis showed 0). No action needed if clean. - Blocked by: nothing
Phase D: WINGs Widget Porting
Ordered by dependency and impact.
D.1 Route widgets.c screen init through backends
- File:
WINGs/widgets.c— 35 Xlib calls - Operation: The screen initialization code (lines 568-739) creates GCs, cursors, stipple pixmaps, and interns atoms using raw Xlib. This code runs on both backends but should only run on X11. Split into two parts:
- Lines 568-571:
XOpenDisplay— already handled (WINGs init takes aDisplay*or NULL) - Lines 637-739: GC creation, cursor creation, modifier mapping, atom interning. Wrap this entire block in:
The Wayland path skips GC/cursor creation (handled byif (scrPtr->display != NULL) { // X11 path // existing code }wrender_wl.candwview_wl.c). The modifier mapping should usexkb_keymapon Wayland (already inwevent_wl.c). - Lines 735-739:
XInternAtoms— move to aviewBackend->platform_init()call (slot exists atbackend.hline 621, already called atwidgets.c:832)
- Lines 568-571:
- Xlib calls eliminated: 35
- Blocked by: nothing
D.2 Route wwindow.c ICCCM properties through vtable
- File:
WINGs/wwindow.c— 41 Xlib calls - Operation: Every Xlib call sets ICCCM window properties (
WM_NAME,WM_ICON_NAME,WM_PROTOCOLS,WM_NORMAL_HINTS,WM_CLASS,WM_HINTS,_NET_WM_ICON, transient-for). These are X11-only concepts. For each function:WMSetWindowTitle(line 155): Wrap theXmbTextListToTextProperty+XSetWMName+XChangePropertyblock inif (scr->display). On Wayland, setxdg_toplevel_set_titlevia a newviewBackend->set_title(view, title)slot.WMSetWindowMiniwindowTitle(line 176): Same pattern,viewBackend->set_icon_title(view, title).WMSetWindowMiniwindowImage(line 230):XChangePropertyfor_NET_WM_ICON. Wrap inif (scr->display). No Wayland equivalent needed (compositor owns icons).WMSetWindowCloseAction/WMSetWindowMaximized(lines 260-285):XGetWMProtocols/XSetWMProtocols. Wrap inif (scr->display).setWindowGeometry(line 318):XAllocSizeHints/XSetWMNormalHints. Wrap inif (scr->display).WMRealizeWindow(lines 415-464):XAllocClassHint/XSetClassHint/XAllocWMHints/XSetWMHints/XSetWMProtocols/XSetTransientForHint. Wrap inif (scr->display).WMSetWindowMiniwindowPixmap(line 572):XGetWMHints/XSetWMHints. Wrap inif (scr->display).WMCloseWindow(line 618):XWithdrawWindow. Replace withviewBackend->unmap(vctx, view).
- Xlib calls eliminated: 41
- Blocked by: nothing
D.3 Move winputmethod.c behind a backend vtable
- File:
WINGs/winputmethod.c— 40 Xlib calls - Operation: The entire file is XIM/XIC lifecycle management — purely X11. On Wayland, input methods use
zwp_text_input_v3. Create two files:- Rename
winputmethod.c→winputmethod_x11.c - Create
winputmethod_wl.cwith stub implementations (orzwp_text_input_v3if needed now) - Create
winputmethod.cas a thin dispatch layer that callsscr->imBackend->*()or usesif (scr->display)guards - Update
Makefile.amto compile all three
- Rename
- Xlib calls eliminated: 40 (moved to
_x11.c) - Blocked by: nothing
D.4 Move wballoon.c drawing through render backend
- File:
WINGs/wballoon.c— 28 Xlib calls - Operation: The balloon drawing code uses
XFillArc,XFillRectangle,XFillPolygon,XSetForeground,XCreateGCto draw shaped tooltips. Replace each withrenderBackend->fill_arc(),renderBackend->fill_rect(),renderBackend->fill_polygon()calls. The render backend vtable already has these slots.XTranslateCoordinates(line 182): Replace withviewBackend->get_screen_position()(slot exists).USE_XSHAPEguards (2 sites): Move shape extension calls intoviewBackendor wrap inif (scr->display).
- Xlib calls eliminated: 28
- Blocked by: nothing
D.5 Move selection.c behind a backend vtable
- File:
WINGs/selection.c— 21 Xlib calls - Operation: The entire file implements X11 selection protocol (
XConvertSelection,XGetWindowProperty,XChangeProperty,XSendEvent,XSetSelectionOwner). On Wayland, clipboard useswl_data_device. Create:- Rename
selection.c→selection_x11.c - Create
selection_wl.cwithwl_data_deviceimplementation (or stubs) - Create
selection.cdispatch layer - Update
Makefile.am
- Rename
- Xlib calls eliminated: 21 (moved to
_x11.c) - Blocked by: nothing
D.6 Move DND subsystem behind a backend vtable
- Files:
WINGs/dragsource.c(45 calls),WINGs/dragdestination.c(37 calls),WINGs/dragcommon.c(16 calls) — 98 total - Operation: The entire XDND protocol implementation is X11-only. On Wayland, DnD uses
wl_data_devicefor cross-client and compositor-internal mechanisms for WINGs↔WINGs.- Rename all three to
*_x11.c - Create
dragsource_wl.c,dragdestination_wl.c,dragcommon_wl.c(stubs initially) - Create thin dispatch files or add a
W_DnDBackendvtable toWINGsP.h.in - Update
Makefile.am
- Rename all three to
- Xlib calls eliminated: 98 (moved to
_x11.c) - Blocked by: nothing
D.7 Route wcolorpanel.c through render/view backends
- File:
WINGs/wcolorpanel.c— 89 Xlib calls - Operation: The color panel does raw pixmap manipulation (XCreatePixmap, XCopyArea, XGetImage, XGetPixel, XPutPixel, XPutImage), pointer grabs (XGrabPointer, XUngrabPointer, XQueryPointer), and cursor manipulation (XRecolorCursor, XCreatePixmapCursor). Replace systematically:
- Pixmap ops (XCreatePixmap, XCopyArea, XFreePixmap, XFillRectangle — ~44 calls): Replace with
renderBackend->pixmap_create(),renderBackend->pixmap_copy(),renderBackend->pixmap_free(),renderBackend->fill_rect(). - Image capture (XGetImage, XGetPixel, XPutPixel, XSubImage, XPutImage, XDestroyImage — ~15 calls): Replace with
renderBackendimage access functions or wrlibRImageoperations. - Pointer grabs (XGrabPointer, XUngrabPointer, XQueryPointer — ~6 calls): Replace with
viewBackendpointer grab functions. - Cursor (XRecolorCursor, XCreatePixmapCursor, XFreeCursor — ~4 calls): Replace with
viewBackend->set_cursor(). - Event polling (XPending, XPeekEvent, XNextEvent, XCheckTypedEvent, XFlush — ~6 calls): Replace with
eventBackendfunctions. USE_XSHAPEguards (6 sites): Move shape calls intoviewBackendor guard withif (scr->display).
- Pixmap ops (XCreatePixmap, XCopyArea, XFreePixmap, XFillRectangle — ~44 calls): Replace with
- Xlib calls eliminated: 89
- Blocked by: D.1 (needs render backend working)
D.8 Route wtext.c clipboard and grabs through backends
- File:
WINGs/wtext.c— 23 Xlib calls - Operation:
- Clipboard (
XFetchBuffer,XStoreBuffer,XFree— 6 calls): Replace with WINGs selection API (which will be backend-split after D.5). - Pointer grabs (
XGrabPointer,XUngrabPointer— 4 calls): Replace withviewBackendpointer grab. - Misc (
XBell— 2 calls): Replace withviewBackend->bell()or no-op. - Drawing (
XCreateGC,XCreateBitmapFromData,XChangeWindowAttributes,XSetWindowAttributes,XMapWindow,XInternAtom,XFlush— 9 calls): Route through render/view backends. XRectangletype (2 uses): Replace withWMRect.
- Clipboard (
- Xlib calls eliminated: 23
- Blocked by: D.5 (clipboard)
D.9 Route wtextfield.c clipboard and grabs through backends
- File:
WINGs/wtextfield.c— 10 Xlib calls - Operation: Same categories as D.8 but smaller:
- Clipboard (
XFetchBuffer,XStoreBuffer,XFree): Use WINGs selection API - Grabs (
XGrabPointer,XUngrabPointer): UseviewBackend - Bell (
XBell): UseviewBackend->bell()or no-op - Drawing (
XDrawRectangle,XInternAtom,XFlush): UserenderBackend
- Clipboard (
- Xlib calls eliminated: 10
- Blocked by: D.5
D.10 Route wpopupbutton.c grabs through view backend
- File:
WINGs/wpopupbutton.c— 7 Xlib calls - Operation: Replace
XGrabPointer/XUngrabPointer/XFlushwithviewBackendpointer grab calls. - Xlib calls eliminated: 7
- Blocked by: nothing
D.11 Route wappresource.c property reads through backend
- File:
WINGs/wappresource.c— 15 Xlib calls - Operation: Replace
XGetWindowProperty/XFree/XInternAtomcalls withviewBackendproperty functions or guard withif (scr->display). These read app icon properties — on Wayland, icons come fromxdg_toplevelor desktop files. - Xlib calls eliminated: 15
- Blocked by: nothing
D.12 Route wmisc.c coordinate translation through view backend
- File:
WINGs/wmisc.c— 2 Xlib calls - Operation: Replace
XTranslateCoordinateswithviewBackend->get_screen_position(). - Xlib calls eliminated: 2
- Blocked by: nothing
Phase E: Dialogs & Panels
E.1 Eliminate _x11_raw in winspector.c
- File:
src/winspector.c:1038 - Operation: The
_x11_rawcast is used to get anXEvent*for some event handling. Replace withWMEventfield access (same pattern as A5.1). - Xlib calls eliminated: 1
_x11_rawaccess - Blocked by: nothing
E.2 Eliminate _x11_raw accesses in event.c
-
File:
src/event.c— 16_x11_rawsites -
Operation: Systematic elimination, one site at a time:
Line(s) Context Replacement 249, 264, 269, 276 handleConfigureRequest— passes raw XEvent to backend for RandR/Shape/XKBAlready dispatches through wm_backend->event_randr_update()andwm_backend->event_handle_extensions(). The_x11_rawis the argument to these vtable calls. Change vtable signatures to acceptWMEvent*instead ofvoid*, and have the X11 backend extract_x11_rawinternally.431 handleMapRequest— raw XEvent forwManageWindowCheck if wManageWindowactually needs the raw event or just the window ID (fromevent->u.mapRequest.window). If just the ID, pass that.446-447 handleExtensions— passes raw event to backendAlready a vtable call. Change vtable to accept WMEvent*.782 handleButtonPress— raw XEvent forwDockReceiveDNDDropEliminated by task B.3. 831, 834, 852, 857 handleClientMessage— raw XEvent for EWMH, XDND, selectionAlready dispatched through wm_backend->netwm_process_client_message()andwm_backend->xdnd_process_client_message(). Change vtable signatures to acceptWMEvent*.971, 974 handleClientMessage— sameSame as above. 993 handleClientMessage— colormap installChange vtable call to accept WMEvent*.1354 handleKeyPress— raw XEvent for root menu shortcutsTask E.3 below. -
Xlib calls eliminated: 16
_x11_rawaccesses -
Blocked by: B.3, E.3
E.3 Change wRootMenuPerformShortcut from XEvent* to WMEvent* ✅
wRootMenuPerformShortcut from XEvent* to WMEvent*- Files:
src/rootmenu.c:320,src/rootmenu.h:25 - Operation: Change signature from
Bool wRootMenuPerformShortcut(XEvent *event)toBool wRootMenuPerformShortcut(WMEvent *event). Update internals to useevent->u.key.*fields instead ofevent->xkey.*. - Blocked by: nothing
E.4 Eliminate X11 types in client.c function signatures ✅
client.c function signatures- Files:
src/client.c:119,247,src/client.h:27,31 - Operation:
wClientConfigure(WWindow *wwin, XConfigureRequestEvent *xcre)→ change parameter toWMEvent *eventand extract fields fromevent->u.configureRequest.*wClientCheckProperty(WWindow *wwin, XPropertyEvent *event)→ change parameter toWMEvent *eventand extract fromevent->u.property.*- Update all call sites (in
event.c)
- Xlib calls eliminated: 3 (XWindowChanges usage inside, plus signature cleanup)
- Blocked by: nothing
E.5 Port WPrefs.app drawing through WINGs render backend
-
Files:
WPrefs.app/Appearance.c(67 calls),WPrefs.app/editmenu.c(37),WPrefs.app/Menu.c(24),WPrefs.app/TexturePanel.c(14),WPrefs.app/HotCornerShortcuts.c(11),WPrefs.app/KeyboardShortcuts.c(12),WPrefs.app/MouseSettings.c(6),WPrefs.app/WPrefs.c(7),WPrefs.app/main.c(4),WPrefs.app/double.c(2),WPrefs.app/Paths.c(1),WPrefs.app/xmodifier.c(12) -
Operation: WPrefs.app is a WINGs client. All its Xlib calls should go through WINGs APIs:
Sub-task Files Calls Replacement E.5a: Replace XCopyArea/XFillRectangle/XDrawLine/XDrawRectangle/XFillPolygon/XDrawLineswithWMDrawLine,WMFillRectangle,WMCopyArea(WINGs drawing API, routed throughrenderBackend)Appearance.c,Menu.c,TexturePanel.c,HotCornerShortcuts.c,double.c,Paths.c,KeyboardShortcuts.c120 WINGs render API E.5b: Replace XCreatePixmap/XFreePixmapwithWMCreatePixmap/WMReleasePixmapAppearance.c,HotCornerShortcuts.c,TexturePanel.c16 WINGs pixmap API E.5c: Replace XCreateGC/XFreeGCwith WINGs managed GCs or remove (render backend handles GCs internally)Appearance.c,Menu.c6 Remove; use WINGs color GCs E.5d: Replace XGrabKeyboard/XUngrabKeyboardwith WINGs keyboard grab API (needs creation or backend call)KeyboardShortcuts.c,Menu.c4 New WINGs API or viewBackendE.5e: Replace XGrabPointer/XUngrabPointer/XQueryPointer/XTranslateCoordinateswith WINGs pointer APIeditmenu.c12 viewBackendpointer opsE.5f: Replace XGetModifierMapping/XKeysymToKeycode/XKeysymToStringwith xkbcommon equivalents or WINGs APIKeyboardShortcuts.c,MouseSettings.c,xmodifier.c18 xkbcommon or WINGs key API E.5g: Replace XParseColorwith WINGsWMCreateNamedColorAppearance.c,TexturePanel.c3 WINGs color API E.5h: Replace XSendEvent/XInternAtom(WM reload command) with WINGs or backend-neutral mechanismWPrefs.c3 Write to defaults file + signal E.5i: Replace XOpenDisplayinmain.cwith WINGs init (already takes display)main.c4 WINGs WMOpenScreenE.5j: Replace XChangePointerControl/XGetPointerControlwith backend call or libinputMouseSettings.c2 Backend-specific or defer E.5k: Replace XRecolorCursor/XMoveWindow/XClearWindow/XSetWMNormalHintsetc. ineditmenu.ceditmenu.c15 WINGs view/window API -
Xlib calls eliminated: 197 total
-
Blocked by: D.1 through D.10 (WINGs backends must work first)
Phase G: Session & Persistence
G.1 Verify session.c is X11-free
- File:
src/session.c - Operation: Our analysis showed 0 Xlib calls. Confirm by grep. No action needed.
- Blocked by: nothing
G.2 Verify defaults.c XColor usage
- File:
src/defaults.c— 20 Xlib references (allXColortype for color parsing) - Operation: The
XColorreferences are for parsing color names from the defaults database. These should usewm_backend->color_parse_name()or equivalent vtable slot. Check if a vtable slot exists for color name→RGB conversion. If so, replace theXColor+XParseColorcalls. If not, add one. - Xlib calls eliminated: 20
- Blocked by: nothing
Phase I: EWMH / Foreign Toplevel
I.1 Assess wmspec.c — no action needed for Wayland
- File:
src/wmspec.c— 65 Xlib calls - Operation: EWMH (
_NET_WM_*) is an X11-only protocol. On Wayland, the equivalent iswlr_foreign_toplevel_management_v1(already advertised by wlroots). The 65 Xlib calls inwmspec.care correct — they implement EWMH for X11 clients. They should NOT be eliminated; they should be guarded so they only execute for X11/XWayland clients. - Check: Verify that
wmspec.cfunctions are only called from code paths that have an X11 client (XWayland surface). Theif (!dpy || !wwin->frame)guard at line 2000 suggests some guarding exists. Verify completeness. - Xlib calls eliminated: 0 (these are correct for X11 path)
- Blocked by: nothing
I.2 Assess xdnd.c — no action needed for Wayland
- File:
src/xdnd.c— 33 Xlib calls - Operation: Same as I.1. XDND is X11-only. On Wayland, DnD uses
wl_data_device(handled by wlroots). Thexdnd.ccode is correct for XWayland clients. Verify it's only called from X11 code paths. - Blocked by: nothing
Phase H: Advanced Compositor Features
H.1 Eliminate USE_XINERAMA guards in src/ policy files
- Files:
src/actions.c:975,src/wmspec.c(6 sites),src/workspace.c(5 sites — covered in A4.1) - Operation: Same pattern as A4.1. Replace Xinerama-specific monitor queries with backend-neutral
wGetHeadForPoint()/wGetUsableAreaForHead()calls. These functions already exist and are backend-abstracted (the backend populatesWScreenhead geometry). - Xlib calls eliminated: 0 (compile-time guards)
- Blocked by: nothing
H.5 Verify clipboard works via wlroots
- Operation: wlroots implements
wl_data_deviceandzwp_primary_selection_v1. Verify copy/paste works between native Wayland clients and between XWayland clients. No code changes expected. - Blocked by: nothing
Remaining src/ Cleanup (not phase-specific)
R.1 Eliminate _x11_raw in framewin.c ✅
_x11_raw in framewin.c- File:
src/framewin.c:1165 - Operation: The
_x11_rawaccess is in a titlebar click handler. Replace withWMEventfield access. - Blocked by: nothing
R.2 Eliminate _x11_raw in icon.c ✅
_x11_raw in icon.c- File:
src/icon.c:861 - Operation: The
_x11_rawaccess is inminiwindowDblClick. Replace withWMEventfield access. - Blocked by: nothing
R.3 Eliminate _x11_raw in menu.c ✅
_x11_raw in menu.c- File:
src/menu.c:738 - Operation: The
_x11_rawaccess is incheck_key. Replace withWMEventfield access for key handling. - Blocked by: nothing
R.4 Eliminate X11 types in misc.c
- File:
src/misc.c— 8 Xlib calls (XKeysymToKeycode,XLookupString,DefaultRootWindow) - Operation: Replace with
wm_backend->keysym_to_keycode()(vtable slot exists) andwm_backend->key_lookup_string()(may need new slot). - Blocked by: nothing
R.5 Eliminate X11 in usermenu.c ✅
usermenu.c- File:
src/usermenu.c— 4 Xlib calls (XSendEvent,XStringToKeysym) - Operation: Replace
XSendEventwithwm_backend->client_send_key_event()or equivalent vtable slot. ReplaceXStringToKeysymwithxkb_keysym_from_name()(libxkbcommon, already linked). - Blocked by: nothing
R.6 Move xmodifier.c behind backend
- File:
src/xmodifier.c— 11 Xlib calls - Operation: This file detects keyboard modifier mappings. On Wayland, modifiers come from
xkb_keymap. The X11 path should remain for X11 backend. Guard the entire file withif (dpy)or move tobackend/x11/. - Blocked by: nothing
R.7 Eliminate USE_XSHAPE guards in window.c ✅
USE_XSHAPE guards in window.c- File:
src/window.c— 4#ifdef USE_XSHAPEsites - Operation: Shape extension queries should be behind the backend. Move
XShapeQueryExtentscalls intowm_backend->window_get_shape()or similar vtable slot. The X11 backend implements it; the Wayland backend returns "no shape" (Wayland surfaces handle their own shape via alpha). - Blocked by: nothing
R.8 Eliminate XKB_BUTTON_HINT guards
- Files:
src/framewin.c(22 sites),src/window.c(10),src/wdefaults.c(3),src/framewin.h(10),src/window.h(1),src/WindowMaker.h(1),src/def_pixmaps.h(1),src/dialog.c(2),src/winspector.c(1) — 51 sites total - Operation: The language button feature is controlled by a compile-time
#ifdef. This is not a backend concern — it's a feature toggle. Two options:- (a) Make it always-on (remove
#ifdef, keep the code) - (b) Make it a runtime preference (remove
#ifdef, addwPreferences.show_language_buttoncheck) - (c) Leave as-is (it's not blocking Wayland)
- (a) Make it always-on (remove
- Recommendation: Option (c) — this is orthogonal to Wayland porting. Skip.
R.9 Eliminate KEEP_XKB_LOCK_STATUS guards
- Files:
src/framewin.c(2),src/event.c(1),src/window.c(1),src/WindowMaker.h(2),src/framewin.h(1),src/keybind.h(1) — 8 sites - Operation: Same as R.8 — feature toggle, not backend concern. Skip.
R.10 Eliminate HAVE_INOTIFY guards
- Files:
src/main.c(3),src/event.c(1),src/shutdown.c(2),src/WindowMaker.h(1) — 7 sites - Operation: Inotify is Linux-specific, not X11-specific. Works on Wayland too. No action needed.
Execution Order Summary
IMMEDIATE (unblocks everything else):
~~F.2 Verify RCreateContextWayland~~ ✅
~~F.3 Verify wl_convert_image~~ ✅
~~F.4 Verify image loaders~~ ✅
~~F.5 Wayland-safe XPM loading~~ ✅
WAVE 1 (independent, no prerequisites):
~~A4.1 workspace.c USE_XINERAMA → backend-neutral~~ ✅
A5.1 ~~switchpanel.c XEvent* → WMEvent*~~ ✅
~~B.1 appicon.c XClearArea → vtable~~ ✅
B.2 appicon.c USE_DOCK_XDND → backend
B.3 ~~dock.c/h XEvent* → WMEvent*~~ ✅
~~C.1 moveres.c XDrawLine → overlay vtable~~ ⏭️ (inside `#if 0` — dead code, skip)
D.1 widgets.c screen init → backend guard
D.3 winputmethod.c → _x11/_wl split
D.5 selection.c → _x11/_wl split
D.6 DND subsystem → _x11/_wl split
D.10 wpopupbutton.c grabs → viewBackend
D.11 wappresource.c props → backend guard
D.12 wmisc.c coords → viewBackend
E.3 ~~rootmenu.c XEvent* → WMEvent*~~ ✅
E.4 ~~client.c X11 types → WMEvent*~~ ✅
R.1 ~~framewin.c _x11_raw → WMEvent~~ ✅
R.2 ~~icon.c _x11_raw → WMEvent~~ ✅
R.3 ~~menu.c _x11_raw → WMEvent~~ ✅
R.4 misc.c Xlib → vtable
~~R.5 usermenu.c Xlib → vtable~~ ✅
R.6 xmodifier.c → backend guard
~~R.7 window.c USE_XSHAPE → vtable~~ ✅
G.2 defaults.c XColor → vtable
I.1 wmspec.c — verify X11-only paths
I.2 xdnd.c — verify X11-only paths
WAVE 2 (depends on Wave 1):
A5.2 ~~cycling.c XEvent synthesis → delete~~ ✅
D.2 wwindow.c ICCCM → viewBackend
D.4 wballoon.c drawing → renderBackend
D.7 wcolorpanel.c → renderBackend/viewBackend
D.8 wtext.c clipboard/grabs → backends
D.9 wtextfield.c clipboard/grabs → backends
E.1 winspector.c _x11_raw → WMEvent
E.2 event.c _x11_raw elimination (all 16 sites)
WAVE 3 (depends on Wave 2):
E.5 WPrefs.app full port (197 calls)
VERIFY (can happen anytime):
C.3 balloon vtable slots
~~F.2-F.4~~ wrlib Wayland path ✅
G.1 session.c clean
H.1 USE_XINERAMA policy cleanup
H.5 clipboard via wlroots
Scorecard
| Category | Xlib calls to eliminate | Tasks |
|---|---|---|
src/ _x11_raw escapes |
16 | E.2, R.1-R.3, E.1 |
src/ X11 function signatures |
~15 | A5.1, B.3, E.3, E.4 |
src/ direct Xlib calls |
~50 | C.1, R.4, R.5, R.6, G.2, B.1 |
src/ compile-time guards |
~25 sites | A4.1, B.2, R.7, H.1 |
WINGs/ non-split Xlib calls |
412 | D.1-D.12 |
WPrefs.app/ Xlib calls |
197 | E.5 |
wrlib/ verification |
0 ✅ (all done) | |
wmlib/ |
9 | Not addressed (too small; keep for X11 or drop) |
| Total | ~700 | ~45 tasks |