# 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 ` changes the draw order.