windowmaker-wl/ROADMAP.md

234 lines
9.4 KiB
Markdown

# WindowMaker Wayland Port — Roadmap
## Current State (2026-05-28, updated)
The backend abstraction is complete. The `src/` policy layer has zero direct Xlib
calls and zero `_x11_raw` references. The Wayland backend (wlroots-based, 10K lines)
implements all core window management: stacking, maximize, shade, workspaces,
alt-tab, dock/clip, menus, move/resize, focus, and frame rendering.
WPrefs.app launches on Wayland but crashes are still observed — the root cause
is **WINGs widget library**, which still has 412 direct Xlib calls in 15 non-split
widget files that bypass the vtable dispatch (see Priority 2).
**DND progress**: compositor-internal drag-and-drop (WINGs view ↔ WINGs view) is now
fully functional. Drag images render as scene-graph overlays, cursor changes to "plus"
over valid drop targets. Cross-client DND (external Wayland client ↔ WINGs) has basic
wiring in place — accepts drags, tracks motion/drop — but needs MIME type routing to
WINGs destination procs to be fully functional.
The smoke test suite passes for core WM features.
What remains is **feature completion and production hardening**.
---
## Priority 1: Daily-Driver Gaps
These block using the Wayland backend as a primary desktop.
### 1.1 Session Persistence
`src/session.c` (614 lines) — verify save/restore works on Wayland. Window
positions are tracked in `WWindow` (backend-neutral). The only concern is
matching restored sessions to native XDG clients via `app_id` instead of
`WM_CLASS`.
- [x] Save/restore state for Wayland native clients: `PropGetWMClass` already
returns the XDG `app_id` on Wayland. Session save no longer bails when
`GetCommandForWindow` returns NULL (external Wayland clients have no ICCCM
command). Restore matches by `app_id` via instance+class without requiring
a command.
- [ ] Test: save session, restart compositor, verify window positions restored
- [ ] Verify dock state persistence (icon layout in `~/GNUstep/Defaults/`)
### 1.2 Multi-Monitor
Currently single-output only. wlroots provides `wlr_output_layout` and
`new_output` signal.
- [ ] Populate `WScreen.heads[]` from `wlr_output_layout_get_box` in `screen_open`
- [ ] Handle output hotplug (migrate windows on disconnect)
- [ ] Per-head usable area calculation (dock margins)
- [ ] Test with nested multi-output (`WMAKER_WAYLAND_NESTED=1` + `wlr-randr`)
### 1.3 Clipboard
wlroots advertises `wl_data_device_manager` and `zwp_primary_selection_v1`.
XWayland bridge auto-syncs. Needs verification.
- [ ] Test copy/paste between native Wayland clients
- [ ] Test copy/paste between XWayland and native clients
- [ ] Test primary selection (middle-click paste)
### 1.4 Remaining Vtable Stubs
These vtable slots are stubs or partial implementations:
| Slot | Purpose | Needed For |
|------|---------|------------|
| `overlay_draw_*` | Pixman animation buffer | Iconify zoom animation |
| `client_snapshot` | Window thumbnail capture | Switch panel thumbnails, icon preview |
| `window_set_border` | Scene rect border nodes | Window borders |
| `client_synth_configure` | XDG configure scheduling | Resize negotiation |
| `pointer_change_grab` | Grab parameter update | Menu tracking |
---
## Priority 2: WPrefs.app Full Port
### Status: Direct X11 Calls Resolved
All 11 direct Xlib calls previously reported in WPrefs.app have been audited:
| File | Previously Reported | Actual Status |
|------|-------------------|--------------|
| `TexturePanel.c` | 7 calls | **0 active** — all inside `#if 0` dead code blocks |
| `Expert.c` | 1 (XGetDefault) | **0 active** — call already removed |
| `MouseSettings.c` | 1 (XChangePointerControl) | **0 active** — call already removed |
| `xmodifier.c` | 1 (XGetModifierMapping) | **0 active** — only in a comment |
WPrefs.app itself now has **zero direct Xlib calls**. The crash source is in
WINGs widget library, which WPrefs links against.
### Root Cause: WINGs X11 Leaks (412 calls)
WINGs still has **412 direct Xlib calls** across 15 non-split widget files that
bypass the 5-vtable dispatch (`W_ViewBackend`, `W_EventBackend`, `W_RenderBackend`,
`W_FontBackend`, `W_ColorBackend`). These are the crash sites when WPrefs calls
WINGs APIs on the Wayland path.
| WINGs File | X11 Calls | What It Does |
|------------|-----------|-------------|
| `wcolorpanel.c` | 89 | Pixmap manipulation, `XGetImage`, pointer grabs, cursor recoloring |
| `dragsource.c` | 45 | XDND protocol (`XSendEvent`, `XInternAtom`, grabs) |
| `wwindow.c` | 41 | ICCCM window properties (`XSetWMName`, `XSetWMHints`, etc.) |
| `winputmethod.c` | 40 | XIM/XIC lifecycle (`XOpenIM`, `XCreateIC`, `XLookupString`) |
| `dragdestination.c` | 37 | XDND protocol (receive side) |
| `widgets.c` | 35 | Screen init, GC/cursor creation, modifier mapping |
| `wballoon.c` | 28 | Tooltip drawing, shape extension |
| `wtext.c` | 23 | Clipboard, grabs |
| `selection.c` | 21 | X selection protocol |
| `dragcommon.c` | 16 | XDND shared atom/property helpers |
| `wappresource.c` | 15 | App icon property reading |
| `wtextfield.c` | 10 | Clipboard, grabs |
| `wpopupbutton.c` | 7 | Pointer grabs |
| `wruler.c` | 3 | `XRectangle` type usage |
| `wmisc.c` | 2 | Coordinate translation |
These files need backend abstraction — either routing through the existing
5 vtables, or adding new vtables for DND, selection, and input methods.
### WINGs Porting Strategy
- [x] **DND subsystem** (`dragsource.c` + `dragdestination.c` + `dragcommon.c`, 2437 LOC,
98 calls) — **done**. Compositor-internal DND fully functional (drag image, cursor feedback,
hit-testing via W_FindViewAtPoint, modal drag loop in wl_drag_begin). Cross-client DND
(wl_data_device) has basic wiring — needs MIME type → WINGs type routing to complete.
- [x] **`wcolorpanel.c`** (3556 LOC, 89 calls) — **done**. Split into three files:
`wcolorpanel.c` (backend-neutral, 2997 lines), `wcolorpanel_x11.c` (X11 magnifying glass,
601 lines), `wcolorpanel_wl.c` (Wayland stub). Magnify button shows "not available"
dialog on Wayland. All 89 X11 calls isolated to `wcolorpanel_x11.c`.
3. **`wwindow.c` + `widgets.c`** (1849 LOC, 76 calls) — window property management
needs backend dispatch (ICCCM is X11-only; Wayland properties differ).
4. **`winputmethod.c`** (243 LOC, 40 calls) — replace XIM/XIC with
`zwp_text_input_v3` or use xkbcommon directly.
5. **`selection.c`** (392 LOC, 21 calls) — replace X selection protocol with
`wl_data_device` / `zwp_primary_selection_v1`.
6. **`wballoon.c`** (476 LOC, 28 calls) — route drawing through `W_RenderBackend`.
7. **`wtext.c` + `wtextfield.c`** (5577 LOC, 33 calls) — route clipboard and
grabs through backends.
---
## Priority 3: Visual Completeness
### 3.1 Iconify/Deiconify Zoom Animation
The X11 path uses XOR GC rubber-band rectangles (`XGrabServer` + `XDrawRectangle`).
On Wayland, implement as per-frame pixman overlay buffer.
- [ ] Implement `overlay_draw_rect` in wl_backend.c using a transient `wlr_scene_buffer`
- [ ] Wire `animateResize()` in actions.c to use the vtable
### 3.2 Client Snapshot (Window Thumbnails)
Used by switch panel and icon preview. X11 uses `XGetImage`. Wayland options:
- Render last committed `wlr_texture` into an RImage via pixman blit
- Use `wlr_screencopy_manager_v1`
- [ ] Implement `client_snapshot` vtable slot using last-committed texture
### 3.3 Window Inspector
`src/winspector.c` — WINGs-based dialog. Should work on Wayland since WINGs
widgets are ported. Needs testing.
- [ ] Test window inspector opens and displays attributes
- [ ] Test attribute changes apply correctly
---
## Priority 4: HiDPI & Scaling
- [ ] Set `wlr_output_set_scale` per output
- [ ] Multiply pixman buffer allocations by scale factor
- [ ] Set PangoFT2 DPI from `output.scale * 96.0`
- [ ] Ensure `WScreen.width/height` remain logical coordinates
- [ ] Test at 2x scale
---
## Priority 5: Protocol Wiring
wlroots already advertises these protocols. Wire them to policy:
| Protocol | Purpose | Effort |
|----------|---------|--------|
| `ext-session-lock-v1` | Screen lock | Medium |
| `xdg_activation_v1` | Focus stealing prevention | Low |
| `zwp_idle_inhibit_manager_v1` | Prevent blank during video | Low |
| `ext-foreign-toplevel-list-v1` | Taskbar integration | Low |
| `zwp_input_method_v2` | IME support | Medium |
| `wlr_gamma_control_v1` | Night light | Low |
---
## Priority 6: DRM/KMS Native Backend
For running without a host compositor:
- [ ] Use `wlr_backend_autocreate` (replaces headless/nested)
- [ ] libinput for real hardware input (wlroots handles this)
- [ ] VT switching via `wlr_session`
- [ ] Test on real hardware
---
## Architecture Notes
- **Rendering pattern**: pixman_image_t → wlr_scene_buffer → scene graph position
- **Event flow**: wlroots signals → wl_backend.c handlers → WMEvent → DispatchEvent
- **WINGs on Wayland**: compositor-internal views (not wl_surfaces), pixman-rendered,
events via ring buffer from compositor hit-testing
- **wl_backend.c (420K) should be split** into wl_frame.c, wl_menu.c, wl_input.c,
wl_toplevel.c, wl_output.c as complexity grows
---
## Reference Documents
| Document | Purpose |
|----------|---------|
| `ARCHITECTURE.md` | Codebase structure, data flow, key types |
| `BACKEND_ABSTRACTION.md` | Historical analysis of X11 leaks (all resolved) |
| `X11_IMPLEMENTATION.md` | How X11 path works (correctness reference) |
| `ACTION_PLAN_PROMPTS.md` | Task templates for mechanical porting work |
| `tools/wm-port/` | Agent-assisted task dispatch tooling |