redox-wayland-compositor/docs/phase7-1-xdg-shell.md

203 lines
7.9 KiB
Markdown
Raw Normal View History

🎉 Phase 7.1 — xdg-shell minimal validé runtime Capture preuve : docs/phase7-1-xdg-toplevel.png — fenêtre 320x240 du client externe positionnée à (60, 60) par le compositor (cascade par défaut), avec bandes verticales arc-en-ciel + bordure noire 2px. Différence visuelle vs phase 6.4 : la fenêtre est maintenant positionnée par le compositor (pas plaquée à 0,0). Modifications redox-wl-wayland-frontend : - + dep wayland-protocols (feature server) - xdg_wm_base global v5 - XdgSurfaceData { wl_surface, last_serial, acked_serial } - XdgToplevelData { title, app_id } - SurfaceData.xdg_pending_initial_configure : bloque l'affichage tant que ack-configure pas reçu (sémantique xdg-shell standard) - WaylandFrontend.next_xdg_serial : counter monotone serial - WaylandFrontend.next_toplevel_index : cascade position +60 par fenêtre - DEFAULT_TOPLEVEL_SIZE = 640x480 envoyé en initial configure - Dispatch xdg_wm_base : GetXdgSurface, CreatePositioner (no-op), Pong (no-op), Destroy (no-op) - Dispatch xdg_positioner + xdg_popup : no-op (out of scope) - Dispatch xdg_surface : - GetToplevel → cascade pos + envoie xdg_toplevel.configure(640,480) + xdg_surface.configure(serial) - AckConfigure(serial) → enregistre + débloque affichage - Destroy → cache la surface - Dispatch xdg_toplevel : - SetTitle / SetAppId → stocke - tout le reste ignoré (move, resize, maximized, ...) redox-wl-test-client-shm adapté : - + dep wayland-protocols (feature client) - bind 3 globals : wl_compositor, wl_shm, xdg_wm_base - Dispatch XdgWmBase::Event::Ping → pong (au cas où) - Dispatch XdgSurface::Event::Configure → store serial - Dispatch XdgToplevel::Event::Configure / Close → log - Workflow runtime : 1. create_surface + get_xdg_surface + get_toplevel 2. set_title / set_app_id 3. surface.commit (initial empty) 4. attente Configure event (timeout 5s) 5. ack_configure(serial) 6. shm + buffer + attach + commit POST-ack 7. boucle 25s 8. destroy propre Init submodule wayland-rs/wayland-protocols/protocols (XML files gitlab.freedesktop.org/wayland/wayland-protocols). Validation runtime QEMU complète : [client] globals : compositor=true shm=true xdg_wm_base=true [client] xdg_toplevel configure suggéré : 640x480 [client] initial configure reçu, serial=1 [client] ack_configure(1) [client] buffer attach + damage + commit POST-ack [comp] tick=30..450 surfaces=1 elapsed=1.2..18.2s PNG capturée à T+14s : surface visible à (60,60), bandes RGB+jaune+ violet+orange comme attendu. Critère de fin 7.1 validé : client xdg-shell crée toplevel, reçoit configure, ack, commit, affiche via shm, sans panic serveur, 18s stable, destroy propre. Limitations connues : focus, cursor, move/resize, multi-client, robustesse — sous-tickets 7.2-7.7. Image Redox restaurée à boot Orbital normal. docs/phase7-1-xdg-shell.md : compte-rendu complet, cycle de vie, limitations, plan 7.2. Leyoda 2026 – GPLv3
2026-05-09 14:34:45 +02:00
# Phase 7.1 — xdg-shell minimal
> Document produit le 2026-05-09 dans le cadre du plan directeur
> `REDOX_COSMIC_XWAYLAND_RS_PLAN.md`.
>
> **Scope strict** validé par user :
> - implémenter `xdg_wm_base`
> - gérer `get_xdg_surface(wl_surface)`
> - gérer `xdg_surface.get_toplevel`
> - envoyer `configure` (xdg_toplevel + xdg_surface)
> - recevoir `ack_configure`
> - gérer `commit` après configure
> - supporter `set_title` / `set_app_id` (stockés sans usage UI)
> - destroy propre via `xdg_toplevel.destroy` / `xdg_surface.destroy`
>
> **Hors scope 7.1** : focus, cursor, move/resize, decorations,
> multi-client avancé.
## Verdict
**✅ Cycle xdg-shell complet validé runtime.**
Capture preuve : ![](phase7-1-xdg-toplevel.png) — fenêtre 320×240
positionnée à `(60, 60)` par le compositor (cascade par défaut), avec
bandes verticales arc-en-ciel + bordure noire 2px peintes par le client.
## Cycle de vie xdg-shell implémenté
```
client compositor
────── ──────────
Connection::connect_to_env
get_registry
◄──── wl_compositor + wl_shm + xdg_wm_base
advertised
bind globals
compositor.create_surface ────►
SurfaceData { id: registry.create(),
xdg_pending: false }
wm_base.get_xdg_surface ────►
XdgSurfaceData { wl_surface, serial: 0 }
sd.xdg_pending_initial_configure = true
xdg_surface.get_toplevel ────►
XdgToplevelData::default()
next_toplevel_index += 1
surface.x = +60, surface.y = +60 (cascade)
next_xdg_serial = 1
◄──── xdg_toplevel.configure(640, 480, [])
◄──── xdg_surface.configure(serial=1)
────────────────────────────────────────
toplevel.set_title(...) ────► data.title = Some(...)
toplevel.set_app_id(...) ────► data.app_id = Some(...)
xdg_surface.ack_configure(1)────► data.acked_serial = 1
sd.xdg_pending_initial_configure = false
shm.create_pool(fd, size) ────► ShmPool::new(fd) → mmap
pool.create_buffer(...) ────► BufferData { pool, offset, w, h, ... }
surface.attach(buffer) ────► sd.pending_buffer = Some(buf)
surface.damage_buffer(...) ────► (no-op tracking 7.1)
surface.commit ────►
!xdg_pending → continue
read shm pixels via mmap
SurfaceBuffer::from_pixels(...)
registry.modify_pending(id, |s|
s.buffer = Some(sb); s.visible = true)
registry.commit(id)
registry.raise(id)
(toplevel.destroy) ────► no-op (wl_surface destroy fera le reste)
(xdg_surface.destroy) ────► surface.visible = false; commit
(surface.destroy) ────► registry.destroy(id)
```
## Modifications apportées
### `redox-wl-wayland-frontend`
Ajout dep `wayland-protocols` (feature `server`).
Constants :
- `XDG_WM_BASE_VERSION: u32 = 5`
- `DEFAULT_TOPLEVEL_SIZE: (i32, i32) = (640, 480)`
- `CASCADE_OFFSET: i32 = 60`
Nouveaux UserData :
- `XdgSurfaceData { wl_surface, last_serial, acked_serial }`
- `XdgToplevelData { title, app_id }`
Modif `SurfaceData` :
- ajout `xdg_pending_initial_configure: Mutex<bool>` qui bloque l'affichage
tant que pas ack-configure (sémantique xdg-shell standard)
Modif `WaylandFrontend` :
- `next_xdg_serial: u32` (counter monotone pour les configure serials)
- `next_toplevel_index: u32` (counter cascading)
Dispatch ajoutés :
- `GlobalDispatch<XdgWmBase>` + `Dispatch<XdgWmBase>`
- `Dispatch<XdgPositioner>` (no-op)
- `Dispatch<XdgPopup>` (no-op)
- `Dispatch<XdgSurface, Arc<XdgSurfaceData>>` :
- `GetToplevel` → cascade position + envoie initial configure
- `AckConfigure(serial)` → débloque affichage
- `Destroy` → cache la surface
- `Dispatch<XdgToplevel, Arc<XdgToplevelData>>` :
- `SetTitle`/`SetAppId` → stocke
- reste : ignoré (move, resize, set_*, etc.)
### `redox-wl-test-client-shm`
Ajout dep `wayland-protocols` (feature `client`).
Bind 3 globals : `wl_compositor`, `wl_shm`, `xdg_wm_base`.
Séquence runtime :
1. `compositor.create_surface()`
2. `wm_base.get_xdg_surface(&surface)`
3. `xdg_surface.get_toplevel()`
4. `toplevel.set_title("Phase 7.1 client")`
5. `toplevel.set_app_id("redox.wl.test.client.shm")`
6. `surface.commit()` — initial commit pour signaler "ready"
7. Attente du `xdg_surface.configure(serial)` event (avec timeout 5s)
8. `xdg_surface.ack_configure(serial)`
9. `shm.create_pool(fd)` + `pool.create_buffer` + pattern ARGB
10. `surface.attach(buffer)` + `damage_buffer` + `commit`
11. Boucle 25s vivante
12. `toplevel.destroy()` + `xdg_surface.destroy()` + `surface.destroy()`
Bonus : Dispatch sur `XdgWmBase::Event::Ping` répond `pong(serial)` (le
compositor ne l'envoie pas en 7.1 mais c'est gratuit côté client).
## Preuve runtime
Logs serial QEMU complets :
```
[client] connect to compositor
[comp] CRTC pris
[comp] Wayland socket : /tmp/redox-wl-comp.sock
[client] globals : compositor=true shm=true xdg_wm_base=true
[client] xdg_toplevel créé, attente initial configure
[client] xdg_toplevel configure suggéré : 640x480
[client] initial configure reçu, serial=1
[client] ack_configure(1)
[client] buffer attach + damage + commit POST-ack
[comp] tick=30 surfaces=1 elapsed=1.2s
... (compositeur stable 18s avec 1 surface) ...
[comp] tick=450 surfaces=1 elapsed=18.2s
```
Capture frame T+14s : fenêtre client à `(60, 60)`, bandes RGB+orange+jaune+
violet visibles avec bordure noire.
## Limitations connues (à traiter en sous-tickets ultérieurs)
- **Pas de focus** → toutes les surfaces sont "actives", pas de keyboard
enter/leave events. Phase 7.4.
- **Pas de cursor visible** côté écran. Phase 7.3.
- **Pas de move/resize interactifs** (xdg_toplevel.Move/Resize ignorés).
Phase 7.7.
- **Window geometry ignoré** (utilisé pour les decorations CSD que nous
ne supportons pas).
- **Multi-client non testé** (1 seul client en 7.1). Phase 7.6.
- **Pas de validation des serials** : si un client envoie un mauvais
ack_configure, on accepte sans broncher. À durcir en phase 7.5
(robustesse).
## Critère de fin 7.1
> Un client Wayland externe qui utilise xdg-shell peut créer une fenêtre
> toplevel visible, recevoir son configure, ack, commit, puis afficher
> via shm sans panic serveur.
**✅ Validé.** Test runtime 18+ secondes, surface visible, aucun panic
serveur ni client, destroy propre à la fin.
## Code
```
crates/redox-wl-wayland-frontend/ # +220 lignes pour xdg-shell (5 Dispatch + helpers)
└── Cargo.toml # + wayland-protocols/server
crates/redox-wl-test-client-shm/ # adapté entièrement à xdg-shell
└── Cargo.toml # + wayland-protocols/client
```
Submodule `wayland-rs/wayland-protocols/protocols/` initialisé via
`git submodule update --init --depth 1`.
## Suite phase 7.2
`wl_seat` + `wl_pointer` + `wl_keyboard` :
- Routage des events `InputBackend` vers la surface focalisée
- Décision XKB (recommandation : `xkeysym` Rust pur, layout US uniquement
au début ; xkbcommon C reportable)
- Premier client qui réagit aux events keyboard
- Tester via QEMU `sendkey` avec un client qui log les events reçus
Estimé 2 sessions.
---
*Fin du document de phase 7.1.*