Audit: every "X11 in src/" hit outside src/backend/x11/ and
src/backend/wayland/ is now either:
- a comment mentioning X11 by name, or
- a backend-neutral macro/type alias (WM_STATE_*, CW*, P*, etc.)
whose numeric value happens to match the X11 protocol value.
Zero <X11/...> includes in shared headers/sources.
Zero X11 type uses (XColor/XContext/XEvent/XFontStruct/XGCValues/
XWindowAttributes/XSetWindowAttributes/XErrorEvent etc.).
Zero X11 symbol references in compiled shared object files
(verified: `nm src/*.o | awk '$1=="U"' | grep '^X[A-Z][a-z]'`
returns empty).
Real architectural fixes:
src/backend/backend_types.h — added the missing backend-neutral
constants/types so shared code never names an X11 macro:
- WM_STATE_WITHDRAWN/NORMAL/ICONIC (ICCCM values 0/1/3).
- WContextID (typedef int) — XContext analogue.
- WMColorRGB (XColor-layout-compatible struct).
- CWX..CWStackMode (ConfigureWindow value-mask bits).
- ForgetGravity..StaticGravity (ICCCM win_gravity values).
- PMinSize..PWinGravity (XSizeHints flags) as WNH_* aliases.
- NoSymbol, NoEventMask, ColormapInstalled/Uninstalled.
- BitmapSuccess..BitmapNoMemory.
All guarded by #ifndef so the X11 backend's <X11/X.h> include
overrides them with the real X11 values when present.
src/screen.h — w_visual is now `void *` (was `Visual *`). Added
w_visual_id / w_visual_class so dialog.c's crash panel can read
visual info without dereferencing a Visual struct. tech_draw_font
is also `void *` with companion tech_draw_font_ascent/descent ints
populated by the backend (X11 from XFontStruct->ascent, Wayland
from a hard-coded bitmap-font metric).
src/WindowMaker.h — XContext fields → WContextID, X11 includes
removed, Time → WMNativeTime.
src/dialog.c — wShowCrashingDialogPanel now uses WMOpenScreen +
WMScreenWidth/Height instead of DefaultScreen()/ScreenOfDisplay()/
WidthOfScreen() so it works in either backend.
Dead-code cleanup found while auditing:
src/event.c — handleUnmapNotify and handleEnterNotify both built
an uninitialized `XEvent ev` and ran it through x11_translate_event
on a peeked queue event. The translation always read stack garbage
(the local was never populated). Replaced with the correct flow:
- unmap handler: skip wUnmanageWindow if a Destroy is already
queued, the Destroy handler will run it next iteration.
- enter handler: skip if a Leave for the same window is queued,
no need to inspect mode/detail (was always reading garbage).
Also dropped the now-unused x11_compat.h / x11_event.h includes
from event.c, dock.c, window.c.
src/misc.c — eatExpose's `XEvent event, foo` were never used; the
function delegates to wm_backend->event_flush_type(WME_EXPOSE).
src/wsmap.c — workspace_map_destroy built an XEvent ClientMessage
but never sent it; the actual notify path is switchpanel_send_enter.
Pass the real root_win argument (was passing literal 0) and drop
the dead XEvent.
src/icon.c — set_dockapp_in_icon's `XWindowAttributes attr` and
cycleColor's `XGCValues gcv` were unused.
src/window.c — windowLanguageClick had a function-signature
mismatch with framewin.h's on_click_language (XEvent* vs WMEvent*).
The framewin code passes a WMEvent. Fixed the parameter type and
its single use of event->xbutton.button.
src/moveres.c — already-disabled `#if 0` block in showPosition
that called XDrawLine / XSetForeground on the root window: removed.
Replaced tech_draw_font->ascent/descent dereferences with the new
flat int fields.
src/xutil.h — removed declarations of FormatXError (moved to X11
backend long ago) and Request/GetSelection (never implemented).
Mass renames in shared src/:
IconicState/NormalState/WithdrawnState → WM_STATE_ICONIC/NORMAL/
WITHDRAWN
IconWindowHint/InputHint/StateHint/IconPixmapHint/IconMaskHint/
IconPositionHint/WindowGroupHint/UrgencyHint
→ WMH_*_HINT
XColor (in struct fields and locals) → WMColorRGB
XContext (in screen.context.{...}) → WContextID
XPoint → WMShortPoint
XRectangle → WMShortRect
XFontStruct * → void *
Backends translate at the boundary:
src/backend/x11/x11_backend.c keeps its native XColor/XContext/
XFontStruct internally and casts to the backend-neutral types
at the public-API surface (memcpy works because WMColorRGB has
XColor's exact layout).
src/backend/wayland/wl_backend.c populates the same fields
directly without any X11 indirection.
Verified:
Default build: `Window Maker 0.96.0` runs.
Shared src/ object files: `nm | grep '^X[A-Z][a-z]'` is empty.
All shared X11 macro names (CW*, P*, ICCCM hint flags) are
defined locally in backend_types.h, no X11 dep needed.
Out of scope (separate refactor): wmaker compositor binary itself
still links libX11 because src/backend/x11/* and the XWayland
integration in src/backend/wayland/wl_backend.c need real X11
types. Both are below the vtable, so shared code is unaffected.
WINGs API surgery, step 1.
New public header WINGs/WINGs/wnative.h declares WINGs-native types
and constants with no X11 header dependency:
- WMNativePixmap/Atom/Cursor/Keysym/Time/XID/Colormap/Bool typedefs
(all 'unsigned long' — compatible with the existing wire ABI).
- WM_MOD_SHIFT/LOCK/CONTROL/MOD{1..5} modifier mask bits.
- WM_BUTTON{1..5}_MASK pointer button mask bits.
- WM_ANY_MODIFIER/WM_ANY_BUTTON sentinels.
- WM_EVMASK_* event-mask bits (forthcoming patches).
- WM_NOTIFY_* crossing modes/details.
- WM_PROPERTY_* / WM_MAPPING_* / WM_VISIBILITY_* / WM_GRAB_* /
WM_REVERT_TO_* / WM_CURRENT_TIME / WM_NATIVE_NONE.
Numeric values intentionally match X11 layout for binary
compatibility with WMEvent fields (which were defined that way
originally). The architectural property that matters is that NONE
of the symbol *names* below are X11 macros — they belong to WINGs
and are defined without any X11 header.
WMEvent.h, WUtil.h, WINGs.h now #include <WINGs/wnative.h> so every
WINGs consumer picks up the new constants. X11 headers are still
included from the public WINGs headers; phase ε will drop them.
Phase α.1 — first sed pass:
ShiftMask → WM_MOD_SHIFT
ControlMask → WM_MOD_CONTROL
LockMask → WM_MOD_LOCK
Mod{1..5}Mask → WM_MOD_MOD{1..5}
Button{1..5}Mask → WM_BUTTON{1..5}_MASK
AnyModifier → WM_ANY_MODIFIER
AnyButton → WM_ANY_BUTTON
Applied across WINGs/, src/, WPrefs.app/ via sed with word
boundaries. Build verified clean; binary identical in size,
re-linked successfully.
xmodifier.c contained x_reset_modifier_mapping which walked the X
server's modifier map via XGetModifierMapping / XFreeModifiermap to
discover the X11 modifier indices for Meta/Hyper/Super/Alt keysyms.
This was 4 direct Xlib calls in shared src/.
Refactor:
src/xmodifier.c — now only holds the modifier-mask state and the
portable wXModifierFromKey / wXModifierToShortcut
Label / wSetModifierMasks helpers used by shared
policy code. No more Xlib symbols.
src/backend/x11/x11_backend.c — owns x11_reset_modifier_mapping,
called from x11_extensions_init. Calls
wSetModifierMasks at the end so shared code
answers modifier lookups correctly.
src/xmodifier.h — drops wXModifierInitialize. Wayland never needed
it; X11 calls the local x11_reset_modifier_mapping
directly.
The unused ModeMask static was dropped along the way.
Set a default XKB keymap on the headless keyboard device in
wl_display_open() so the keyboard has a keycode↔keysym mapping
available from startup.
Implement wl_keysym_to_keycode() by scanning the XKB keymap for the
first keycode that produces the given keysym; XKB keycodes equal
evdev+8 == X11 keycodes, so wKeyBindings are directly compatible.
Implement wl_keysym_from_keycode() as the reverse lookup.
Call wSetModifierMasks(Mod1Mask, Mod1Mask, Mod4Mask, 0) from
wl_screen_create_internals() so AltMask/MetaMask/SuperMask are
non-zero in Wayland mode, making modifier parsing in wXModifierFromKey
produce correct values.
Add wSetModifierMasks() to xmodifier.c/h as the non-X11 entry point.
Replace the four XKeysymToKeycode(dpy, ksym) call sites in
defaults.c, rootmenu.c, and usermenu.c with
wm_backend->keysym_to_keycode() so they work when dpy==NULL.
Smoke test: check for "XKB keymap set on headless keyboard" log line.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>