581 lines
36 KiB
Markdown
581 lines
36 KiB
Markdown
# 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_raw` sites in `src/`: 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_target` against `view_table` at fetch boundary in `wevent_wl.c`, plus defense-in-depth in `wview.c` and `wevent.c`
|
|
- Scene graph cleanup: `wl_destroy()` calls `W_ViewDestroyBackingFn` → `wl_view_destroy_backing_impl()` to destroy `wlr_scene_node` and `wlr_buffer_drop` when 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_raw` sites in `src/`: 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.c` is 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~~
|
|
- **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.h` but makes zero Xlib calls. They get it transitively via `#include "wraster.h"`. The include is in `wraster.h.in` itself (line 47), so these files can't avoid it without changing the public header. Two options:
|
|
- (a) Guard the X11 includes in `wraster.h.in` with `#ifndef WRLIB_NO_X11` and define that in Wayland builds, OR
|
|
- (b) Accept the transitive include (it's a type definition header, not a link dependency) and move on.
|
|
- **Recommendation**: Option (b) — this is cosmetic. Skip and move to substantive tasks.
|
|
- **Xlib calls eliminated**: 0 (cosmetic only)
|
|
|
|
### F.2 ~~Verify `RCreateContextWayland()` completeness~~ ✅
|
|
**Status**: DONE — all fields verified correct, no issues.
|
|
- **File**: `wrlib/context.c:725-775`
|
|
- **Operation**: Read `RCreateContextWayland()`. Verify it sets all fields that `RConvertImage` and image loaders need: `depth`, `vclass`, `red_offset`, `green_offset`, `blue_offset`, `black`, `white`, `convert_image`, `convert_image_mask`. Verify `dpy`, `cmap`, `copy_gc`, `visual`, `drawable` are NULL/0.
|
|
- **Test**: Call `RCreateContextWayland(1920, 1080, NULL)`, then `RLoadImage(ctx, "test.png", 0)`, then `RConvertImage(ctx, img, &pixmap)`. Confirm the pixmap is a `pixman_image_t*` cast to `Pixmap`.
|
|
- **Blocked by**: nothing
|
|
|
|
### F.3 ~~Verify `wl_convert_image` / `wl_convert_image_mask`~~ ✅
|
|
**Status**: 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) vs `RRGBAFormat`. Verify the returned `Pixmap` is `(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 returns `RImage*` without touching `ctx->dpy`. Grep each file for `->dpy`, `->cmap`, `->visual`.
|
|
- **Expected result**: All clean except `load_xpm.c` (uses `XParseColor`).
|
|
- **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) — uses `XParseColor` for color name→RGB
|
|
- **Operation**: `load_xpm_normalized.c` (459 lines) already exists as a pure-C XPM parser that doesn't need X11. Verify that `RLoadImage()` in `wrlib/load.c` dispatches to `load_xpm_normalized.c` when `ctx->dpy == NULL`. If not, add a check:
|
|
```c
|
|
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`~~ ✅
|
|
- **File**: `src/workspace.c` — 5 `#ifdef USE_XINERAMA` sites (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 `WScreen` fields (already populated by the backend), not from Xinerama calls. For each site:
|
|
1. Read the `#ifdef USE_XINERAMA` block and the `#else` block
|
|
2. Replace both with code that reads `wGetHeadForPointerLocation(scr)` or equivalent backend-neutral monitor query (these functions already exist and are backend-abstracted)
|
|
3. Delete the `#ifdef`
|
|
- **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*`~~ ✅
|
|
- **Files**: `src/switchpanel.c:684`, `src/switchpanel.h:33`
|
|
- **Operation**:
|
|
1. Change function signature from `WWindow *wSwitchPanelHandleEvent(WSwitchPanel *panel, XEvent *event)` to `WWindow *wSwitchPanelHandleEvent(WSwitchPanel *panel, WMEvent *event)`
|
|
2. Inside the function, replace all `event->xmotion.x` field accesses with `event->u.motion.x` (the backend-neutral WMEvent fields)
|
|
3. Replace all `event->xbutton.button` with `event->u.button.button`, etc.
|
|
4. Replace `event->type == MotionNotify` with `event->type == WME_MOTION`, etc.
|
|
- **Blocked by**: nothing
|
|
|
|
#### A5.2 ~~Remove XEvent synthesis in `cycling.c`~~ ✅
|
|
- **File**: `src/cycling.c:227-259`
|
|
- **Operation**: After A5.1, the `wSwitchPanelHandleEvent` takes `WMEvent*`. Delete the entire XEvent synthesis block (lines 227-259) and replace with:
|
|
```c
|
|
tmp = wSwitchPanelHandleEvent(swpanel, &ev);
|
|
```
|
|
Pass the `WMEvent ev` directly instead of synthesizing an `XEvent`.
|
|
- **Xlib calls eliminated**: 5 (XEvent type references)
|
|
- **Blocked by**: A5.1
|
|
|
|
---
|
|
|
|
## Phase B: Dock & App Icons
|
|
|
|
### B.1 ~~Eliminate `XClearArea` in `appicon.c`~~ ✅
|
|
- **File**: `src/appicon.c:371`
|
|
- **Operation**: Replace `XClearArea(dpy, dicon->icon->core->window, 2, 2, 50, ...)` with `wm_backend->window_clear_area(dicon->icon->core->window, 2, 2, 50, ...)` or `wm_backend->frame_paint(...)` to trigger a repaint. Check if a `window_clear_area` vtable slot exists; if not, use `frame_paint` on 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:
|
|
1. Lines 52, 131: Move `#include "xdnd.h"` and `wXDNDMakeAwareness()` call into the X11 backend's `appicon_show` implementation
|
|
2. Lines 315, 338: The DND event handling in `iconDblClick` / `iconMouseDown` should dispatch through `wm_backend->xdnd_process_client_message` (already exists)
|
|
3. Remove all `#ifdef USE_DOCK_XDND` from `appicon.c`
|
|
- **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*`~~ ✅
|
|
- **Files**: `src/dock.c:2009`, `src/dock.h:97`
|
|
- **Operation**: Same pattern as A5.1. Change `int wDockReceiveDNDDrop(WScreen *scr, XEvent *event)` to take `WMEvent*`. Update the single call site in `event.c:782` to pass the `WMEvent` instead of casting `_x11_raw`.
|
|
- **Xlib calls eliminated**: 1 `_x11_raw` access in `event.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)
|
|
- **File**: `src/moveres.c` — 6 Xlib calls (lines 145-151)
|
|
- **Operation**: Replace `XSetForeground` + `XDrawLine` calls with `wm_backend->overlay_draw_line()` vtable calls (slot exists at `backend.h:797`):
|
|
```c
|
|
// 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);
|
|
```
|
|
Do this for all 4 `XDrawLine` calls and the `XSetForeground`.
|
|
- **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_hide` vtable slots exist and are called from `balloon.c`. Confirm `balloon.c` has 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:
|
|
1. **Lines 568-571**: `XOpenDisplay` — already handled (WINGs init takes a `Display*` or NULL)
|
|
2. **Lines 637-739**: GC creation, cursor creation, modifier mapping, atom interning. Wrap this entire block in:
|
|
```c
|
|
if (scrPtr->display != NULL) { // X11 path
|
|
// existing code
|
|
}
|
|
```
|
|
The Wayland path skips GC/cursor creation (handled by `wrender_wl.c` and `wview_wl.c`). The modifier mapping should use `xkb_keymap` on Wayland (already in `wevent_wl.c`).
|
|
3. **Lines 735-739**: `XInternAtoms` — move to a `viewBackend->platform_init()` call (slot exists at `backend.h` line 621, already called at `widgets.c:832`)
|
|
- **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:
|
|
1. `WMSetWindowTitle` (line 155): Wrap the `XmbTextListToTextProperty` + `XSetWMName` + `XChangeProperty` block in `if (scr->display)`. On Wayland, set `xdg_toplevel_set_title` via a new `viewBackend->set_title(view, title)` slot.
|
|
2. `WMSetWindowMiniwindowTitle` (line 176): Same pattern, `viewBackend->set_icon_title(view, title)`.
|
|
3. `WMSetWindowMiniwindowImage` (line 230): `XChangeProperty` for `_NET_WM_ICON`. Wrap in `if (scr->display)`. No Wayland equivalent needed (compositor owns icons).
|
|
4. `WMSetWindowCloseAction` / `WMSetWindowMaximized` (lines 260-285): `XGetWMProtocols` / `XSetWMProtocols`. Wrap in `if (scr->display)`.
|
|
5. `setWindowGeometry` (line 318): `XAllocSizeHints` / `XSetWMNormalHints`. Wrap in `if (scr->display)`.
|
|
6. `WMRealizeWindow` (lines 415-464): `XAllocClassHint` / `XSetClassHint` / `XAllocWMHints` / `XSetWMHints` / `XSetWMProtocols` / `XSetTransientForHint`. Wrap in `if (scr->display)`.
|
|
7. `WMSetWindowMiniwindowPixmap` (line 572): `XGetWMHints` / `XSetWMHints`. Wrap in `if (scr->display)`.
|
|
8. `WMCloseWindow` (line 618): `XWithdrawWindow`. Replace with `viewBackend->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:
|
|
1. Rename `winputmethod.c` → `winputmethod_x11.c`
|
|
2. Create `winputmethod_wl.c` with stub implementations (or `zwp_text_input_v3` if needed now)
|
|
3. Create `winputmethod.c` as a thin dispatch layer that calls `scr->imBackend->*()` or uses `if (scr->display)` guards
|
|
4. Update `Makefile.am` to compile all three
|
|
- **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`, `XCreateGC` to draw shaped tooltips. Replace each with `renderBackend->fill_arc()`, `renderBackend->fill_rect()`, `renderBackend->fill_polygon()` calls. The render backend vtable already has these slots.
|
|
- `XTranslateCoordinates` (line 182): Replace with `viewBackend->get_screen_position()` (slot exists).
|
|
- `USE_XSHAPE` guards (2 sites): Move shape extension calls into `viewBackend` or wrap in `if (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 uses `wl_data_device`. Create:
|
|
1. Rename `selection.c` → `selection_x11.c`
|
|
2. Create `selection_wl.c` with `wl_data_device` implementation (or stubs)
|
|
3. Create `selection.c` dispatch layer
|
|
4. Update `Makefile.am`
|
|
- **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_device` for cross-client and compositor-internal mechanisms for WINGs↔WINGs.
|
|
1. Rename all three to `*_x11.c`
|
|
2. Create `dragsource_wl.c`, `dragdestination_wl.c`, `dragcommon_wl.c` (stubs initially)
|
|
3. Create thin dispatch files or add a `W_DnDBackend` vtable to `WINGsP.h.in`
|
|
4. Update `Makefile.am`
|
|
- **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:
|
|
1. **Pixmap ops** (XCreatePixmap, XCopyArea, XFreePixmap, XFillRectangle — ~44 calls): Replace with `renderBackend->pixmap_create()`, `renderBackend->pixmap_copy()`, `renderBackend->pixmap_free()`, `renderBackend->fill_rect()`.
|
|
2. **Image capture** (XGetImage, XGetPixel, XPutPixel, XSubImage, XPutImage, XDestroyImage — ~15 calls): Replace with `renderBackend` image access functions or wrlib `RImage` operations.
|
|
3. **Pointer grabs** (XGrabPointer, XUngrabPointer, XQueryPointer — ~6 calls): Replace with `viewBackend` pointer grab functions.
|
|
4. **Cursor** (XRecolorCursor, XCreatePixmapCursor, XFreeCursor — ~4 calls): Replace with `viewBackend->set_cursor()`.
|
|
5. **Event polling** (XPending, XPeekEvent, XNextEvent, XCheckTypedEvent, XFlush — ~6 calls): Replace with `eventBackend` functions.
|
|
6. **`USE_XSHAPE` guards** (6 sites): Move shape calls into `viewBackend` or guard with `if (scr->display)`.
|
|
- **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**:
|
|
1. **Clipboard** (`XFetchBuffer`, `XStoreBuffer`, `XFree` — 6 calls): Replace with WINGs selection API (which will be backend-split after D.5).
|
|
2. **Pointer grabs** (`XGrabPointer`, `XUngrabPointer` — 4 calls): Replace with `viewBackend` pointer grab.
|
|
3. **Misc** (`XBell` — 2 calls): Replace with `viewBackend->bell()` or no-op.
|
|
4. **Drawing** (`XCreateGC`, `XCreateBitmapFromData`, `XChangeWindowAttributes`, `XSetWindowAttributes`, `XMapWindow`, `XInternAtom`, `XFlush` — 9 calls): Route through render/view backends.
|
|
5. **`XRectangle` type** (2 uses): Replace with `WMRect`.
|
|
- **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:
|
|
1. Clipboard (`XFetchBuffer`, `XStoreBuffer`, `XFree`): Use WINGs selection API
|
|
2. Grabs (`XGrabPointer`, `XUngrabPointer`): Use `viewBackend`
|
|
3. Bell (`XBell`): Use `viewBackend->bell()` or no-op
|
|
4. Drawing (`XDrawRectangle`, `XInternAtom`, `XFlush`): Use `renderBackend`
|
|
- **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` / `XFlush` with `viewBackend` pointer 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` / `XInternAtom` calls with `viewBackend` property functions or guard with `if (scr->display)`. These read app icon properties — on Wayland, icons come from `xdg_toplevel` or 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 `XTranslateCoordinates` with `viewBackend->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_raw` cast is used to get an `XEvent*` for some event handling. Replace with `WMEvent` field access (same pattern as A5.1).
|
|
- **Xlib calls eliminated**: 1 `_x11_raw` access
|
|
- **Blocked by**: nothing
|
|
|
|
### E.2 Eliminate `_x11_raw` accesses in `event.c`
|
|
- **File**: `src/event.c` — 16 `_x11_raw` sites
|
|
- **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/XKB | Already dispatches through `wm_backend->event_randr_update()` and `wm_backend->event_handle_extensions()`. The `_x11_raw` is the *argument* to these vtable calls. Change vtable signatures to accept `WMEvent*` instead of `void*`, and have the X11 backend extract `_x11_raw` internally. |
|
|
| 431 | `handleMapRequest` — raw XEvent for `wManageWindow` | Check if `wManageWindow` actually needs the raw event or just the window ID (from `event->u.mapRequest.window`). If just the ID, pass that. |
|
|
| 446-447 | `handleExtensions` — passes raw event to backend | Already a vtable call. Change vtable to accept `WMEvent*`. |
|
|
| 782 | `handleButtonPress` — raw XEvent for `wDockReceiveDNDDrop` | Eliminated by task B.3. |
|
|
| 831, 834, 852, 857 | `handleClientMessage` — raw XEvent for EWMH, XDND, selection | Already dispatched through `wm_backend->netwm_process_client_message()` and `wm_backend->xdnd_process_client_message()`. Change vtable signatures to accept `WMEvent*`. |
|
|
| 971, 974 | `handleClientMessage` — same | Same as above. |
|
|
| 993 | `handleClientMessage` — colormap install | Change vtable call to accept `WMEvent*`. |
|
|
| 1354 | `handleKeyPress` — raw XEvent for root menu shortcuts | Task E.3 below. |
|
|
|
|
- **Xlib calls eliminated**: 16 `_x11_raw` accesses
|
|
- **Blocked by**: B.3, E.3
|
|
|
|
### E.3 ~~Change `wRootMenuPerformShortcut` from `XEvent*` to `WMEvent*`~~ ✅
|
|
- **Files**: `src/rootmenu.c:320`, `src/rootmenu.h:25`
|
|
- **Operation**: Change signature from `Bool wRootMenuPerformShortcut(XEvent *event)` to `Bool wRootMenuPerformShortcut(WMEvent *event)`. Update internals to use `event->u.key.*` fields instead of `event->xkey.*`.
|
|
- **Blocked by**: nothing
|
|
|
|
### E.4 ~~Eliminate X11 types in `client.c` function signatures~~ ✅
|
|
- **Files**: `src/client.c:119,247`, `src/client.h:27,31`
|
|
- **Operation**:
|
|
1. `wClientConfigure(WWindow *wwin, XConfigureRequestEvent *xcre)` → change parameter to `WMEvent *event` and extract fields from `event->u.configureRequest.*`
|
|
2. `wClientCheckProperty(WWindow *wwin, XPropertyEvent *event)` → change parameter to `WMEvent *event` and extract from `event->u.property.*`
|
|
3. 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`/`XDrawLines` with `WMDrawLine`, `WMFillRectangle`, `WMCopyArea` (WINGs drawing API, routed through `renderBackend`) | `Appearance.c`, `Menu.c`, `TexturePanel.c`, `HotCornerShortcuts.c`, `double.c`, `Paths.c`, `KeyboardShortcuts.c` | 120 | WINGs render API |
|
|
| E.5b: Replace `XCreatePixmap`/`XFreePixmap` with `WMCreatePixmap`/`WMReleasePixmap` | `Appearance.c`, `HotCornerShortcuts.c`, `TexturePanel.c` | 16 | WINGs pixmap API |
|
|
| E.5c: Replace `XCreateGC`/`XFreeGC` with WINGs managed GCs or remove (render backend handles GCs internally) | `Appearance.c`, `Menu.c` | 6 | Remove; use WINGs color GCs |
|
|
| E.5d: Replace `XGrabKeyboard`/`XUngrabKeyboard` with WINGs keyboard grab API (needs creation or backend call) | `KeyboardShortcuts.c`, `Menu.c` | 4 | New WINGs API or `viewBackend` |
|
|
| E.5e: Replace `XGrabPointer`/`XUngrabPointer`/`XQueryPointer`/`XTranslateCoordinates` with WINGs pointer API | `editmenu.c` | 12 | `viewBackend` pointer ops |
|
|
| E.5f: Replace `XGetModifierMapping`/`XKeysymToKeycode`/`XKeysymToString` with xkbcommon equivalents or WINGs API | `KeyboardShortcuts.c`, `MouseSettings.c`, `xmodifier.c` | 18 | xkbcommon or WINGs key API |
|
|
| E.5g: Replace `XParseColor` with WINGs `WMCreateNamedColor` | `Appearance.c`, `TexturePanel.c` | 3 | WINGs color API |
|
|
| E.5h: Replace `XSendEvent`/`XInternAtom` (WM reload command) with WINGs or backend-neutral mechanism | `WPrefs.c` | 3 | Write to defaults file + signal |
|
|
| E.5i: Replace `XOpenDisplay` in `main.c` with WINGs init (already takes display) | `main.c` | 4 | WINGs `WMOpenScreen` |
|
|
| E.5j: Replace `XChangePointerControl`/`XGetPointerControl` with backend call or libinput | `MouseSettings.c` | 2 | Backend-specific or defer |
|
|
| E.5k: Replace `XRecolorCursor`/`XMoveWindow`/`XClearWindow`/`XSetWMNormalHints` etc. in `editmenu.c` | `editmenu.c` | 15 | 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 (all `XColor` type for color parsing)
|
|
- **Operation**: The `XColor` references are for parsing color names from the defaults database. These should use `wm_backend->color_parse_name()` or equivalent vtable slot. Check if a vtable slot exists for color name→RGB conversion. If so, replace the `XColor` + `XParseColor` calls. 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 is `wlr_foreign_toplevel_management_v1` (already advertised by wlroots). The 65 Xlib calls in `wmspec.c` are **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.c` functions are only called from code paths that have an X11 client (XWayland surface). The `if (!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). The `xdnd.c` code 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 populates `WScreen` head geometry).
|
|
- **Xlib calls eliminated**: 0 (compile-time guards)
|
|
- **Blocked by**: nothing
|
|
|
|
### H.5 Verify clipboard works via wlroots
|
|
- **Operation**: wlroots implements `wl_data_device` and `zwp_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`~~ ✅
|
|
- **File**: `src/framewin.c:1165`
|
|
- **Operation**: The `_x11_raw` access is in a titlebar click handler. Replace with `WMEvent` field access.
|
|
- **Blocked by**: nothing
|
|
|
|
### R.2 ~~Eliminate `_x11_raw` in `icon.c`~~ ✅
|
|
- **File**: `src/icon.c:861`
|
|
- **Operation**: The `_x11_raw` access is in `miniwindowDblClick`. Replace with `WMEvent` field access.
|
|
- **Blocked by**: nothing
|
|
|
|
### R.3 ~~Eliminate `_x11_raw` in `menu.c`~~ ✅
|
|
- **File**: `src/menu.c:738`
|
|
- **Operation**: The `_x11_raw` access is in `check_key`. Replace with `WMEvent` field 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) and `wm_backend->key_lookup_string()` (may need new slot).
|
|
- **Blocked by**: nothing
|
|
|
|
### R.5 ~~Eliminate X11 in `usermenu.c`~~ ✅
|
|
- **File**: `src/usermenu.c` — 4 Xlib calls (`XSendEvent`, `XStringToKeysym`)
|
|
- **Operation**: Replace `XSendEvent` with `wm_backend->client_send_key_event()` or equivalent vtable slot. Replace `XStringToKeysym` with `xkb_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 with `if (dpy)` or move to `backend/x11/`.
|
|
- **Blocked by**: nothing
|
|
|
|
### R.7 ~~Eliminate `USE_XSHAPE` guards in `window.c`~~ ✅
|
|
- **File**: `src/window.c` — 4 `#ifdef USE_XSHAPE` sites
|
|
- **Operation**: Shape extension queries should be behind the backend. Move `XShapeQueryExtents` calls into `wm_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`, add `wPreferences.show_language_button` check)
|
|
- (c) Leave as-is (it's not blocking Wayland)
|
|
- **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) | ~~F.2-F.5~~ ✅ |
|
|
| `wmlib/` | 9 | Not addressed (too small; keep for X11 or drop) |
|
|
| **Total** | **~700** | **~45 tasks** |
|