summaryrefslogtreecommitdiffhomepage
path: root/.rules/plan/phase-03-compositing.md
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-04-11 19:06:35 +0900
committerAdam Malczewski <[email protected]>2026-04-11 19:06:35 +0900
commit93f50d20a021150a0b95242be0d5dd5cae9d0185 (patch)
tree48054581d580974651260900d1ef79d370872952 /.rules/plan/phase-03-compositing.md
downloadwinman-raylib-93f50d20a021150a0b95242be0d5dd5cae9d0185.tar.gz
winman-raylib-93f50d20a021150a0b95242be0d5dd5cae9d0185.zip
plan and researchmain
Diffstat (limited to '.rules/plan/phase-03-compositing.md')
-rw-r--r--.rules/plan/phase-03-compositing.md106
1 files changed, 106 insertions, 0 deletions
diff --git a/.rules/plan/phase-03-compositing.md b/.rules/plan/phase-03-compositing.md
new file mode 100644
index 0000000..a85d12b
--- /dev/null
+++ b/.rules/plan/phase-03-compositing.md
@@ -0,0 +1,106 @@
+# Phase 3 — Compositing: Redirect & Capture Window Contents
+
+---
+
+## Step 3.1 — Query and enable the Composite extension
+
+At startup (after becoming WM), call:
+
+```c
+XCompositeQueryExtension(dpy, &composite_event, &composite_error);
+XCompositeQueryVersion(dpy, &major, &minor);
+XCompositeRedirectSubwindows(dpy, root, CompositeRedirectManual);
+```
+
+Print the extension version to confirm.
+
+**Verify:** Prints "Composite extension: 0.4" (or similar). Clients
+launched into `:1` are now **invisible** (redirected to off-screen pixmaps
+but nobody is painting them). This is expected — the WM is responsible for
+compositing now.
+
+---
+
+## Step 3.2 — Name window pixmaps
+
+When a window is mapped (in the `MapRequest` handler or after
+`XMapWindow`), call:
+
+```c
+Pixmap pixmap = XCompositeNameWindowPixmap(dpy, win->xwin);
+```
+
+Store the `Pixmap` in the `WmWindow` struct. On `ConfigureNotify` (resize),
+free the old pixmap and re-obtain it.
+
+**Verify:** No visual change yet (windows are still invisible), but no X
+errors are printed. Confirm pixmap handles are non-zero via log output.
+
+---
+
+## Step 3.3 — Read pixmap into a raylib Texture (CPU copy path)
+
+For each mapped window with a valid pixmap:
+
+1. Call `XGetImage(dpy, pixmap, 0, 0, width, height, AllPlanes, ZPixmap)`
+ to read the pixel data.
+2. Convert the BGRA data (X11 format) to RGBA.
+3. Create a raylib `Image` from the buffer, then `LoadTextureFromImage()`.
+4. Store the `Texture2D` in the `WmWindow` struct.
+
+In the raylib draw loop, draw each managed window's texture at its
+position using `DrawTexture()`.
+
+**Verify:** `./bin/run.sh --clients` — `xeyes`, `xclock`, and `xterm`
+appear as textured quads rendered by raylib on the dark blue background.
+They are static snapshots (no live updates yet). The raylib window is the
+compositor.
+
+---
+
+## Step 3.4 — Enable the Damage extension for live updates
+
+At startup, query and enable Damage:
+
+```c
+XDamageQueryExtension(dpy, &damage_event, &damage_error);
+```
+
+For each managed window, create a damage object:
+
+```c
+win->damage = XDamageCreate(dpy, win->xwin, XDamageReportNonEmpty);
+```
+
+In the event loop, handle `DamageNotify`:
+
+```c
+if (ev.type == damage_event + XDamageNotify) {
+ // mark the window dirty
+ win->dirty = true;
+}
+```
+
+When a window is dirty, before drawing, re-read the pixmap via
+`XGetImage`, update the texture with `UpdateTexture()`, then call
+`XDamageSubtract(dpy, win->damage, None, None)`.
+
+**Verify:** `xeyes` follows your mouse cursor in real-time. `xclock`
+ticks. Typing in `xterm` is visible immediately. This is a working (CPU-
+copied) compositor.
+
+---
+
+## Step 3.5 — Handle window stacking order
+
+Draw windows in the correct stacking order (bottom to top). Maintain the
+list order to match X's stacking order. Use `XQueryTree()` at startup to
+get the initial order, and update on `ConfigureNotify` with
+`Above`/`Below` sibling fields, or re-query when the stack changes.
+
+Also handle `XRaiseWindow` / `XLowerWindow` requests via
+`ConfigureRequest`.
+
+**Verify:** Overlapping windows draw in the correct order. Clicking
+`xterm` (if focus-follows-click is wired) or manually calling
+`DISPLAY=:1 xdotool windowraise <id>` changes the draw order.