diff options
Diffstat (limited to '.rules/plan/phase-02-window-manager.md')
| -rw-r--r-- | .rules/plan/phase-02-window-manager.md | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/.rules/plan/phase-02-window-manager.md b/.rules/plan/phase-02-window-manager.md new file mode 100644 index 0000000..2627a57 --- /dev/null +++ b/.rules/plan/phase-02-window-manager.md @@ -0,0 +1,93 @@ +# Phase 2 — Become a Window Manager + +--- + +## Step 2.1 — Open an Xlib display connection alongside raylib + +Before `InitWindow()`, call `XOpenDisplay(NULL)` to get a `Display*`. +Store it globally. Get the root window with `DefaultRootWindow()`. After +the raylib loop exits, `XCloseDisplay()`. + +Print the display name and root window ID to confirm. + +**Verify:** The output prints something like `Display: :1, Root: 0x...`. +Raylib window still works as before. + +--- + +## Step 2.2 — Register as the window manager (SubstructureRedirect) + +After opening the display, call: + +```c +XSelectInput(dpy, root, + SubstructureRedirectMask | + SubstructureNotifyMask | + StructureNotifyMask); +XSync(dpy, False); +``` + +Set a custom X error handler that catches `BadAccess` (another WM is +already running) and prints a clear message. + +**Verify:** Running in Xephyr succeeds (no other WM). Running a second +instance prints "Another window manager is already running" and exits. + +--- + +## Step 2.3 — Process X events in the raylib loop + +Inside the raylib `while (!WindowShouldClose())` loop, add a non-blocking +X event drain: + +```c +while (XPending(dpy) > 0) { + XEvent ev; + XNextEvent(dpy, &ev); + printf("Event: %d\n", ev.type); +} +``` + +**Verify:** `./bin/run.sh --clients` — launching `xeyes` or `xterm` into +`:1` prints `MapRequest`, `ConfigureRequest`, etc. to the terminal. The +clients don't appear yet (because we don't handle `MapRequest`). + +--- + +## Step 2.4 — Handle MapRequest and ConfigureRequest (basic) + +Add a simple event handler: + +- **`MapRequest`** → call `XMapWindow(dpy, ev.xmaprequest.window)`. +- **`ConfigureRequest`** → honor the request by calling + `XConfigureWindow()` with the requested values. + +**Verify:** `./bin/run.sh --clients` — `xeyes`, `xclock`, and `xterm` now +appear inside the Xephyr window. They're drawn by X directly (not +composited yet), floating on top of/beside the raylib window. You can type +in `xterm`. + +--- + +## Step 2.5 — Track managed windows in a list + +Create a simple dynamic array (or linked list) of `WmWindow` structs: + +```c +typedef struct { + Window xwin; + int x, y; + unsigned int width, height; + bool mapped; +} WmWindow; +``` + +- On `MapRequest`: add the window to the list, then `XMapWindow`. +- On `UnmapNotify`: mark `mapped = false`. +- On `DestroyNotify`: remove from the list. +- On `ConfigureRequest`: update stored geometry, then `XConfigureWindow`. + +Print the window list count on each change. + +**Verify:** Spawn/close clients in `:1`. The log shows windows being added +and removed. Count matches what's visible. |
