summaryrefslogtreecommitdiffhomepage
path: root/.rules/plan/phase-02-window-manager.md
blob: 2627a57935b704e0c2e9b189d175e7ee6a0705c9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
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.