3 livrables :
1. Cleanup post-disconnect (corrige sub-bug 7.5)
- DumbClientData::disconnected push dans Arc<Mutex<Vec<ClientId>>>
partagé (peuplé à accept_pending_clients)
- SurfaceData.client_id: Mutex<Option<ClientId>> capturé au
wl_compositor.create_surface pendant que _client: &Client est
encore vivant (à la déconnexion surf.client() retourne None,
on ne pourrait plus déduire le mapping)
- WaylandFrontend.garbage_collect_dead_clients drain la queue
et nettoie surfaces_by_id + registry + focused_surface +
cursor_surface_id + pointers/keyboards orphelins
- Appelée à chaque tick depuis le compositor binaire après
dispatch_clients
2. wl_buffer.release après commit-copy
- SurfaceData.pending_buffer passé de Option<BufferData> à
Option<wl_buffer::WlBuffer> pour avoir le Resource sous la main
- Au commit, après la lecture des params via
buf.data::<BufferData>().cloned() et la copie des pixels,
appel buf.release() qui signale au client qu'il peut réutiliser
son buffer
3. Filtrage events par client focused
- forward_input calcule focused_client_id depuis
focused_surface.client().map(|c| c.id())
- wl_pointer.{motion,button,axis,frame} et wl_keyboard.key
n'arrivent qu'aux Resources dont client_id matche le focused
- PointerButton recalcule focused_cid APRÈS le hit_test+set_focus
pour que le clic atterrisse bien sur le nouveau client
Pièges trouvés :
- Resource n'a pas de client_id() direct → utiliser
client().map(|c| c.id())
- À l'instant du disconnected(), surf.client() retourne déjà None
→ capturer le ClientId au CreateSurface, pas après
Validation runtime :
- Test fuzz : surface fantôme du fuzz1 (brutal exit) nettoyée,
surfaces=0 stable post-fuzz, capture phase7-6-cleanup-no-ghost.png
confirme visuellement (vs rectangle noir 7.5)
- Test 2 clients : redox-wl-test-client-shm-two avec parent + fork
affiche A vert + B magenta en parallèle, surfaces=2 stable,
capture phase7-6-two-clients.png
- Log frontend : [frontend] garbage_collect: client X → destroyed
1 surfaces (fuzz1), 0 surfaces (fuzz2-4 qui ont cleanup propre)
Doc complète : docs/phase7-6-multi-clients.md
Leyoda 2026 – GPLv3