windowmaker-wl/ARCHITECTURE.md

247 lines
12 KiB
Markdown

# WindowMaker 0.96.0 — Architecture Overview
## Top-Level Directory Map
| Directory | Role | LOC (`.c`) |
|---|---|---|
| **`src/`** | **Window manager core** — policy, layout, event dispatch | ~26k |
| **`src/backend/`** | Display-system abstraction (X11 + Wayland vtable) | ~18k |
| **`WINGs/`** | Widget library (buttons, text fields, panels, etc.) + utility library (WUtil) | ~40k |
| **`wrlib/`** | **Raster graphics library** — image loading, scaling, gradients, format codecs | ~9k |
| **`wmlib/`** | Tiny helper library for external apps to talk to the WM (menus, events) | ~500 |
| **`WPrefs.app/`** | Preferences GUI application (uses WINGs) | ~15k |
| **`util/`** | CLI utilities: `wmsetbg`, `wmagnify`, `wmiv`, `getstyle`, `setstyle`, etc. | ~7k |
| **`WindowMaker/`** | Runtime data: default menus, themes, icon sets, pixmaps (no code) | — |
| **`doc/`** | Documentation | — |
| **`po/`** | Translations (gettext) | — |
## 1. The Core — `src/`
This is the window manager itself. The biggest files reveal the hotspots:
| File | LOC | Responsibility |
|---|---|---|
| `dock.c` | 4884 | Dock & clip (app launcher bar) |
| `defaults.c` | 3470 | Reading/writing the defaults database (user prefs) |
| `window.c` | 2891 | `WWindow` lifecycle — manage, unmanage, configure |
| `moveres.c` | 2448 | Interactive move/resize (rubber-banding, snap) |
| `menu.c` | 2410 | Menu data structure, drawing, keyboard navigation |
| `actions.c` | 2338 | High-level window actions (maximize, shade, close…) |
| `event.c` | 1953 | **Main event loop + dispatch** |
| `framewin.c` | 1251 | Frame window (titlebar, buttons, resizebar) drawing |
| `icon.c` | 971 | Miniwindow / app icon rendering |
| `workspace.c` | 914 | Virtual desktop management |
| `screen.c` | 641 | Per-screen state (`WScreen`) init/teardown |
| `startup.c` | 645 | `StartUp()` — full WM initialization sequence |
| `main.c` | 801 | `main()` — arg parsing, backend selection, enters `EventLoop()` |
### Key Data Structures
- **`WScreen`** (`screen.h`, 352 lines) — god object for a physical screen. Holds the root window, stacking lists, colormap, default pixmaps, the dock, the clip, workspace list, and the backend-specific `backend_screen` pointer.
- **`WWindow`** (`window.h`) — one per managed client. Contains the `WFrameWindow`, client hints, geometry, state flags.
- **`WFrameWindow`** (`framewin.h`) — the decoration frame. Has child `WCoreWindow`s for the titlebar, left/right buttons, and resizebar.
- **`WCoreWindow`** (`wcore.h`) — lowest-level wrapper around a native window. Every WM-owned window (frames, icons, menus) is a `WCoreWindow`. Contains a `WObjDescriptor`.
- **`WObjDescriptor`** (`WindowMaker.h`) — the **event dispatch target**. Every `WCoreWindow` carries one. It has four function pointers:
```c
void (*handle_expose)(WObjDescriptor *sender, WBackendEvent *event);
void (*handle_mousedown)(...);
void (*handle_enternotify)(...);
void (*handle_leavenotify)(...);
```
Plus a `parent_type` / `parent` back-pointer so dispatch can reach the owning `WWindow` or `WMenu`.
## 2. Event Dispatch — `src/event.c`
The flow is:
```
main()
→ StartUp() // init screens, load defaults, manage existing windows
→ EventLoop() // never returns
→ wm_backend->event_loop_run()
// X11: WINGs event pump (WMNextEvent + WMHandleEvent)
// Wayland: wl_display_run()
```
Inside the X11 path, each event ends up at:
```
DispatchEvent(WMEvent *event)
→ switch (event->type)
WME_MAP_REQUEST → handleMapRequest()
WME_KEY_PRESS → handleKeyPress()
WME_BUTTON_PRESS → handleButtonPress()
WME_EXPOSE → handleExpose()
WME_PROPERTY → handlePropertyNotify()
WME_CONFIGURE_REQUEST → handleConfigureRequest()
...
```
Most handlers look up the target window via `wm_backend->context_find(win, WM_CTX_CLIENT_WIN)` to get the `WObjDescriptor`, then call its function pointers (e.g., `desc->handle_mousedown(desc, event)`).
**Signal handling** is also routed through `DispatchEvent` — `SIGTERM` sets `WSTATE_NEED_EXIT`, `SIGHUP` sets `WSTATE_NEED_RESTART`, and the top of `DispatchEvent` checks these flags before processing the event.
## 3. Backend Abstraction — `src/backend/`
A **vtable pattern** (`WMBackend` struct, 1915-line header with ~250 function pointer slots) with a single global pointer:
```c
extern const WMBackend *wm_backend; // set in main() before anything else
```
`main.c` picks the backend:
```c
wm_backend = &wl_backend; // or
wm_backend = &x11_backend;
```
The vtable covers **everything** the display system does:
| Category | Example slots |
|---|---|
| Display lifecycle | `display_open`, `display_close`, `display_post_open` |
| Screen lifecycle | `screen_open`, `screen_init_display`, `screen_close` |
| Frame windows | `frame_create_toplevel`, `frame_create_child`, `frame_destroy`, `frame_configure`, `frame_paint` |
| Context table | `context_save`, `context_find`, `context_delete` |
| Event loop | `event_loop_run`, `event_loop_terminate`, `event_sync`, `event_pending` |
| Focus & grabs | `focus_set`, pointer/keyboard grab |
| Atoms & properties | `atom_intern`, property get/set |
Implementations:
- **`backend/x11/x11_backend.c`** (4998 lines) — wraps Xlib calls
- **`backend/wayland/wl_backend.c`** (10109 lines) — wlroots compositor
- **`backend/x11/x11_event.c`** — X11-specific event translation
- **`backend/x11/x11_props.c`** — X11 property helpers
- **`backend/x11/x11_monitor.c`** — Xinerama/XRandR monitor detection
- **`backend/x11/wmspec.c`** (2015 lines) — EWMH / `_NET_WM_*` compliance
- **`backend/x11/xdnd.c`** (323 lines) — X11 drag-and-drop protocol
The event type itself is backend-neutral: `WMEvent` / `WBackendEvent` defined in `WINGs/WINGs/WMEvent.h` with an enum (`WME_KEY_PRESS`, `WME_BUTTON_PRESS`, `WME_MAP_REQUEST`, etc.).
## 4. WINGs — Widget Library (`WINGs/`)
Two sub-libraries in one directory:
### WINGs widgets (`WINGs/WINGs/WINGs.h`, 1933 lines)
Full GUI toolkit with an NeXTSTEP flavor:
| Widget file | What |
|---|---|
| `wwindow.c` | Top-level windows |
| `wbutton.c` | Buttons |
| `wtextfield.c` | Single-line text input |
| `wtext.c` | Multi-line rich text (3998 lines — the biggest widget) |
| `wlist.c` | List boxes |
| `wbrowser.c` | Column browser (NeXT-style) |
| `wscroller.c` / `wscrollview.c` | Scrollbars and scroll containers |
| `wslider.c` | Sliders |
| `wpopupbutton.c` | Popup/dropdown buttons |
| `wcolorpanel.c` | Color picker panel |
| `wcolorwell.c` | Color swatch |
| `wfontpanel.c` | Font chooser |
| `wfilepanel.c` | Open/save file dialogs |
| `wtabview.c` | Tab views |
| `wsplitview.c` | Split panes |
| `wruler.c` | Text ruler |
| `wframe.c` | Group boxes |
| `wlabel.c` | Labels |
| `wballoon.c` | Tooltip balloons |
| `wpanel.c` | Alert/input panels |
Core plumbing:
- **`wview.c`** / `wview_wl.c` / `wview_x11.c` — the view hierarchy (WINGs' equivalent of a "widget base class")
- **`wevent.c`** / `wevent_wl.c` / `wevent_x11.c` — WINGs event handling
- **`wrender_wl.c`** / `wrender_x11.c` — rendering backend split
- **`wfont.c`** / `wfont_wl.c` / `wfont_x11.c` — font rendering split
- **`wcolor.c`** / `wcolor_wl.c` / `wcolor_x11.c` — color allocation split
### WUtil (`WINGs/WINGs/WUtil.h`, 959 lines)
Utility library used everywhere:
- `array.c`, `bagtree.c`, `hashtable.c`, `tree.c` — data structures
- `proplist.c` — NeXTSTEP-style property list parser (used for defaults database)
- `notification.c` — notification center
- `userdefaults.c` — user defaults system
- `findfile.c`, `string.c`, `memory.c`, `misc.c` — general utilities
- `handlers.c` — idle/timer handlers
- `selection.c` — X selection (clipboard)
- `menuparser.c` — menu file parser
## 5. Rendering — `wrlib/`
**wrlib** (Window Maker Raster Library) is a standalone image manipulation library:
- **Image formats**: PNG, JPEG, TIFF, GIF, XPM, PPM, WebP, ImageMagick (each in `load_*.c` / `save_*.c`)
- **Operations**: `scale.c`, `rotate.c`, `flip.c`, `gradient.c`, `convolve.c`, `draw.c`, `alpha_combine.c`
- **Display bridge**: `convert.c` / `convert_x11.c` / `convert_wl.c` — converts `RImage` to display-system pixmaps
- **Context**: `context.c` — `RContext` wraps the display connection + visual for rendering
The WM core uses wrlib for all texture/icon rendering (via `texture.c` and `icon.c` in `src/`).
## 6. Rendering in the WM Core — `src/texture.c`, `src/framewin.c`
- **`WTexture`** (`texture.h`) is a union of solid color, gradients, and pixmap-based textures. `wTextureRender()` / `wTextureRenderImage()` produce `Pixmap`s or `RImage`s from these.
- **`framewin.c`** paints the actual window decorations — titlebar, buttons, resizebar — using textures. The backend vtable's `frame_paint()` slot allows the Wayland backend to override the entire paint path.
- **`WPixmap`** (`pixmap.h`) is a simple image+mask pair used for icons and button pixmaps.
## 7. Stacking
`stacking.c` / `stacking.h` — manages the window stacking order using **window levels** (defined in `WindowMaker.h`):
```
WMBackLevel → WMDesktopLevel → WMNormalLevel → WMFloatingLevel → WMDockLevel
→ WMSubmenuLevel → WMMainMenuLevel → WMFullscreenLevel → WMPopUpLevel → ...
```
## 8. Supporting Programs
- **`WPrefs.app/`** — full preferences editor. Each `*.c` file is a preference panel (Appearance, Focus, Docks, Icons, Keyboard, Mouse, etc.). Uses WINGs widgets.
- **`util/`** — CLI tools: `wmsetbg` (set background), `wmagnify` (screen magnifier), `wmiv` (image viewer), `getstyle`/`setstyle` (theme import/export), `wmgenmenu`/`wmmenugen` (auto-generate menus from `.desktop` files).
## Dependency Graph
```
┌─────────────────────────────────────────────────────┐
│ WPrefs.app │
│ util/ │
└──────────────┬──────────────────┬───────────────────┘
│ │
▼ ▼
┌──────────────────┐ ┌─────────────────┐
│ WINGs widgets │ │ src/ (WM core)│
│ WINGs/w*.c │ │ policy + layout│
└───────┬──────────┘ └──┬──────────────┘
│ │
│ ┌─────────────┘
▼ ▼
┌──────────────────┐ ┌─────────────────────────┐
│ WUtil │ │ src/backend/ │
│ (data structs, │ │ backend.h vtable │
│ proplist, etc) │ │ ┌─────────┬───────────┐ │
└───────┬──────────┘ │ │ x11/ │ wayland/ │ │
│ │ └─────────┴───────────┘ │
▼ └────────────┬──────────────┘
┌──────────────────┐ │
│ wrlib │◄────────────────┘
│ (image loading, │
│ rendering) │
└──────────────────┘
```
## Key Architectural Patterns
1. **Vtable backend abstraction** — all display-system calls go through `wm_backend->*()`. Policy code never calls Xlib directly.
2. **Context-table dispatch** — native window → `WObjDescriptor` lookup via `context_find()`. This is how events reach the right object.
3. **`WObjDescriptor` function pointers** — per-object event handlers (expose, mousedown, enter, leave). This is the closest thing to polymorphic dispatch in the codebase.
4. **Flat C module structure** — no deep directory nesting. Each `src/*.c` file is a module with a matching `.h`. Dependencies are explicit `#include`s.
5. **Three rendering layers**: wrlib (`RImage` manipulation) → `WTexture` (WM-level texture descriptions) → `framewin.c` / `icon.c` (actual decoration painting).
6. **Wayland as a parallel backend** — not a port, but a second implementation behind the same vtable. The `_wl.c` / `_x11.c` file splits in WINGs show this pattern extending into the widget library too.