247 lines
12 KiB
Markdown
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.
|