windowmaker-wl/BACKEND_ABSTRACTION.md

1339 lines
66 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Backend-Specific Branches Remaining in `src/` Policy Code
> **Status (2026-05-28, final):** This document was written during the initial
> abstraction analysis and has been superseded by ROADMAP.md. All X11 isolation
> work described below has been completed:
>
> - `wmspec.c` and `xdnd.c` moved to `src/backend/x11/` — done
> - `_x11_raw` references eliminated from `src/` policy code — done
> - **WINGs widget library**: All 412+ direct Xlib calls isolated to `_x11.c`
> backend files with Wayland stubs in `wstubs_no_x11.c` — done
>
> The counts below are **historical** and reflect the state before the refactoring.
> See ROADMAP.md for the current state.
The backend vtable (`wm_backend->*()`) handles most display-system dispatch, but significant X11-specific code still lives directly in the policy files. Here's every category.
---
## 1. Compile-Time `#ifdef` Branches
### `USE_WAYLAND_BACKEND` (2 sites)
| File | Line | Purpose |
|---|---|---|
| `main.c` | 60 | `#include` wayland backend header |
| `main.c` | 771 | Select `wl_backend` vs `x11_backend` vtable |
This is clean — it's the backend selection switch.
### `XKB_BUTTON_HINT` (38 sites — the biggest offender)
Sprayed across the frame window and window management code. Adds a "language indicator" button to the titlebar.
| File | Sites | What it guards |
|---|---|---|
| `framewin.c` | **22** | Language button creation, layout, drawing, click handling, destroy |
| `framewin.h` | **10** | Language button fields in `WFrameWindow` struct, function prototypes |
| `window.c` | **10** | Language button setup during window manage/unmanage, attribute updates |
| `wdefaults.c` | 3 | Language button in per-window attribute defaults |
| `WindowMaker.h` | 1 | `WBUT_XKBGROUP*` button constants, `PRED_BPIXMAPS` count |
| `window.h` | 1 | `language_button` field in `WWindow` |
| `def_pixmaps.h` | 1 | Language button pixmap data |
| `dialog.c` | 2 | Feature reporting in info dialog |
| `winspector.c` | 1 | Window inspector language option |
### `KEEP_XKB_LOCK_STATUS` (6 sites)
| File | Line(s) | What it guards |
|---|---|---|
| `framewin.c` | 23, 86 | XKB include, language state tracking in frame |
| `framewin.h` | 93 | `languagemode` / `last_languagemode` fields |
| `event.c` | 1853 | XKB state-change event handling |
| `window.c` | 1727 | XKB lock status update on focus |
| `WindowMaker.h` | 359, 622 | XKB state in preferences, XKB event base in globals |
| `keybind.h` | 161 | `WKBD_TOGGLE` keybinding |
### `USE_DOCK_XDND` (7 sites)
| File | Line(s) | What it guards |
|---|---|---|
| `appicon.c` | 52, 131, 315, 338 | XDND include, DND-aware setup, DND event handling on app icons |
| `dock.c` | 76 | XDND include |
| `event.c` | (via backend) | XDND client message dispatch |
| `dialog.c` | 1433 | Feature reporting |
Plus `xdnd.c` itself (312 lines) is **entirely X11-specific** — raw `XInternAtom`, `XGetWindowProperty`, `XSendEvent`, `XGetSelectionOwner` throughout.
### `USE_XSHAPE` (4 sites + headers)
| File | Line(s) | What it guards |
|---|---|---|
| `window.c` | 654, 2012, 2236, 2301 | Shape extension queries on client windows |
| `window.h` | 263, 345 | `net_has_shape` flag, shape update prototype |
| `WindowMaker.h` | 615 | Shape event base in globals |
| `balloon.h` | 26 | `SHAPED_BALLOON` for shaped tooltip windows |
### `USE_XINERAMA` (10 sites)
| File | Line(s) | What it guards |
|---|---|---|
| `workspace.c` | 252, 280, 295, 303, 328 | Per-monitor workspace geometry calculations |
| `wmspec.c` | 78, 165, 294, 1043, 1087, 1820 | EWMH multi-monitor strut/workarea handling |
| `actions.c` | 975 | Maximize to monitor bounds |
| `dialog.c` | 1445, 1447 | Feature reporting, Solaris Xinerama variant |
### `USE_RANDR` (1 site + header)
| File | Line(s) | What it guards |
|---|---|---|
| `dialog.c` | 1458 | Feature reporting |
| `WindowMaker.h` | 629 | RandR event base in globals |
### `USE_MWM_HINTS` (2 sites)
| File | Line(s) | What it guards |
|---|---|---|
| `window.c` | 63, 360 | Motif WM hints include and processing |
| `dialog.c` | 1429 | Feature reporting |
### `HAVE_INOTIFY` (6 sites)
| File | Line(s) | What it guards |
|---|---|---|
| `main.c` | 23, 487, 787 | Inotify includes, setup, watch creation |
| `event.c` | 25 | Inotify includes |
| `shutdown.c` | 61, 91 | Inotify fd cleanup |
| `WindowMaker.h` | 553 | Inotify fd in globals |
### Minor `HAVE_*` guards
| Guard | File | Purpose |
|---|---|---|
| `HAVE_SETSID` | `main.c:326,378`, `dock.c:3000` | `setsid()` availability |
| `HAVE_MALLOC_H` | `dialog.c:39` | Include path |
| `HAVE_XINTERNATOMS` | `wmspec.c:662` | Batch atom intern optimization |
| `HAVE_STDNORETURN` | `event.h:28`, `main.h:27` | C11 `_Noreturn` |
---
## 2. Runtime `_x11_raw` Escape Hatch (16 sites — NOW ZERO in policy code)
The `WMEvent` struct carries a `void *_x11_raw` field — a pointer to the original `XEvent`. Policy code reaches through it when the abstracted event fields aren't sufficient:
| File | Line(s) | What it does |
|---|---|---|
| `event.c` | 249, 264, 269, 276 | `handleConfigureRequest` — passes raw XEvent to backend for RandR, Shape, XKB extension events |
| `event.c` | 431 | `handleMapRequest` — raw XEvent for `wManageWindow` |
| `event.c` | 446–447 | `handleExtensions` — passes raw event to backend |
| `event.c` | 782 | `handleButtonPress` — raw XEvent for `wDockReceiveDNDDrop` |
| `event.c` | 831, 834, 852, 857 | `handleClientMessage` — raw XEvent for EWMH, XDND, selection |
| `event.c` | 971, 974 | `handleClientMessage` — raw XEvent to `netwm_process_client_message`, `xdnd_process_client_message` |
| `event.c` | 993 | `handleClientMessage` — raw XEvent for colormap install |
| `event.c` | 1354 | `handleKeyPress` — raw XEvent for root menu shortcuts |
| `framewin.c` | 1165 | Frame titlebar click — raw XEvent |
| `icon.c` | 861 | Miniwindow double-click — raw XEvent |
| `cycling.c` | 227–234 | Window cycling — synthesizes XEvent for switch panel, with Wayland fallback |
| `menu.c` | 738 | Menu key handling — raw XEvent |
| `winspector.c` | 1038 | Window inspector — raw XEvent |
---
## 3. X11 Types in Function Signatures
Functions in policy code that take raw X11 types as parameters — these are API boundaries that can't work on Wayland without the `_x11_raw` escape hatch or a cast:
| File | Function | X11 parameter type |
|---|---|---|
| `client.c:119` | `wClientConfigure()` | `XConfigureRequestEvent *` |
| `client.c:247` | `wClientCheckProperty()` | `XPropertyEvent *` |
| `rootmenu.c:320` | `wRootMenuPerformShortcut()` | `XEvent *` |
| `switchpanel.c:684` | `wSwitchPanelHandleEvent()` | `XEvent *` |
| `dock.c:1978` | `findDock()` | `XEvent *` |
| `dock.c:2009` | `wDockReceiveDNDDrop()` | `XEvent *` |
| `icon.c:57` | `miniwindowDblClick()` | `XEvent *` |
| `menu.c:677` | `check_key()` | `XKeyEvent *` |
| `window.c:90` | `windowLanguageClick()` | `XEvent *` |
| `wmspec.c:1701` | `wNETWMProcessClientMessage()` | `XClientMessageEvent *` |
| `event.c:94–95` | `handle_selection_request/clear()` | `XSelectionRequestEvent/ClearEvent *` |
---
## 4. Direct Xlib Calls in Policy Code (by file)
Files that call Xlib functions directly instead of going through `wm_backend`:
| File | Call count | What's leaking |
|---|---|---|
| **`wmspec.c`** | **65** | `XGetWindowProperty`, `XChangeProperty`, `XDeleteProperty`, `XInternAtom(s)`, `XFlush` — the entire EWMH implementation is raw Xlib |
| **`xdnd.c`** | **33** | `XInternAtom`, `XGetWindowProperty`, `XSendEvent`, `XGetSelectionOwner`, `XFree` — 100% X11 |
| **`event.c`** | **26** | `XInternAtom`, `XChangeProperty`, selection handling, `DefaultRootWindow` |
| **`defaults.c`** | **20** | `XColor` parsing via `XParseColor`/`XAllocColor` for color preferences |
| **`xmodifier.c`** | **11** | `XGetModifierMapping`, `XFreeModifiermap` — keyboard modifier detection |
| **`misc.c`** | **8** | `XKeysymToKeycode`, `XLookupString`, `DefaultRootWindow` |
| **`moveres.c`** | **6** | `XSetForeground`, `XDrawLine` — XOR rubber-band lines on root window |
| **`menu.c`** | **5** | Debug logging with window IDs |
| **`icon.c`** | **5** | `XWindowAttributes`, `XGetWindowAttributes` |
| **`cycling.c`** | **5** | `XEvent` synthesis for switch panel |
| **`usermenu.c`** | **4** | `XSendEvent`, `XStringToKeysym` — synthetic key events to client |
| **`dock.c`** | **3** | `XEvent` in DND drop handling |
| **`client.c`** | **3** | `XWindowChanges`, `XConfigureRequestEvent` |
| **`appicon.c`** | **1** | `XClearArea` for dock icon label |
---
## 5. X11 Types Embedded in Data Structures
These X11 types are used as field types in core structs, meaning the data model itself is X11-flavored:
| Type | Usage count in `src/*.h` | Where |
|---|---|---|
| `Pixmap` | ~46 | `screen.h`, `texture.h`, `pixmap.h`, `framewin.h` — everywhere pixmaps are stored |
| `GC` | ~10 | `screen.h` (7 GC fields), `texture.h` (6 GC fields), `balloon.h` |
| `XColor` | ~39 (in `.c`) | `defaults.c`, `texture.c`, `resources.c` |
| `Visual *` | ~5 | `framewin.h`, `screen.h` |
| `Colormap` | ~5 | `framewin.h`, `screen.h`, `resources.h` |
| `Atom` | ~96 (in `.c`) | `wmspec.c` (95), `xdnd.c` (19), scattered elsewhere |
| `Cursor` | in `screen.h` | Cursor array in `WScreen` |
---
## Summary: Heat Map
```
Fully Partially Entirely
Abstracted Abstracted X11-Raw
────────── ────────── ────────
wcore.c ██████████
stacking.c ██████████
placement.c ██████████
workspace.c ████████░░ (XINERAMA)
actions.c ████████░░ (XINERAMA)
window.c ██████░░░░ (XKB, SHAPE, MWM)
framewin.c █████░░░░░ (XKB 22 sites, _x11_raw)
event.c ████░░░░░░ (_x11_raw 16 sites, Xlib)
defaults.c ████░░░░░░ (XColor)
cycling.c ███░░░░░░░ (XEvent synthesis)
moveres.c ███░░░░░░░ (XDrawLine)
dock.c ███░░░░░░░ (XEvent, XDND)
icon.c ███░░░░░░░ (XWindowAttributes, _x11_raw)
menu.c ███░░░░░░░ (XKeyEvent, _x11_raw)
client.c ██░░░░░░░░ (X11 event types in API)
wmspec.c ░░░░░░░░░░ ██████████ (65 Xlib calls)
xdnd.c ░░░░░░░░░░ ██████████ (33 Xlib calls)
xmodifier.c ░░░░░░░░░░ ██████████ (11 Xlib calls)
usermenu.c ░░░░░░░░░░ ████████░░ (XSendEvent)
```
**UPDATE (2026-05-26):** All three problems have been resolved:
1. **`wmspec.c`** — moved to `src/backend/x11/wmspec.c`. On Wayland, EWMH vtable slots are no-ops.
2. **`xdnd.c`** — moved to `src/backend/x11/xdnd.c`. Wayland DnD handled by wlroots.
3. **`event.c`'s `_x11_raw` escape hatch** — all 16 sites eliminated from policy code. The remaining `_x11_raw` accesses (15) are exclusively in `src/backend/` where they belong.
---
# wrlib/ — Backend-Specific Branch Inventory
## File Classification
### Entirely X11-Free (pure image manipulation)
These files have **zero** Xlib calls and no X11 type usage. Some `#include <X11/Xlib.h>` transitively through `wraster.h` but don't use it:
| File | LOC | Purpose |
|---|---|---|
| `alpha_combine.c` | 71 | Alpha compositing |
| `draw.c` | 504 | Line/pixel drawing on RImage |
| `gradient.c` | 501 | Gradient rendering |
| `load_gif.c` | 232 | GIF loader |
| `load_jpeg.c` | 196 | JPEG loader |
| `load_magick.c` | 130 | ImageMagick loader |
| `load_png.c` | 220 | PNG loader |
| `load_tiff.c` | 153 | TIFF loader |
| `load_webp.c` | 172 | WebP loader |
| `load_xpm_normalized.c` | 459 | Pure-C XPM parser (no libXpm) |
| `save_jpeg.c` | 104 | JPEG saver |
| `save_png.c` | 127 | PNG saver |
| `save_xpm.c` | 283 | XPM saver |
| **Total** | **3152** | **36% of wrlib — fully portable** |
### Gratuitous X11 Header Includes (no actual Xlib calls)
These files `#include <X11/Xlib.h>` (pulled in transitively via `wraster.h`) but make **zero** Xlib function calls. The include is unnecessary:
| File | LOC | Actual purpose |
|---|---|---|
| `color.c` | 130 | RColor ↔ pixel conversion (uses `RContext` fields only) |
| `convolve.c` | 145 | Image convolution/blur |
| `flip.c` | 163 | Image flip |
| `load.c` | 395 | Format dispatch (calls `RLoadPNG`, etc.) |
| `load_ppm.c` | 394 | PPM loader |
| `misc.c` | 279 | Error strings, format support queries |
| `raster.c` | 640 | `RCreateImage`, `RCloneImage`, `RGetSubImage`, etc. |
| `rotate.c` | 434 | Image rotation |
| `save.c` | 61 | Save format dispatch |
| `scale.c` | 499 | Image scaling |
| **Total** | **3140** | **36% of wrlib — portable code with unnecessary X11 header dep** |
### Genuinely X11-Dependent
| File | LOC | Xlib calls | What it does |
|---|---|---|---|
| `context.c` | 772 | **44** | `RCreateContext()` — the big one. Visual selection, colormap allocation, GC creation, XShm probing. Also contains `RCreateContextWayland()` (the Wayland alternative). |
| `xutil.c` | 263 | **32** | `RCreateXImage`, `RDestroyXImage`, `RGetXImage`, `RPutXImage` — XImage/XShm lifecycle |
| `convert.c` | 985 | **14** | `image2TrueColor`, `image2PseudoColor`, `image2GrayScale`, `image2Bitmap` — RImage→XImage pixel conversion |
| `convert_x11.c` | 96 | **6** | `x11_convert_image`, `x11_convert_image_mask` — XImage→Pixmap via `XCreatePixmap`/`XCopyArea` |
| `xpixmap.c` | 183 | **13** | `RCreateImageFromXImage`, `RCreateImageFromDrawable` — Pixmap/Drawable→RImage extraction |
| `load_xpm.c` | 180 | **2** | `RLoadXPM`, `RGetImageFromXPMData` — uses `libXpm` + `XParseColor` for color resolution |
| **Total** | **2479** | **111** | **28% of wrlib — hard X11 dependency** |
### Wayland Backend
| File | LOC | What it does |
|---|---|---|
| `convert_wl.c` | 58 | `wl_convert_image`, `wl_convert_image_mask` — RImage→`pixman_image_t` (cast to `Pixmap`) |
---
## 1. Compile-Time `#ifdef` Branches
### `USE_XSHM` (10 sites — 2 files)
The XShm (shared memory) extension for fast image transfer to the X server:
| File | Line(s) | What it guards |
|---|---|---|
| `context.c` | 639 | XShm version check, shared pixmap capability probe |
| `xutil.c` | 34, 44, 71, 158, 195, 238, 251 | XShm include, `XShmCreateImage`, `XShmAttach`, `XShmDetach`, `XShmGetImage`, `XShmPutImage`, shared pixmap creation. The entire `RCreateXImage`/`RDestroyXImage` have dual paths (shm vs non-shm). |
| `convert_x11.c` | 16, 43 | Shared pixmap fast path in `x11_convert_image` |
| `xutil.h` | 24 | `R_CreateXImageMappedPixmap` prototype |
### `HAVE_LIBXMU` (2 sites)
| File | Line(s) | What it guards |
|---|---|---|
| `context.c` | 29, 145 | `XmuLookupStandardColormap` — optional shortcut for standard colormap lookup |
### `USE_*` Image Format Guards (16 sites)
All in `load.c`, `save.c`, and `imgformat.h` — these are feature toggles, not backend-specific:
| Guard | Sites | Files |
|---|---|---|
| `USE_TIFF` | 3 | `load.c`, `imgformat.h` |
| `USE_PNG` | 3 | `load.c`, `save.c`, `imgformat.h` |
| `USE_JPEG` | 3 | `load.c`, `save.c`, `imgformat.h` |
| `USE_GIF` | 5 | `load.c`, `load_gif.c`, `imgformat.h` |
| `USE_WEBP` | 2 | `load.c`, `imgformat.h` |
| `USE_MAGICK` | 3 | `load.c`, `load_magick.c`, `misc.c`, `imgformat.h` |
### Minor Guards
| Guard | File | Purpose |
|---|---|---|
| `WRLIB_DEBUG` | `context.c` (4), `convert.c` (6) | Debug logging |
| `HAVE_FLOAT_MATHFUNC` | `context.c:46` | `floorf()` availability |
| `HAVE_STDNORETURN` | `load_jpeg.c:34` | C11 `_Noreturn` |
| `I18N` | `misc.c:248` | Internationalization |
---
## 2. Runtime Backend Dispatch
There is exactly **one** runtime dispatch point — the `convert_image` function pointer in `RContext`:
```c
// wraster.h.in:210-211
int (*convert_image)(struct RContext *ctx, RImage *image, Pixmap *pixmap);
int (*convert_image_mask)(struct RContext *ctx, RImage *image, Pixmap *pixmap, Pixmap *mask, int threshold);
```
Set at context creation time:
- **X11 path** (`context.c:660-661`): `context->convert_image = x11_convert_image`
- **Wayland path** (`context.c:768-769`): `context->convert_image = wl_convert_image`
Called from `convert.c:869,882`:
```c
return context->convert_image(context, image, pixmap);
```
This is the **only** abstraction seam in wrlib. Everything else is either pure image manipulation or hardcoded X11.
---
## 3. X11 Types in the Public API (`wraster.h.in`)
The public header exposes X11 types directly:
| API function | X11 types in signature |
|---|---|
| `RCreateContext()` | `Display *dpy` |
| `RGetClosestXColor()` | `XColor *retColor` |
| `RCreateImageFromXImage()` | `XImage *image, XImage *mask` |
| `RCreateImageFromDrawable()` | `Drawable drawable, Pixmap mask` |
| `RConvertImage()` | `Pixmap *pixmap` (return) |
| `RConvertImageMask()` | `Pixmap *pixmap, Pixmap *mask` (return) |
| `RCreateXImage()` | returns `RXImage *` (wraps `XImage`) |
| `RGetXImage()` | `Drawable d` |
| `RPutXImage()` | `Drawable d, GC gc` |
### `RContext` struct fields that are X11 types
| Field | Type | Used by |
|---|---|---|
| `dpy` | `Display *` | Everything in context.c, xutil.c, xpixmap.c, convert_x11.c, load_xpm.c |
| `cmap` | `Colormap` | context.c (colormap allocation), load_xpm.c (color parsing) |
| `copy_gc` | `GC` | convert_x11.c (pixmap copy) |
| `visual` | `Visual *` | context.c (visual selection), xutil.c (XImage creation) |
| `drawable` | `Window` | convert_x11.c (XCreatePixmap root window) |
| `colors` | `XColor *` | context.c (PseudoColor palette) |
### `RXImage` struct — entirely X11
```c
// wraster.h.in:265-268
XImage *image;
// USE_XSHM:
XShmSegmentInfo info;
```
---
## 4. Direct Xlib Calls by File
| File | Calls | Functions used |
|---|---|---|
| **`context.c`** | **44** | `XAllocColor`, `XQueryColors`, `XInternAtom`, `XGetRGBColormaps`, `XAllocStandardColormap`, `XFree`, `XCreateColormap`, `XGetVisualInfo`, `XCreateWindow`, `XCreateGC`, `XFreeGC`, `XDestroyWindow`, `XShmQueryVersion`, `XShmPixmapFormat`, `XSetWindowAttributes` |
| **`xutil.c`** | **32** | `XCreateImage`, `XDestroyImage`, `XShmCreateImage`, `XShmAttach`, `XShmDetach`, `XShmGetImage`, `XShmPutImage`, `XSync`, `XSetErrorHandler`, `XGetGeometry`, `XGetImage`, `XPutImage`, `XCreatePixmap`, `XFreePixmap` |
| **`convert.c`** | **14** | `RCreateXImage`, `RDestroyXImage` (wrlib wrappers, but they call Xlib internally) |
| **`xpixmap.c`** | **13** | `XGetPixel`, `XGetGeometry`, `XGetImage`, `XDestroyImage` |
| **`convert_x11.c`** | **6** | `XCreatePixmap`, `XCopyArea`, `XFreePixmap`, `XCreateGC`, `XFreeGC`, `RPutXImage` |
| **`load_xpm.c`** | **2** | `XParseColor` (color name→RGB), `XpmCreateXpmImageFromData`, `XpmReadFileToXpmImage`, `XpmFreeXpmImage` (libXpm, not Xlib proper) |
---
## 5. Summary: Heat Map
```
Pure Gratuitous Genuinely
Portable X11 Header X11-Dependent
────────── ────────── ────────
alpha_combine.c ██████████
draw.c ██████████
gradient.c ██████████
load_gif.c ██████████
load_jpeg.c ██████████
load_magick.c ██████████
load_png.c ██████████
load_tiff.c ██████████
load_webp.c ██████████
load_xpm_normalized.c ██████████
save_jpeg.c ██████████
save_png.c ██████████
save_xpm.c ██████████
convert_wl.c ██████████ (Wayland backend)
color.c ██████████
convolve.c ██████████
flip.c ██████████
load.c ██████████
load_ppm.c ██████████
misc.c ██████████
raster.c ██████████
rotate.c ██████████
save.c ██████████
scale.c ██████████
load_xpm.c ████████░░ (libXpm + XParseColor)
convert.c ██████████ (RXImage converters)
convert_x11.c ██████████ (X11 convert backend)
xpixmap.c ██████████ (Drawable→RImage)
xutil.c ██████████ (XImage/XShm lifecycle)
context.c ██████████ (RContext creation, 44 calls)
```
**By the numbers:**
| Category | Files | LOC | % of wrlib |
|---|---|---|---|
| Fully portable | 14 | 3210 | 36% |
| Portable but needlessly includes `X11/Xlib.h` | 10 | 3140 | 36% |
| Genuinely X11-dependent | 6 | 2479 | 28% |
**The Wayland story in wrlib is already partially told.** The `convert_image` function pointer dispatch and `RCreateContextWayland()` exist, and `convert_wl.c` provides the pixman-based conversion path. What remains X11-bound:
1. **`context.c`** — `RCreateContext()` (525 lines of X11 visual/colormap setup) vs `RCreateContextWayland()` (45 lines). The X11 path is 10× larger but they're already separate functions.
2. **`xutil.c` + `xpixmap.c`** — the entire `RXImage` abstraction is X11-only. On Wayland, these are dead code (the `wl_convert_image` path never touches `RXImage`).
3. **`convert.c`** — the `image2TrueColor`/`image2PseudoColor`/etc. converters produce `RXImage` (X11). On Wayland, they're bypassed entirely by the function pointer dispatch.
4. **`load_xpm.c`** — uses `libXpm` and `XParseColor`. The alternative `load_xpm_normalized.c` is a pure-C XPM parser that doesn't need X11 (already exists as the Wayland-compatible path).
5. **The public API** — `wraster.h` exposes `Display *`, `Pixmap`, `Drawable`, `GC`, `XImage`, `XColor` in function signatures. On Wayland, `Pixmap` is reused as a `uintptr_t` cast of `pixman_image_t *` — a type pun, not a real abstraction.
---
# wmlib/ — Backend-Specific Branch Inventory
wmlib is tiny — 481 lines of C across 4 files, plus 2 headers (238 lines). It's a client-side helper library that lets external applications communicate with the WindowMaker WM via X11 properties and client messages. **It is 100% X11.**
## File Map
| File | LOC | Purpose | Xlib calls |
|---|---|---|---|
| `command.c` | 75 | Send WM commands (hide app, hide others, set GNUstep attributes) via `XSendEvent` + `XChangeProperty` | **5** |
| `event.c` | 87 | Process incoming `_WINDOWMAKER_MENU` client messages from the WM | **1** |
| `menu.c` | 239 | Build menu tree in memory, serialize to X text property via `XSetTextProperty` | **3** |
| `app.c` | 80 | Application context (`WMAppContext`) — stores `Display *`, main window, window list | **0** (stores X11 types, doesn't call Xlib) |
| `WMaker.h` | 162 | Public API header | — |
| `app.h` | 41 | Private `wmAppContext` struct | — |
| `menu.h` | 76 | Private `wmMenu`/`wmMenuEntry` structs | — |
## 1. Compile-Time `#ifdef` Branches
**None.** Zero `#ifdef` guards of any kind (beyond header include guards and `__cplusplus`). No conditional compilation, no feature toggles, no backend switches.
## 2. Runtime Backend Dispatch
**None.** No function pointers, no vtables, no `is_wayland` checks.
## 3. X11 Types in the Public API (`WMaker.h`)
Every public function takes X11 types:
| Function | X11 types |
|---|---|
| `WMAppCreateWithMain()` | `Display *display`, `Window main_window` |
| `WMAppCreate()` | `Display *display` |
| `WMAppAddWindow()` | `Window window` |
| `WMProcessEvent()` | `XEvent *event` |
| `WMSetWindowAttributes()` | `Display *dpy`, `Window window` |
| `WMMenuAction` callback | `Time timestamp` |
The `GNUstepWMAttributes` struct contains `Pixmap` fields.
## 4. X11 Types in Private Structs
### `wmAppContext` (`app.h`)
```c
Display *dpy;
Window main_window;
Window *windows;
```
### `wmMenuEntry` / `wmMenu` (`menu.h`)
No X11 types — pure C data structures (strings, tags, linked list pointers). The X11 dependency comes only at serialization time.
## 5. Direct Xlib Calls — Complete List
There are only **9** Xlib calls in the entire library:
| File | Line | Call | Purpose |
|---|---|---|---|
| `command.c:31` | `XInternAtom(dpy, "_WINDOWMAKER_WM_FUNCTION", False)` | Get the WM command atom |
| `command.c:47` | `XSendEvent(...)` | Send "hide application" command to WM |
| `command.c:62` | `XSendEvent(...)` | Send "hide others" command to WM |
| `command.c:70` | `XInternAtom(dpy, "_GNUSTEP_WM_ATTR", False)` | Get the GNUstep attributes atom |
| `command.c:71` | `XChangeProperty(...)` | Set GNUstep WM attributes on a window |
| `event.c:76` | `XInternAtom(app->dpy, "_WINDOWMAKER_MENU", False)` | Get the menu event atom |
| `menu.c:199` | `XInternAtom(dpy, WMMENU_PROPNAME, False)` | Get the menu property atom |
| `menu.c:226` | `XStringListToTextProperty(...)` | Serialize menu string list |
| `menu.c:232` | `XSetTextProperty(...)` | Write serialized menu to window property |
Plus one `XFree()` call (`menu.c:234`).
## 6. Communication Protocol
The library implements a simple IPC protocol built entirely on X11 mechanisms:
- **App → WM**: `XSendEvent` with `ClientMessage` type `_WINDOWMAKER_WM_FUNCTION` to the root window
- **App → WM (menus)**: `XSetTextProperty` writes a serialized menu tree to `_WINDOWMAKER_MENU` on the app's main window
- **WM → App**: `ClientMessage` events with type `_WINDOWMAKER_MENU` carrying a menu item tag
## Summary
```
Pure X11-Dependent
Portable
────────── ──────────
app.c (data only) ████░░░░░░ (stores Display*/Window)
menu.c (data + serial) ░░░░░░░░░░ ██████████ (XSetTextProperty)
command.c ░░░░░░░░░░ ██████████ (XSendEvent, XChangeProperty)
event.c ░░░░░░░░░░ ██████████ (XInternAtom, ClientMessage)
WMaker.h ░░░░░░░░░░ ██████████ (Display, Window, Pixmap, XEvent, Time)
```
**wmlib is entirely X11.** There is no abstraction layer, no backend dispatch, no Wayland path, and no compile-time guards. The entire library is a thin wrapper around X11 client messages and properties for the GNUstep/WindowMaker protocol.
For a Wayland port, wmlib would either need to be:
1. **Replaced** with a Wayland-native protocol (e.g., a custom `wl_protocol` extension), or
2. **Kept as-is** for XWayland clients only, with a parallel Wayland-native equivalent, or
3. **Dropped** — its functionality (app hide/show, WM-managed menus) could be subsumed into the compositor's own protocol.
Given its size (481 lines of C, 9 Xlib calls), any of these options is straightforward.
---
# util/ — Backend-Specific Branch Inventory
util/ contains **15 standalone CLI programs** (7336 LOC). They range from fully X11-dependent GUI apps to pure file-manipulation tools with zero display-system dependency.
## File Classification
### Entirely X11-Free (pure file/text manipulation)
| File | LOC | Purpose | X11 calls |
|---|---|---|---|
| `convertfonts.c` | 167 | Convert old WM font config to new format | **0** |
| `fontconv.c` | 200 | XLFD font name conversion helpers | **0** |
| `wdread.c` | 110 | Read a key from the WM defaults database | **0** |
| `wdwrite.c` | 114 | Write a key to the WM defaults database | **0** |
| `getstyle.c` | 418 | Export style/theme from WM defaults to file | **0** |
| `geticonset.c` | 124 | Export icon set from WM defaults to file | **0** |
| `seticons.c` | 129 | Import icon set into WM defaults | **0** |
| `wmmenugen.c` | 393 | Generate WM menu from `.desktop` files (PropList output) | **0** |
| `wmmenugen_misc.c` | 172 | Menu generator helpers (terminal detection) | **0** |
| `wmmenugen_parse_xdg.c` | 737 | XDG `.desktop` file parser | **0** |
| `wmmenugen_parse_wmconfig.c` | 297 | wmconfig file parser | **0** |
| `wmgenmenu.c` | 519 | Another menu generator (hardcoded menu templates) | **0**¹ |
| **Total** | **3380** | | |
¹ `wmgenmenu.c` has the string "XTerm" as a menu item label — no actual Xlib call.
### X11-Dependent GUI Applications
| File | LOC | Xlib calls | Purpose |
|---|---|---|---|
| `wmiv.c` + `wmiv.h` | 1020 + 1279 | **60** | Image viewer — full X11 window, event loop, keyboard handling |
| `wmsetbg.c` | 1444 | **53** | Set desktop background — pixmap creation, root window manipulation |
| `wmagnify.c` | 491 | **20** | Screen magnifier — `XGetImage` from root, WINGs GUI |
| `wxpaste.c` | 232 | **18** | Paste from X selection/clipboard |
| `wxcopy.c` | 246 | **12** | Copy to X cut buffers/selection |
| `setstyle.c` | 523 | **10** | Import style into WM defaults + send reload command via `XSendEvent` |
| **Total** | **3956** (excl. `wmiv.h`) | **173** | |
---
## 1. Compile-Time `#ifdef` Branches
### Backend/Extension Guards
| Guard | File | Sites | What it guards |
|---|---|---|---|
| `USE_XINERAMA` | `wmsetbg.c` | **7** | Xinerama include, `XineramaQueryScreens`, per-head background stretching, `--xinerama` CLI flag |
| `USE_XPM` | `wmiv.c` | **4** | XPM icon loading for the image viewer window |
| `HAVE_EXIF` | `wmiv.c` | **3** | EXIF orientation auto-rotation |
| `HAVE_PTHREAD` | `wmiv.c` | **5** | Background image preloading thread |
### Portability Guards (not backend-specific)
| Guard | Files | Sites | What it guards |
|---|---|---|---|
| `__GLIBC__` | 8 files | 8 | `#define _GNU_SOURCE` |
| `HAVE_STDNORETURN` | 7 files | 7 | C11 `_Noreturn` |
| `_GNU_SOURCE` | `wmiv.c` | 1 | GNU extensions |
| `HAVE_SYS_SELECT_H` | `wxpaste.c` | 1 | `<sys/select.h>` include |
| `HAVE_LIBINTL_H` + `I18N` | `wmgenmenu.c` | 1 | Gettext |
| `PATH_MAX` | `getstyle.c` | 1 | Fallback definition |
| `DEBUG` | `wmsetbg.c` (6), `wmmenugen.c` (2), `wmmenugen_parse_*.c` (3) | 11 | Debug logging |
---
## 2. Runtime Backend Dispatch
### `_x11_raw` Escape Hatch (1 site)
| File | Line | What it does |
|---|---|---|
| `wmagnify.c` | 314 | `XEvent *xev = (XEvent *)event->_x11_raw` — casts the WINGs event to get the raw `XKeyEvent` for `XLookupString` |
No other runtime backend checks (`is_wayland`, `dpy == NULL`, etc.) in any util file.
---
## 3. X11 Types in Function Signatures / Structs
### `wmsetbg.c`
```c
Display *dpy; // global
Pixmap texture->pixmap; // background storage
XColor color; // color parsing
XRectangle head[]; // Xinerama head geometry
```
### `wmiv.c`
```c
Display *dpy; // global
Window win; // viewer window
XTextProperty title_property; // window title
XClassHint, XSizeHints, XWMHints // window manager hints
XEvent e; // event loop
XKeyEvent event; // synthetic key events
```
### `wmagnify.c`
```c
Display *dpy, *vdpy; // two display connections (magnify from one, draw to other)
XImage *image; // captured screen region
XRectangle rects[]; // magnified pixel rectangles
GC gc; // drawing context
```
### `wxcopy.c` / `wxpaste.c`
```c
Display *dpy; // global
Atom selatom, clipatom; // selection atoms
XEvent ev; // selection events
Window win; // hidden window for selection protocol
```
### `setstyle.c`
```c
Display *dpy; // opened only to send reload command
XEvent ev; // client message
XColor color1, color2; // color validation
```
---
## 4. Direct Xlib Calls — Per File
### `wmiv.c` (60 calls) — Image Viewer
Full X11 application: window creation, event loop, pixmap management.
| Category | Calls |
|---|---|
| Window lifecycle | `XOpenDisplay`, `XCreateSimpleWindow`, `XMapWindow`, `XCloseDisplay`, `XSelectInput` |
| Drawing | `XCopyArea` (×6), `XClearWindow` (×3), `XResizeWindow` (×4), `XFreePixmap` (×3) |
| Window properties | `XSetWMProperties`, `XSetWMName`, `XSetWMProtocols`, `XStringListToTextProperty`, `XAllocClassHint`, `XAllocSizeHints`, `XAllocWMHints` |
| Event loop | `XNextEvent`, `XSendEvent`, `XFlush`, `XSync` |
| EWMH | `XInternAtom` (×2 — `_NET_WM_STATE`, `_NET_WM_STATE_FULLSCREEN`) |
| Input | `XKeysymToKeycode`, `XGetWindowAttributes` |
### `wmsetbg.c` (53 calls) — Background Setter
Root window pixmap manipulation, color allocation, property management.
| Category | Calls |
|---|---|
| Color | `XParseColor` (×7), `XAllocColor` (×2), `XFreeColors` |
| Pixmap | `XCreatePixmap` (×3), `XFreePixmap` (×2), `XCopyArea` (×3), `XSetForeground` (×2), `XFillRectangle` (×2) |
| Root window | `XSetWindowBackground`, `XSetWindowBackgroundPixmap`, `XClearWindow` |
| Properties | `XInternAtom`, `XGetWindowProperty`, `XChangeProperty`, `XDeleteProperty` — `_XROOTPMAP_ID` management |
| Connection | `XOpenDisplay` (×2 — main + `RetainPermanent` trick), `XCloseDisplay`, `XSetCloseDownMode`, `XSync`, `XFlush`, `XSynchronize` |
| Server grab | `XGrabServer`, `XUngrabServer` |
| Error handling | `XSetErrorHandler`, `XKillClient` |
| Xinerama | `XineramaIsActive`, `XineramaQueryScreens`, `XFree` |
### `wmagnify.c` (20 calls) — Screen Magnifier
Captures screen pixels and renders magnified view via WINGs.
| Category | Calls |
|---|---|
| Capture | `XGetImage`, `XDestroyImage`, `XGetPixel`, `XQueryPointer` |
| Drawing | `XCreateGC`, `XSetForeground`, `XFillRectangles` (×3) |
| Connection | `XOpenDisplay` (×2 — main + virtual display), `XMaxRequestSize` |
| Input | `XLookupString` (via `_x11_raw`) |
### `wxpaste.c` (18 calls) — Clipboard Paste
X11 selection protocol client.
| Category | Calls |
|---|---|
| Selection | `XConvertSelection`, `XGetWindowProperty`, `XFetchBuffer` |
| Connection | `XOpenDisplay`, `XCloseDisplay`, `XDisplayName` |
| Window | `XCreateSimpleWindow`, `XSelectInput`, `XStoreName` |
| Events | `XNextEvent`, `XPending`, `XInternAtom` (×2) |
### `wxcopy.c` (12 calls) — Clipboard Copy
X11 cut buffer / selection protocol.
| Category | Calls |
|---|---|
| Buffers | `XStoreBuffer`, `XRotateBuffers`, `XListProperties`, `XSetSelectionOwner` |
| Connection | `XOpenDisplay`, `XCloseDisplay`, `XDisplayName`, `XSetErrorHandler`, `XFlush` |
| Properties | `XFree` |
### `setstyle.c` (10 calls) — Style Importer
Mostly file manipulation; X11 used only for color validation and sending a reload command.
| Category | Calls |
|---|---|
| Color validation | `XParseColor` (×2) — validates color names in the style |
| WM command | `XOpenDisplay`, `XInternAtom` (`_WINDOWMAKER_COMMAND`), `XSendEvent`, `XFlush` |
---
## 5. Summary: Heat Map
```
Pure X11-Dependent
Portable
────────── ──────────
convertfonts.c ██████████
fontconv.c ██████████
wdread.c ██████████
wdwrite.c ██████████
getstyle.c ██████████
geticonset.c ██████████
seticons.c ██████████
wmmenugen.c ██████████
wmmenugen_misc.c ██████████
wmmenugen_parse_xdg.c ██████████
wmmenugen_parse_wmc.. ██████████
wmgenmenu.c ██████████
setstyle.c ██████░░░░ (XParseColor, XSendEvent for reload)
wxcopy.c ░░░░░░░░░░ ██████████ (X cut buffers/selection)
wxpaste.c ░░░░░░░░░░ ██████████ (X selection protocol)
wmagnify.c ░░░░░░░░░░ ██████████ (XGetImage, WINGs GUI)
wmsetbg.c ░░░░░░░░░░ ██████████ (root pixmap, 53 Xlib calls)
wmiv.c ░░░░░░░░░░ ██████████ (full X11 app, 60 Xlib calls)
```
**By the numbers:**
| Category | Files | LOC | % of util |
|---|---|---|---|
| Fully portable (no X11) | 12 | 3380 | 46% |
| Mostly portable (minor X11 for WM command) | 1 (`setstyle.c`) | 523 | 7% |
| Entirely X11-dependent | 5 | 3433 | 47% |
**The five X11-dependent utilities are all standalone GUI programs.** For a Wayland port, each would need either:
1. **`wmsetbg.c`** — Wayland compositors typically own the background; this tool would become a protocol message to the compositor rather than root window pixmap manipulation.
2. **`wmiv.c`** — Full rewrite against Wayland client APIs (or just use WINGs, which already has a Wayland view backend).
3. **`wmagnify.c`** — Already uses WINGs widgets; the X11 dependency is `XGetImage` for screen capture (no Wayland equivalent without a screencopy protocol).
4. **`wxcopy.c` / `wxpaste.c`** — X11 selection protocol → Wayland `wl_data_device` / `zwp_primary_selection_v1`. Completely different protocol, complete rewrite.
The 12 portable utilities (defaults DB tools, menu generators, font converters) work on any platform unchanged.
---
# WINGs/ — Backend-Specific Branch Inventory
WINGs is the largest component at ~40k LOC across 62 `.c` files. It has a well-developed **five-vtable backend abstraction** but significant X11 leakage remains in widget code.
## Architecture: The Five Backend Vtables
WINGs uses runtime vtable dispatch set in `widgets.c:777-812` based on `WMAKER_USE_WAYLAND` env var:
```c
scrPtr->viewBackend = wayland ? &W_ViewBackendWL : &W_ViewBackendX11;
scrPtr->eventBackend = wayland ? &W_EventBackendWL : &W_EventBackendX11;
scrPtr->renderBackend = wayland ? &W_RenderBackendWL : &W_RenderBackendX11;
scrPtr->fontBackend = wayland ? &W_FontBackendWL : &W_FontBackendX11;
scrPtr->colorBackend = wayland ? &W_ColorBackendWL : &W_ColorBackendX11;
```
| Vtable | Slots | X11 impl | Wayland impl |
|---|---|---|---|
| `W_ViewBackend` | 19 (realize, map, unmap, move, resize, raise, lower, reparent, destroy, set_background_color, set_cursor, redisplay, selection, flush…) | `wview_x11.c` (238 LOC) | `wview_wl.c` (368 LOC) |
| `W_EventBackend` | 5 (screen_init, screen_fini, fetch, check_mask, post_dispatch) | `wevent_x11.c` (354 LOC) | `wevent_wl.c` (235 LOC) |
| `W_RenderBackend` | 12 (pixmap_create, pixmap_free, pixmap_copy, draw_line, draw_rect, fill_rect, fill_stippled, composite_pixmap, fill_polygon, fill_arc, create_disabled_mask) | `wrender_x11.c` (175 LOC) | `wrender_wl.c` (279 LOC) |
| `W_FontBackend` | 8 (screen_init, screen_fini, create, destroy, measure, draw_string, draw_image_string, height) | `wfont_x11.c` (212 LOC) | `wfont_wl.c` (235 LOC) |
| `W_ColorBackend` | 5 (screen_init, screen_fini, alloc_color, find_close_color, free_color, parse_named) | `wcolor_x11.c` (130 LOC) | `wcolor_wl.c` (106 LOC) |
**Backend split files total**: X11 = 1109 LOC, Wayland = 1223 LOC.
---
## File Classification
### Fully Portable (zero Xlib calls, zero X11 types)
| File | LOC | Purpose |
|---|---|---|
| `proplist.c` | 1878 | NeXTSTEP property list parser/serializer |
| `wfilepanel.c` | 896 | File open/save panel |
| `wpanel.c` | 847 | Alert/input panels |
| `wscroller.c` | 830 | Scrollbar widget |
| `wfontpanel.c` | 825 | Font chooser panel |
| `wbutton.c` | 755 | Button widget |
| `bagtree.c` | 745 | Balanced tree data structure |
| `userdefaults.c` | 641 | User defaults system |
| `handlers.c` | 566 | Timer/idle handler dispatch |
| `wscrollview.c` | 561 | Scroll container widget |
| `notification.c` | 482 | Notification center |
| `string.c` | 425 | String utilities |
| `hashtable.c` | 422 | Hash table |
| `array.c` | 363 | Dynamic array |
| `wfont.c` | 329 | Font dispatch (delegates to fontBackend) |
| `data.c` | 289 | WMData wrapper |
| `tree.c` | 255 | Tree data structure |
| `wbox.c` | 247 | Box layout widget |
| `wprogressindicator.c` | 243 | Progress bar widget |
| `wframe.c` | 230 | Group box widget |
| `wmenuitem.c` | 226 | Menu item data |
| `memory.c` | 223 | Memory allocation wrappers |
| `wapplication.c` | 216 | Application context |
| `wlabel.c` | 214 | Label widget |
| `wcolor.c` | 187 | Color dispatch (delegates to colorBackend) |
| `configuration.c` | 132 | Configuration file handling |
| `usleep.c` | 26 | Microsecond sleep |
| `wutil.c` | 24 | Misc utilities |
| **+ Wayland backends** | | |
| `wview_wl.c` | 368 | Wayland view backend |
| `wevent_wl.c` | 235 | Wayland event backend |
| `wfont_wl.c` | 235 | Wayland font backend |
| `wrender_wl.c` | 279 | Wayland render backend |
| `wcolor_wl.c` | 106 | Wayland color backend |
| **Total** | **12,474** | **31% of WINGs** |
### X11 Backend Split Files (properly abstracted)
| File | LOC | Xlib calls | Purpose |
|---|---|---|---|
| `wview_x11.c` | 238 | 29 | X11 view lifecycle (XCreateWindow, XMapWindow, etc.) |
| `wrender_x11.c` | 175 | 24 | X11 drawing (XCreatePixmap, XFillRectangle, etc.) |
| `wevent_x11.c` | 354 | 20 | X11 event fetching (XNextEvent, XPending, etc.) |
| `wcolor_x11.c` | 130 | 11 | X11 color allocation (XAllocColor, etc.) |
| `wfont_x11.c` | 212 | 2 | X11 font rendering (Xft) |
| **Total** | **1109** | **86** | **3% of WINGs — properly isolated** |
### Widget Files with Xlib Leakage (should be backend-neutral but aren't)
| File | LOC | Xlib calls | What's leaking |
|---|---|---|---|
| **`wcolorpanel.c`** | 3556 | **89** | `XCreatePixmap`, `XCopyArea`, `XFillRectangle`, `XFreePixmap`, `XGetImage`, `XGetPixel`, `XPutPixel`, `XPutImage`, `XSubImage`, `XDestroyImage`, `XImage`, `XColor`, `XGrabPointer`, `XUngrabPointer`, `XQueryPointer`, `XSetWindowBackgroundPixmap`, `XRecolorCursor`, `XSetForeground`, `XSetClipMask`, `XSetClipOrigin`, `XCreatePixmapCursor`, `XFreeCursor`, `XCreatePixmapFromBitmapData`, `XFlush`, `XPending`, `XPeekEvent`, `XNextEvent`, `XCheckTypedEvent` |
| **`dragsource.c`** | 1179 | **45** | XDND protocol: `XSendEvent`, `XGetWindowProperty`, `XChangeProperty`, `XSetSelectionOwner`, `XConvertSelection`, `XGrabPointer`, `XUngrabPointer`, `XInternAtom`, `XGetInputFocus`, `XQueryTree`, `XTranslateCoordinates`, shape extension |
| **`wwindow.c`** | 712 | **41** | Window properties: `XSetWMName`, `XSetWMProtocols`, `XGetWMProtocols`, `XSetWMHints`, `XGetWMHints`, `XSetWMNormalHints`, `XSetClassHint`, `XSetTransientForHint`, `XChangeProperty`, `XWithdrawWindow`, `XAllocSizeHints`, `XAllocWMHints`, `XAllocClassHint`, `XmbTextListToTextProperty`, `XStoreName`, `XSetIconName`, `XFree` |
| **`winputmethod.c`** | 243 | **40** | XIM/XIC: `XOpenIM`, `XCreateIC`, `XDestroyIC`, `XSetICValues`, `XGetICValues`, `XSetICFocus`, `XUnsetICFocus`, `XSetIMValues`, `XGetIMValues`, `XRegisterIMInstantiateCallback`, `XUnregisterIMInstantiateCallback`, `XVaCreateNestedList`, `XSetInputFocus`, `XLookupString`, `XSelectInput`, `XDisplayKeycodes`, `XGetKeyboardMapping`, `XFree` |
| **`dragdestination.c`** | 999 | **37** | XDND protocol: `XSendEvent`, `XGetWindowProperty`, `XChangeProperty`, `XConvertSelection`, `XInternAtom`, `XTranslateCoordinates` |
| **`widgets.c`** | 1137 | **35** | Screen init: `XOpenDisplay`, `XCreateGC` (×8), `XCreateBitmapFromData`, `XCreatePixmap`, `XCreateFontCursor`, `XCreatePixmapCursor`, `XSetForeground`, `XFillRectangle`, `XFreePixmap`, `XInternAtom(s)`, `XListProperties`, `XStoreBuffer`, `XGetModifierMapping`, `XFreeModifiermap`, `XKeysymToKeycode`, `XDisplayName`, `XColor` |
| **`wballoon.c`** | 476 | **28** | Tooltip drawing: `XFillArc`, `XFillRectangle`, `XFillPolygon`, `XSetForeground`, `XCreateGC`, `XTranslateCoordinates`, shape extension |
| **`wtext.c`** | 3998 | **23** | Rich text: `XBell`, `XFetchBuffer`, `XStoreBuffer`, `XFree`, `XUngrabPointer`, `XGrabPointer`, `XFlush`, `XInternAtom`, `XCreateGC`, `XCreateBitmapFromData`, `XChangeWindowAttributes`, `XSetWindowAttributes`, `XMapWindow`, `XRectangle`, `XEvent` |
| **`selection.c`** | 392 | **21** | X selection protocol: `XConvertSelection`, `XGetWindowProperty`, `XChangeProperty`, `XSendEvent`, `XSetSelectionOwner`, `XGetSelectionOwner`, `XDeleteProperty`, `XInternAtom`, `XFree` |
| **`dragcommon.c`** | 259 | **16** | XDND shared: `XInternAtom`, `XGetWindowProperty`, `XChangeProperty`, `XFree` |
| **`wappresource.c`** | 148 | **15** | App icon: `XGetWindowProperty`, `XFree`, `XInternAtom` |
| **`wtextfield.c`** | 1579 | **10** | Text input: `XBell`, `XFetchBuffer`, `XStoreBuffer`, `XFree`, `XUngrabPointer`, `XGrabPointer`, `XFlush`, `XInternAtom`, `XDrawRectangle` |
| **`wpopupbutton.c`** | 697 | **7** | Popup: `XGrabPointer`, `XUngrabPointer`, `XFlush` |
| **`wruler.c`** | 526 | **3** | Ruler: `XRectangle` type usage |
| **`wmisc.c`** | 351 | **2** | Misc: `XTranslateCoordinates` |
| **Total** | **16,252** | **412** | **41% of WINGs** |
### Utility Files (WUtil sub-library, no X11)
| File | LOC | Purpose |
|---|---|---|
| `menuparser.c` | 652 | Menu file parser |
| `menuparser_macros.c` | 723 | Menu parser macro expansion |
| `findfile.c` | 523 | File path search |
| `error.c` | 147 | Error/warning output |
| `misc.c` | 45 | Misc WUtil helpers |
| **Total** | **2090** | **5% of WINGs** |
---
## 1. Compile-Time `#ifdef` Branches
### Backend/Extension Guards
| Guard | File(s) | Sites | What it guards |
|---|---|---|---|
| `USE_XSHAPE` | `dragsource.c` (2), `wballoon.c` (2), `wcolorpanel.c` (6) | **10** | Shape extension for DND drag icons, balloon tooltips, color picker magnifier |
| `USE_PANGO` | `wfont_x11.c` | **9** | Pango text rendering in X11 font backend |
| `XDND_DEBUG` | `dragsource.c` (4), `dragdestination.c` (3), `dragcommon.c` (3) | **10** | DND protocol debug logging |
| `HAVE_XINTERNATOMS` | `widgets.c` | **1** | Batch atom intern optimization |
| `X_HAVE_UTF8_STRING` | `winputmethod.c` | **1** | `Xutf8LookupString` availability |
| `DOUBLE_BUFFER` | `wmisc.c` (3), `wscroller.c` (8) | **11** | Double-buffered drawing |
### Portability Guards (not backend-specific)
| Guard | File(s) | Sites | What it guards |
|---|---|---|---|
| `HAVE_SYSLOG` / `HAVE_SYSLOG_H` | `error.c`, `misc.c` | 6 | Syslog logging |
| `HAVE_INOTIFY` | `userdefaults.c` | 4 | File change monitoring |
| `USE_BOEHM_GC` | `memory.c` | 6 | Boehm garbage collector |
| `HAVE_SYS_SELECT_H` | `handlers.c` | 1 | `<sys/select.h>` |
| `HAVE_POLL` | `handlers.c` | 1 | `poll()` vs `select()` |
| `HAVE_MKSTEMP` | `proplist.c` | 2 | Secure temp file creation |
| `HAVE_STDNORETURN` | `memory.c` | 1 | C11 `_Noreturn` |
| `HAVE_STRLCAT` / `HAVE_STRLCPY` | `string.c` | 2 | BSD string functions |
| `HAVE_BSD_STRING_H` | `string.c` | 1 | BSD string header |
| `HAVE_SYSCONF` | `error.c` | 1 | `sysconf()` |
| `HAVE_SELECT` | `handlers.c` | 1 | `select()` availability |
| `STRICT_NEXT_BEHAVIOUR` | `wscroller.c` (3), `wslider.c` (1) | 4 | NeXTSTEP-strict scrollbar behavior |
| `I18N` | `wapplication.c` | 1 | Internationalization |
| `DEBUG` | `menuparser_macros.c` (4), various | ~6 | Debug logging |
| `VERBOSE` | `wfilepanel.c` (2), `memory.c` (3) | 5 | Verbose logging |
---
## 2. X11 Types in Core Structs (`WINGsP.h.in`)
### `W_Screen` (the WINGs screen object)
| Field | Type | Count |
|---|---|---|
| `display` | `Display *` | 1 |
| `rootWin` | `Window` | 1 |
| `applicationIconWindow`, `groupLeader` | `Window` | 2 |
| `stipple` | `Pixmap` | 1 |
| GCs | `GC` | **8** (`stippleGC`, `copyGC`, `clipGC`, `monoGC`, `xorGC`, `ixorGC`, `drawStringGC`, `drawImStringGC`) |
| `colormap` | `Colormap` | 1 |
| `visual` | `Visual *` | 1 |
| Cursors | `Cursor` | (in `defaultCursor`, `textCursor`, `invisibleCursor`) |
| Atoms | `Atom` | (multiple protocol atoms) |
### `W_DragSourceInfo` / `W_DragDestinationInfo`
| Field | Type |
|---|---|
| `sourceAction`, `destinationAction` | `Atom` |
---
## 3. Direct Xlib Calls — Summary by Category
### In properly-split `_x11` files (86 calls — correctly isolated)
| File | Calls | Category |
|---|---|---|
| `wview_x11.c` | 29 | Window create/map/unmap/move/resize/destroy |
| `wrender_x11.c` | 24 | Pixmap create/free/copy, drawing primitives |
| `wevent_x11.c` | 20 | Event fetch, pending check, XSync |
| `wcolor_x11.c` | 11 | Color allocation |
| `wfont_x11.c` | 2 | Xft font rendering |
### In non-split widget files (412 calls — leaking)
| Category | Calls | Files |
|---|---|---|
| **DND (XDND protocol)** | **98** | `dragsource.c` (45), `dragdestination.c` (37), `dragcommon.c` (16) |
| **Color picker** | **89** | `wcolorpanel.c` — pixmap manipulation, image capture, pointer grabs |
| **Window properties** | **41** | `wwindow.c` — ICCCM hints, WM protocols |
| **Input methods** | **40** | `winputmethod.c` — XIM/XIC lifecycle |
| **Screen init** | **35** | `widgets.c` — GC creation, cursor creation, modifier mapping |
| **Tooltips** | **28** | `wballoon.c` — shaped balloon drawing |
| **Rich text** | **23** | `wtext.c` — clipboard, grabs |
| **Selection/clipboard** | **21** | `selection.c` — X selection protocol |
| **App resources** | **15** | `wappresource.c` — icon property reading |
| **Text field** | **10** | `wtextfield.c` — clipboard, grabs |
| **Popup button** | **7** | `wpopupbutton.c` — pointer grabs |
| **Ruler** | **3** | `wruler.c` — `XRectangle` type |
| **Misc** | **2** | `wmisc.c` — coordinate translation |
---
## 4. Summary: Heat Map
```
Fully Backend-Split Xlib
Portable (vtable) Leaking
────────── ────────── ────────
WUtil layer:
proplist.c ██████████
bagtree/array/hash/.. ██████████
handlers.c ██████████
menuparser*.c ██████████
findfile/string/etc ██████████
Backend split files:
wview_x11/wl.c ██████████
wevent_x11/wl.c ██████████
wrender_x11/wl.c ██████████
wfont_x11/wl.c ██████████
wcolor_x11/wl.c ██████████
Clean widgets (0 Xlib):
wbutton.c ██████████
wscroller.c ██████████
wscrollview.c ██████████
wlist.c ██████████
wbrowser.c ██████████
wslider.c ██████████
wsplitview.c ██████████
wtabview.c ██████████
wfilepanel.c ██████████
wfontpanel.c ██████████
wpanel.c ██████████
wframe.c ██████████
wlabel.c ██████████
wbox.c ██████████
wprogressindicator.c ██████████
wcolorwell.c ██████████
wmenuitem.c ██████████
Leaking widgets:
wcolorpanel.c ██████████ (89 calls)
dragsource.c ██████████ (45 calls)
wwindow.c ██████████ (41 calls)
winputmethod.c ██████████ (40 calls)
dragdestination.c ██████████ (37 calls)
widgets.c ██████████ (35 calls)
wballoon.c ██████████ (28 calls)
wtext.c ████████░░ (23 calls)
selection.c ████████░░ (21 calls)
dragcommon.c ██████░░░░ (16 calls)
wappresource.c ████░░░░░░ (15 calls)
wtextfield.c ███░░░░░░░ (10 calls)
wpopupbutton.c ██░░░░░░░░ (7 calls)
wruler.c █░░░░░░░░░ (3 calls)
wmisc.c █░░░░░░░░░ (2 calls)
```
**By the numbers:**
| Category | Files | LOC | Xlib calls | % of WINGs |
|---|---|---|---|---|
| Fully portable (WUtil + clean widgets + Wayland backends) | 34 | 14,564 | 0 | 36% |
| Backend-split `_x11` files (properly isolated) | 5 | 1,109 | 86 | 3% |
| Leaking widget files (X11 in non-split code) | 15 | 16,252 | 412 | 41% |
| WUtil utility code (no X11) | 8 | 2,090 | 0 | 5% |
| Remaining clean widgets (0 calls but use X11 types transitively) | ~6k | | | 15% |
**The three biggest remaining problems for Wayland parity:**
1. **DND subsystem** (`dragsource.c` + `dragdestination.c` + `dragcommon.c` = 2437 LOC, 98 Xlib calls) — the entire XDND protocol implementation. Wayland has `wl_data_device`. Needs a sixth vtable or full replacement.
2. **`wcolorpanel.c`** (3556 LOC, 89 Xlib calls) — the color picker does raw pixmap manipulation, screen capture (`XGetImage`), pointer grabs, and cursor recoloring. Needs to route through `renderBackend` and `viewBackend`.
3. **`wwindow.c`** + **`winputmethod.c`** + **`widgets.c`** (2092 LOC, 116 Xlib calls combined) — ICCCM window properties, XIM/XIC input method lifecycle, and screen initialization. These are protocol-level concerns that need backend abstraction (ICCCM doesn't exist on Wayland; input methods use `zwp_text_input_v3`).
---
# WPrefs.app/ — Backend-Specific Branch Inventory
WPrefs.app is the WindowMaker preferences editor — a WINGs-based GUI application with 15,540 LOC across 21 `.c` files. Each file is a preference panel.
## File Map
| File | LOC | Purpose |
|---|---|---|
| `Appearance.c` | 2356 | Titlebar/menu texture and color configuration |
| `Menu.c` | 1825 | Menu structure editor |
| `TexturePanel.c` | 1549 | Texture creation/editing dialog |
| `editmenu.c` | 1361 | Drag-and-drop menu editor widget |
| `WPrefs.c` | 927 | Main window, panel switching, save/revert |
| `MouseSettings.c` | 798 | Mouse speed, button mapping, modifier keys |
| `FontSimple.c` | 751 | Font configuration for titlebars, menus, etc. |
| `KeyboardShortcuts.c` | 695 | Keyboard shortcut binding editor |
| `WindowHandling.c` | 612 | Window placement, focus, maximize behavior |
| `Icons.c` | 485 | Icon size, position, animation |
| `HotCornerShortcuts.c` | 465 | Screen corner actions |
| `Configurations.c` | 445 | Misc settings (icon size, edge resistance, etc.) |
| `Expert.c` | 363 | Expert-level toggle options |
| `Focus.c` | 362 | Focus mode, auto-raise delay |
| `Preferences.c` | 359 | Size/position display, dialog behavior |
| `Docks.c` | 335 | Dock/clip behavior |
| `Paths.c` | 328 | Pixmap/icon search paths |
| `xmodifier.c` | 311 | Keyboard modifier detection (from XEmacs) |
| `Workspace.c` | 240 | Workspace naming |
| `MenuPreferences.c` | 234 | Menu behavior options |
| `Themes.c` | 221 | Theme import/export |
| `main.c` | 180 | Entry point, display open, WINGs init |
| `double.c` | 163 | Double-click speed test widget |
| `WPrefs.h` | 175 | Shared header |
| `TexturePanel.h` | 56 | Texture panel header |
| `editmenu.h` | 113 | Menu editor header |
---
## File Classification
### Fully Portable (zero Xlib calls, zero meaningful X11 types)
These files use only WINGs widget APIs and WMPropList for defaults manipulation:
| File | LOC | Purpose |
|---|---|---|
| `FontSimple.c` | 751 | Font configuration |
| `WindowHandling.c` | 612 | Window placement/behavior |
| `Icons.c` | 485 | Icon preferences |
| `Configurations.c` | 445 | Misc configuration |
| `Expert.c` | 363 | Expert toggles |
| `Focus.c` | 362 | Focus mode |
| `Preferences.c` | 359 | Size/position display |
| `Docks.c` | 335 | Dock behavior |
| `Workspace.c` | 240 | Workspace naming |
| `MenuPreferences.c` | 234 | Menu behavior |
| `Themes.c` | 221 | Theme management |
| `KeyboardSettings.c` | 175 | Keyboard repeat/delay |
| **Total** | **4582** | **29% of WPrefs.app** |
Note: several of these files reference `Display *` or `Window` in variable declarations (obtained via `WMScreenDisplay()`) but only pass them to WINGs functions — they never call Xlib directly. The X11 types flow through transitively from WINGs.
### X11-Dependent Files
| File | LOC | Xlib calls | What's leaking |
|---|---|---|---|
| **`Appearance.c`** | 2356 | **67** | Texture preview rendering: `XCreatePixmap`, `XCopyArea` (×20), `XDrawLine` (×15), `XDrawRectangle` (×6), `XFillRectangle` (×4), `XFillPolygon` (×2), `XFreePixmap` (×6), `XCreateGC`/`XFreeGC`, `XParseColor` |
| **`editmenu.c`** | 1361 | **37** | Drag-and-drop menu editing: `XGrabPointer`/`XUngrabPointer`, `XTranslateCoordinates` (×4), `XRecolorCursor` (×4), `XQueryTree`, `XQueryPointer`, `XGetWindowAttributes`, `XGetGeometry`, `XMoveWindow`, `XClearWindow`, `XFlush`, `XChangeProperty`, `XSetWMNormalHints`, `XAllocSizeHints`, `XSetErrorHandler` |
| **`Menu.c`** | 1825 | **24** | Menu editor: `XGrabKeyboard`/`XUngrabKeyboard`, `XDrawLine` (×7), `XSetForeground` (×2), `XFillRectangle`, `XCreateGC`/`XFreeGC` — mostly drawing crosshair markers and key capture |
| **`TexturePanel.c`** | 1549 | **14** | Texture editor: `XFillRectangle` (×3), `XCopyArea` (×2), `XFreePixmap`, `XParseColor`, `XCreateSimpleWindow`, `XMapRaised`, `XFlush`, `XOpenDisplay`, `XColor` |
| **`xmodifier.c`** | 311 | **12** | Modifier key detection: `XGetModifierMapping`, `XFreeModifiermap`, `XKeysymToKeycode` — entirely X11 |
| **`KeyboardShortcuts.c`** | 695 | **12** | Shortcut capture: `XGrabKeyboard`/`XUngrabKeyboard`, `XKeysymToKeycode`, `XKeysymToString`, `XAllowEvents`, `XGetModifierMapping`, `XFreeModifiermap`, `XConvertCase`, `XFillRectangle` |
| **`HotCornerShortcuts.c`** | 465 | **11** | Hot corner icon rendering: `XCreatePixmap` (×5), `XCopyArea` (×5), `XFreePixmap` (×5), `XCreateGC`/`XFreeGC` — icon quadrant assembly |
| **`WPrefs.c`** | 927 | **7** | WM command: `XInternAtom`, `XSendEvent`, `XFlush` (×2) — sends `_WINDOWMAKER_COMMAND` to reload |
| **`MouseSettings.c`** | 798 | **6** | Mouse config: `XChangePointerControl`, `XGetPointerControl`, `XGetModifierMapping`, `XFreeModifiermap`, `XKeysymToString` |
| **`main.c`** | 180 | **4** | Startup: `XSupportsLocale`, `XSetLocaleModifiers`, `XOpenDisplay`, `XDisplayName` |
| **`double.c`** | 163 | **2** | Double-click widget: `XFillRectangle`, `XClearWindow` |
| **`Paths.c`** | 328 | **1** | List drawing: `XFillRectangle` (in custom list cell renderer) |
| **Total** | **8958** | **197** | |
---
## 1. Compile-Time `#ifdef` Branches
### Backend/Feature Guards
| Guard | File | Sites | What it guards |
|---|---|---|---|
| `XKB_MODELOCK` | `Expert.c:87`, `KeyboardShortcuts.c:166` | 2 | XKB mode lock toggle option, extra keybinding |
| `HAVE_XCONVERTCASE` | `KeyboardShortcuts.c:171` | 1 | Whether to use system `XConvertCase` or local implementation |
### Portability Guards
| Guard | File | Sites | What it guards |
|---|---|---|---|
| `HAVE_STDNORETURN` | `WPrefs.c:27`, `main.c:33` | 2 | C11 `_Noreturn` |
| `I18N` | `main.c:131` | 1 | Gettext initialization |
| `FC_WEIGHT_NORMAL` | `FontSimple.c:28` | 1 | Fontconfig constant fallback |
| `DEBUG` | `Expert.c:286` | 1 | Debug panel option |
**Total: 8 `#ifdef` sites.** Remarkably few for a 15k LOC application.
---
## 2. Runtime Backend Dispatch
**None.** No vtable calls, no `is_wayland` checks, no `_x11_raw` access, no `dpy == NULL` guards. WPrefs.app is a pure WINGs client — it gets its X11 dependency entirely through WINGs APIs and direct Xlib calls.
---
## 3. X11 Types in Shared Headers
### `WPrefs.h`
```c
int ModifierFromKey(Display *dpy, const char *key); // line 144
```
One function prototype with `Display *`. The rest of the header is WINGs types (`WMScreen *`, `WMWindow *`, etc.).
---
## 4. Direct Xlib Calls — By Category
### Drawing / Pixmap Manipulation (120 calls — 61%)
The dominant category. WPrefs renders texture previews, menu editor decorations, and icon composites directly via Xlib:
| Operation | Count | Files |
|---|---|---|
| `XCopyArea` | 27 | `Appearance.c` (20), `HotCornerShortcuts.c` (5), `TexturePanel.c` (2) |
| `XDrawLine` | 22 | `Appearance.c` (15), `Menu.c` (7) |
| `XFillRectangle` | 13 | `Appearance.c` (4), `Menu.c` (1), `TexturePanel.c` (3), `Paths.c` (1), `double.c` (1), `KeyboardShortcuts.c` (1), `HotCornerShortcuts.c` (1), `editmenu.c` (1) |
| `XCreatePixmap` | 8 | `Appearance.c` (3), `HotCornerShortcuts.c` (5) |
| `XFreePixmap` | 8 | `Appearance.c` (4), `HotCornerShortcuts.c` (3), `TexturePanel.c` (1) |
| `XDrawRectangle` | 6 | `Appearance.c` |
| `XCreateGC` / `XFreeGC` | 6 | `Appearance.c` (4), `Menu.c` (2) |
| `XFillPolygon` / `XDrawLines` | 4 | `Appearance.c` |
| `XSetForeground` | 2 | `Menu.c` |
**These should all route through WINGs' `W_RenderBackend` vtable** but don't.
### Keyboard / Input (24 calls — 12%)
| Operation | Count | Files |
|---|---|---|
| `XGrabKeyboard` / `XUngrabKeyboard` | 4 | `KeyboardShortcuts.c`, `Menu.c` |
| `XKeysymToKeycode` / `XKeysymToString` | 5 | `KeyboardShortcuts.c`, `MouseSettings.c` |
| `XGetModifierMapping` / `XFreeModifiermap` | 6 | `KeyboardShortcuts.c`, `MouseSettings.c`, `xmodifier.c` |
| `XConvertCase` | 1 | `KeyboardShortcuts.c` |
| `XAllowEvents` | 1 | `KeyboardShortcuts.c` |
### Window / Pointer Manipulation (22 calls — 11%)
| Operation | Count | Files |
|---|---|---|
| `XGrabPointer` / `XUngrabPointer` | 4 | `editmenu.c` |
| `XTranslateCoordinates` | 5 | `editmenu.c` |
| `XRecolorCursor` | 4 | `editmenu.c` |
| `XQueryTree` / `XQueryPointer` | 2 | `editmenu.c` |
| `XGetWindowAttributes` / `XGetGeometry` | 2 | `editmenu.c` |
| `XMoveWindow` / `XClearWindow` | 2 | `editmenu.c`, `double.c` |
| `XChangePointerControl` / `XGetPointerControl` | 2 | `MouseSettings.c` |
### WM Communication (7 calls — 4%)
| Operation | Count | Files |
|---|---|---|
| `XInternAtom` | 1 | `WPrefs.c` |
| `XSendEvent` | 1 | `WPrefs.c` |
| `XFlush` | 3 | `WPrefs.c` (2), `TexturePanel.c` (1) |
| `XChangeProperty` / `XSetWMNormalHints` | 2 | `editmenu.c` |
### Color Parsing (3 calls — 2%)
| Operation | Count | Files |
|---|---|---|
| `XParseColor` | 2 | `Appearance.c`, `TexturePanel.c` |
| `XColor` type | 2 | `Appearance.c`, `TexturePanel.c` |
### Display Connection (4 calls — 2%)
| Operation | Count | Files |
|---|---|---|
| `XOpenDisplay` | 2 | `main.c`, `TexturePanel.c` |
| `XSupportsLocale` / `XSetLocaleModifiers` | 2 | `main.c` |
---
## 5. Summary: Heat Map
```
Fully X11
Portable Leaking
────────── ────────
FontSimple.c ██████████
WindowHandling.c ██████████
Icons.c ██████████
Configurations.c ██████████
Expert.c ██████████
Focus.c ██████████
Preferences.c ██████████
Docks.c ██████████
Workspace.c ██████████
MenuPreferences.c ██████████
Themes.c ██████████
KeyboardSettings.c ██████████
Paths.c █████████░ (1 XFillRectangle)
double.c ████████░░ (2 calls)
WPrefs.c ███████░░░ (7 calls - WM reload command)
main.c ███████░░░ (4 calls - display open)
MouseSettings.c ██████░░░░ (6 calls - pointer control)
HotCornerShortcuts.c █████░░░░░ (11 calls - icon pixmap assembly)
KeyboardShortcuts.c █████░░░░░ (12 calls - key grab/detect)
TexturePanel.c ████░░░░░░ (14 calls - texture preview)
Menu.c ███░░░░░░░ (24 calls - menu editor drawing)
editmenu.c ██░░░░░░░░ (37 calls - DnD menu editing)
xmodifier.c ░░░░░░░░░░ ██████████ (12 calls - entirely X11)
Appearance.c ░░░░░░░░░░ ██████████ (67 calls - texture preview)
```
**By the numbers:**
| Category | Files | LOC | Xlib calls | % of WPrefs.app |
|---|---|---|---|---|
| Fully portable | 12 | 4582 | 0 | 29% |
| Minor X11 leakage (≤7 calls) | 5 | 1876 | 20 | 12% |
| Moderate X11 leakage (8–37 calls) | 5 | 3834 | 86 | 25% |
| Heavy X11 dependency (>37 calls) | 2 | 3717 | 91 | 24% |
| Entirely X11 (xmodifier.c) | 1 | 311 | 12 | 2% |
**The three biggest problems for Wayland parity:**
1. **`Appearance.c`** (67 Xlib calls) — all texture preview rendering. Uses `XCopyArea`, `XDrawLine`, `XDrawRectangle`, `XFillPolygon` directly on pixmaps. Should use WINGs' `W_RenderBackend` instead.
2. **`editmenu.c`** (37 Xlib calls) — the drag-and-drop menu editor. Pointer grabs, coordinate translation, window tree queries, cursor recoloring. These are interaction-model operations that need backend abstraction.
3. **Keyboard/modifier detection** (`KeyboardShortcuts.c` + `xmodifier.c` = 24 Xlib calls) — `XGrabKeyboard`, `XGetModifierMapping`, `XKeysymToKeycode`. On Wayland, keyboard handling uses `xkbcommon` directly rather than X11 modifier mapping.