From a87de02555b8e7150f6ea20d554d3b121c85f462 Mon Sep 17 00:00:00 2001 From: Votre Nom Date: Wed, 13 May 2026 18:51:33 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=89=20Phase=207.6=20=E2=80=94=20multi-?= =?UTF-8?q?clients=20paquet=20B=20valid=C3=A9=20runtime?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 3 livrables : 1. Cleanup post-disconnect (corrige sub-bug 7.5) - DumbClientData::disconnected push dans Arc>> partagé (peuplé à accept_pending_clients) - SurfaceData.client_id: Mutex> 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 à Option pour avoir le Resource sous la main - Au commit, après la lecture des params via buf.data::().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 --- crates/redox-wl-compositor/src/main.rs | 5 + crates/redox-wl-wayland-frontend/src/lib.rs | 234 +++++++++++++---- docs/phase7-6-cleanup-no-ghost.png | Bin 0 -> 658 bytes docs/phase7-6-multi-clients.md | 273 ++++++++++++++++++++ docs/phase7-6-two-clients.png | Bin 0 -> 1589 bytes 5 files changed, 464 insertions(+), 48 deletions(-) create mode 100644 docs/phase7-6-cleanup-no-ghost.png create mode 100644 docs/phase7-6-multi-clients.md create mode 100644 docs/phase7-6-two-clients.png diff --git a/crates/redox-wl-compositor/src/main.rs b/crates/redox-wl-compositor/src/main.rs index af0c692..126ee26 100644 --- a/crates/redox-wl-compositor/src/main.rs +++ b/crates/redox-wl-compositor/src/main.rs @@ -116,6 +116,11 @@ fn run() -> Result<(), Box> { dlog(&format!("[comp] dispatch err: {e}")); } + // 2.5. Phase 7.6 : nettoyer les surfaces des clients déconnectés. + // Sans ça les surfaces persistent après un close socket brutal + // (sub-bug 7.5). + frontend.garbage_collect_dead_clients(); + // 3. Input if let Ok(events) = input.poll() { if !events.is_empty() { diff --git a/crates/redox-wl-wayland-frontend/src/lib.rs b/crates/redox-wl-wayland-frontend/src/lib.rs index 4e63f05..68dae81 100644 --- a/crates/redox-wl-wayland-frontend/src/lib.rs +++ b/crates/redox-wl-wayland-frontend/src/lib.rs @@ -150,8 +150,11 @@ struct SurfaceData { /// SurfaceId associé dans le SurfaceRegistry. /// Initialisé par `wl_compositor.create_surface` via Mutex