11 KiB
WindowMaker Wayland Port — Roadmap
Last updated: 2026-05-14
Governing Principles
-
No guards in the middle — the core (src/, wrlib/, WINGs/) never asks "am I on X11 or Wayland?" Backend-specific behavior lives exclusively in the backend that owns it. Zero
#ifdef WAYLANDor runtime backend checks in shared code. -
Duplication over coupling — if both backends need similar-but-not-identical logic, each gets its own copy. Shared abstractions that leak backend details are forbidden. Clarity and independence beat DRY.
-
Fail fast, fail loudly — no defensive null checks, no silent fallbacks, no "just in case" guards. If a precondition is violated, crash immediately with a clear signal. Defensive coding for the sake of being defensive is not acceptable.
-
Perfect architecture over fewer lines — the right structure wins even if it means more files or duplicated code. Clean separation now buys simple reasoning forever.
┌─────────────┐ ┌─────────────────────────┐ ┌─────────────────┐
│ X11 Backend │◄────┤ Core / wrlib / WINGs ├────►│ Wayland Backend │
└─────────────┘ └─────────────────────────┘ └─────────────────┘
│ │ │
backend-specific pure policy, backend-specific
special cases zero backend guards special cases
Architecture
WindowMaker 0.96.0 uses a vtable-based backend abstraction (WMBackend struct in
src/backend/backend.h) with ~150+ function pointer slots. Policy code calls
wm_backend->operation(...) and never touches X11/Wayland APIs directly.
Two backends:
- X11:
src/backend/x11/x11_backend.c(150K) - Wayland:
src/backend/wayland/wl_backend.c(316K, wlroots-based compositor)
Activation: WMAKER_USE_WAYLAND=1 env var. Nested mode: WMAKER_WAYLAND_NESTED=1.
Three major libraries:
- src/ — WM core (policy layer, zero Xlib calls remaining)
- WINGs/ — Widget toolkit ("WINGs Is Not GNUstep"), split into
_x11.c/_wl.cbackends - wrlib/ — Raster graphics library (image loading, manipulation, rendering)
Completed (as of 2026-05-14)
- Backend vtable abstraction (150+ slots)
- Policy layer fully X11-free (zero direct Xlib calls in WM core)
- wlroots compositor (headless + nested modes)
- XDG shell + XWayland bridge
- Frame rendering (titlebar, buttons, resizebar) via pixman → wlr_scene_buffer
- Menu rendering + highlighting + item activation
- Root menu from config file
- Dock rendering (SHM panel, icon slots, app tracking)
- Clip rendering
- Background rendering
- Mouse input (motion, buttons, scroll, grabs)
- Keyboard input (XKB, modifiers, keysym translation)
- Interactive move/resize with edge detection + cursor changes
- Click-to-focus via hit-testing
- Run dialog (WINGs modal loop with compositor tick)
- Window manage/unmanage lifecycle (XDG toplevel + XWayland)
- Focus delivery (wlr_seat_keyboard_notify_enter)
- WINGs Wayland backend (views, fonts/PangoFT2, events/ring buffer, rendering/pixman, colors)
- Smoke test suite (30+ tests in tests/wl-smoke-test.sh)
Phase A: Core Window Management Gaps
Priority: HIGH — needed for daily-driver use.
| # | Task | Key Files | Complexity |
|---|---|---|---|
| A1 | stacking.c, wlr_scene_node_raise/lower | ✅ Done | |
| A2 | actions.c, usable area calc | ✅ Done | |
| A3 | actions.c, frame buffer resize | ✅ Done | |
| A4 | Workspace switching (create/destroy/switch) | workspace.c, scene tree reparenting | Medium |
| A5 | Alt-Tab window cycling + switch panel | cycling.c, switchpanel.c, vtable switchpanel_enter | Medium |
| A6 | icon.c, appicon.c, vtable icon_paint/icon_update_pixmap | Done | |
| A7 | Window placement algorithms (smart/cascade/random) | placement.c (may already work via vtable) | Low |
Phase B: Dock & App Icons
| # | Task | Key Files | Complexity |
|---|---|---|---|
| B1 | App icon rendering (load .tiff/.png, render into dock) | appicon.c, wrlib loaders, vtable appicon_show | Medium |
| B2 | Dock icon drag & drop (reorder, add/remove) | dock.c DnD handlers | Medium |
| B3 | Dock auto-launch on login | dock.c session restore | Low |
| B4 | Clip workspace indicator (number, arrows) | dock.c clip paint | Low |
| B5 | Drawer support (horizontal dock extension) | dock.c drawer subsystem | Medium |
| B6 | Icon bounce on launch | vtable appicon_bounce | Low |
Phase C: Visual Polish & Animations
| # | Task | Key Files | Complexity |
|---|---|---|---|
| C1 | Slide animations (iconify/deiconify zoom) | vtable slide_window | Medium |
| C2 | Menu scrolling (long menus) | menu.c scroll logic | Low |
| C3 | Balloon tooltips (dock icon hover) | vtable balloon_show | Low |
| C4 | Cursor themes (xcursor loading) | wlr_xcursor_manager | Low |
| C5 | Window opacity (NETWM alpha) | vtable netwm_set_opacity | Low |
Phase D: WINGs Widgets (for Preferences & Inspectors)
Core rendering backends exist. Complex widgets need verification/porting:
| Widget | Needed For | Notes |
|---|---|---|
| WMList | File panels, icon chooser | Test |
| WMBrowser | File browser in dialogs | Test |
| WMColorPanel | Color picker in prefs | May need porting |
| WMFontPanel | Font selection | May need porting |
| WMFilePanel | Open/save dialogs | Test |
| WMTabView | Preferences app tabs | Test |
| WMScroller/WMScrollView | Scrollable content | Test |
| WMSlider | Preference sliders | Test |
| WMPopUpButton | Dropdown menus in prefs | Test |
| WMTextField (advanced) | Multi-line editing | Test |
| Drag & Drop | Icon DnD, file DnD | Likely needs porting |
Phase E: Dialogs & Panels
| # | Task | Key Files | Complexity |
|---|---|---|---|
| E1 | Window Inspector (per-window attributes) | winspector.c | High (many widgets) |
| E2 | Info Panel (about dialog) | dialog.c | Low |
| E3 | Crash Dialog (recovery UI) | dialog.c | Low |
| E4 | Icon Chooser (browse icon files) | dialog.c | Medium |
| E5 | Preferences App (full GUI) | WPrefs.app/ | High |
Phase F: wrlib Wayland Integration
| # | Task | Description | Complexity |
|---|---|---|---|
| F1 | RContext for Wayland | pixman-backed RContext without X11 Display | Medium |
| F2 | RImage → pixman_image conversion | Direct path without XImage | Low (may exist) |
| F3 | Texture rendering verification | Solid, gradient, pixmap textures | Verify |
| F4 | Image format loaders | PNG/JPEG/GIF/WebP (X11-independent) | Verify |
Phase G: Session & Persistence
| # | Task | Key Files | Complexity |
|---|---|---|---|
| G1 | Session save/restore (positions, workspaces) | session.c | Medium |
| G2 | Dock state persistence (icon layout) | dock.c state files | Low (may work) |
| G3 | Defaults database (~/GNUstep/Defaults/) | defaults.c | Verify |
| G4 | Autostart (launch apps from session) | startup.c | Low |
Phase H: Advanced Compositor Features
| # | Task | Description | Complexity |
|---|---|---|---|
| H1 | Multi-monitor (output layout, per-output workspaces) | wlr_output_layout, screen.c | High |
| H2 | HiDPI / output scaling | wlr_output_set_scale, buffer scaling | Medium |
| H3 | Gamma control (night light) | Already advertised, wire up | Low |
| H4 | Screen lock integration | ext-session-lock-v1 protocol | Medium |
| H5 | Clipboard (copy/paste between clients) | wl_data_device (may work via wlroots) | Verify |
| H6 | Primary selection | Already advertised | Verify |
| H7 | Screencopy (screenshots) | Already advertised | Verify |
| H8 | DMA-BUF (GPU buffer sharing) | Already advertised | Verify |
| H9 | Input method (IME support) | Already advertised | Medium |
Phase I: EWMH / Foreign Toplevel
| # | Task | Description | Complexity |
|---|---|---|---|
| I1 | Foreign toplevel list (taskbar integration) | Already advertised, verify events | Low |
| I2 | XDG activation (focus stealing prevention) | Wire to policy | Low |
| I3 | Idle inhibit (prevent blank during video) | Already advertised | Low |
Phase J: DRM/KMS Backend (Native)
For running without a host compositor:
| # | Task | Description | Complexity |
|---|---|---|---|
| J1 | DRM backend | wlr_backend_autocreate | Medium |
| J2 | libinput (real hardware input) | wlroots handles this | Low |
| J3 | VT switching | wlr_session | Low |
| J4 | Multi-GPU | Secondary GPU rendering | High |
Suggested Implementation Order
NOW (daily-driver basics):
A1. Stacking (raise/lower)
A2. ~~Maximize~~ ✅
A3. ~~Shade~~ ✅
A4. Workspace switching
A5. Alt-Tab cycling
A6. Icon/minimize
A7. Placement (verify)
NEXT (visual completeness):
B1. App icon rendering (wrlib → pixman)
F1. wrlib RContext for Wayland
C1. Slide animations
C3. Balloon tooltips
THEN (full feature parity):
D*. Test all WINGs widgets
E1. Window Inspector
E4. Icon Chooser
G*. Session persistence
B2-B6. Full dock features
LATER (production-ready):
H1. Multi-monitor
H2. HiDPI
J*. DRM/KMS native backend
E5. WPrefs app
Technical Notes
- Rendering pattern: pixman_image_t → wlr_scene_buffer → position in scene graph
- wrlib is mostly X11-independent — only context.c and convert.c touch X11
- WINGs complex widgets are the hardest remaining work (subtle X11 assumptions in events/coords)
- wlroots handles compositor plumbing — protocols advertised, work is wiring to policy
- wl_backend.c (316K) should be split into wl_frame.c, wl_menu.c, wl_input.c, wl_toplevel.c, wl_output.c as complexity grows
- Many vtable slots are no-ops — stubs exist, need implementation following the pixman→scene pattern
Key Source Files Reference
| File | Size | Purpose |
|---|---|---|
| src/backend/backend.h | 74K | Vtable definition |
| src/backend/backend_types.h | 16K | Backend-neutral types |
| src/backend/wayland/wl_backend.c | 316K | Wayland compositor |
| src/backend/x11/x11_backend.c | 150K | X11 backend |
| src/window.c | 83K | Window management |
| src/dock.c | 130K | Dock/Clip/Drawers |
| src/menu.c | 61K | Menu system |
| src/actions.c | 68K | Window actions |
| src/defaults.c | 102K | Preferences/config |
| src/event.c | 61K | Event dispatch |
| src/moveres.c | 67K | Move/resize |
| src/wmspec.c | 61K | EWMH compliance |
| src/main.c | 22K | Entry point |
| WINGs/WINGs.h | 56K | Toolkit public API |
| wrlib/wraster.h | 17K | Raster lib public API |