Sur clic gauche, le compositor fait hit_test Ă la position curseur, raise la surface ciblĂ©e au top du Z-order et transfĂšre le keyboard focus Ă cette surface (broadcast wl_keyboard.leave/enter via le set_focus dĂ©jĂ implĂ©mentĂ© en 7.2). Frontend additions : - HashMap<SurfaceId, wl_surface::WlSurface> dans WaylandFrontend, peuplĂ©e au wl_compositor.create_surface (capture du retour de data_init.init), nettoyĂ©e au wl_surface.destroy - Au wl_surface.destroy : clear focused_surface et cursor_surface_id si la surface dĂ©truite Ă©tait l'une de ces rĂ©fĂ©rences (Ă©vite les wl_surface fantĂŽmes dans les events suivants) - forward_input(PointerButton.left=true) dĂ©clenche registry.hit_test(cursor_x, cursor_y), puis si la cible n'est pas une surface curseur : registry.raise + set_focus(target) - println! tracing pour [frontend] left-click et focus change Nouveau crate : redox-wl-test-client-shm-two - Binaire qui fork() : parent = fenĂȘtre A (verte, pyramide), enfant = fenĂȘtre B (magenta, double cercle) aprĂšs sleep 800ms - 2 connexions Wayland indĂ©pendantes au mĂȘme socket compositor - timeout 160s alignĂ© sur le compositor 180s Validation runtime : 4 captures synchronisĂ©es via cycle de positionnement curseur temporaire (retirĂ© aprĂšs) prouvent les 2 transitions de Z-order : - initial : B au top (commit le plus rĂ©cent) - click@(80,80) â hit A â A passe au top - click@(400,280) â hit B â B repasse au top Traces /tmp/comp.log (extraites via redoxfs) confirment : [frontend] left-click @ (80, 80) â hit_test = Some(SurfaceId(0)) [frontend] focus change: Some(SurfaceId(1)) â Some(SurfaceId(0)) [frontend] left-click @ (400, 280) â hit_test = Some(SurfaceId(1)) [frontend] focus change: Some(SurfaceId(0)) â Some(SurfaceId(1)) Pipeline validĂ© end-to-end : mouse_button QEMU â ps2d â inputd â InputBackend::poll â RedoxInputEvent::PointerButton â forward_input â hit_test â raise + set_focus â wl_keyboard.leave/enter broadcast. Doc complĂšte : docs/phase7-4-focus-raise.md. Leyoda 2026 â GPLv3
8.2 KiB
Phase 7.4 â Focus + raise on click
Document produit le 2026-05-13 dans le cadre du plan directeur
REDOX_COSMIC_XWAYLAND_RS_PLAN.md.Scope strict :
- sur clic gauche, faire
registry.hit_test(cursor_x, cursor_y)- si la surface ciblée est non-cursor :
registry.raise(sid)+set_focus(matching wl_surface)(transfert du keyboard focus)- ajouter un mapping inverse
SurfaceId â wl_surface::WlSurfacepour pouvoir retrouver la WlSurface depuis le hit_test- tester avec 2 fenĂȘtres xdg_toplevel SHM en parallĂšle (fork)
Hors scope 7.4 : focus-follows-mouse, click-through, move/resize interactifs (7.7), filtrage par client des events pointer (7.6), validation des serials ack_configure (7.5).
Verdict
â Click-to-raise + focus transfer validĂ©s runtime, 2 clients SHM parallĂšles, 4 captures de preuve.
| Capture | Ătat |
|---|---|
phase7-4-1-initial-B-top.png |
B violet créée en dernier â au top du Z-order, A vert visible sous B. Curseur sur A (80, 80). |
phase7-4-2-after-click-A-raised.png |
AprÚs clic à (80, 80) sur A : A passe au top, B passe en-dessous. Curseur a migré sur B (cycle programmé). |
phase7-4-3-after-click-B-raised.png |
AprĂšs clic Ă (400, 280) sur B : B repasse au top, A passe en-dessous. |
Trace /tmp/comp.log cÎté Redox (extraite via redoxfs aprÚs le run) :
[comp] phase 0: cursor â A (80, 80)
[frontend] focus change: None â Some(SurfaceId(0)) # A créée
[frontend] focus change: Some(SurfaceId(0)) â Some(SurfaceId(1)) # B créée (commit auto-focus)
[comp] 1 input events from inputd # mouse_button 1 = press
[frontend] left-click @ (80, 80) â hit_test = Some(SurfaceId(0)) # A trouvĂ©e
[frontend] focus change: Some(SurfaceId(1)) â Some(SurfaceId(0)) # focus â A
[comp] 1 input events from inputd # mouse_button 0 = release
[comp] phase 1: cursor â B (400, 280)
[comp] 1 input events from inputd # 2e clic press
[frontend] left-click @ (400, 280) â hit_test = Some(SurfaceId(1)) # B trouvĂ©e
[frontend] focus change: Some(SurfaceId(0)) â Some(SurfaceId(1)) # focus â B
[comp] 1 input events from inputd # release
Le pipeline complet est validé end-to-end :
mouse_button QEMU â ps2d â inputd â InputBackend::poll â RedoxInputEvent::PointerButton â WaylandFrontend::forward_input â SurfaceRegistry::hit_test â registry.raise + set_focus â wl_keyboard.leave/enter broadcast.
Modifications apportées
redox-wl-wayland-frontend
WaylandFrontend : nouveau champ
surfaces_by_id: HashMap<SurfaceId, wl_surface::WlSurface>,
peuplé dans le handler wl_compositor::Request::CreateSurface (en
récupérant le retour de data_init.init(id, ...)), nettoyé dans
wl_surface::Request::Destroy avec en plus le clear de
focused_surface et cursor_surface_id si la surface détruite était
ces références (évite les wl_surface fantÎmes dans les events suivants).
forward_input(PointerButton { left, .. }) : avant l'envoi des
events button aux pointers, si left == true :
self.registry.hit_test(cursor_x, cursor_y) -> Option<SurfaceId>- Si
Some(sid)et la surface n'est pas un curseur (is_cursor.load() == false), récupérer lawl_surfacedanssurfaces_by_id, faireregistry.raise(sid)puisset_focus(Some(surf)).
Le set_focus envoie déjà les wl_keyboard.leave / wl_keyboard.enter
et wl_pointer.leave / wl_pointer.enter sur les bons wl_surface, et
ses modifiers reset (cf phase 7.2). Pas de duplication de code.
Instrumentation : println! du frontend Ă chaque clic
([frontend] left-click @ (...) â hit_test = ...) et Ă chaque
changement de focus ([frontend] focus change: old_sid â new_sid).
Sort sur stdout du processus compositor ; le service init redirige
vers /tmp/comp.log cÎté Redox pour analyse post-run.
redox-wl-test-client-shm-two (nouveau crate)
Binaire qui fork() une fois. Parent et enfant exécutent chacun la
mĂȘme sĂ©quence de connexion Wayland + xdg-shell, mais avec :
- des couleurs ARGB différentes (vert pastel pour A, magenta pour B)
- un grand pictogramme central distinctif (pyramide tronquĂ©e "A" / deux disques empilĂ©s "B") pour identifier la fenĂȘtre dans les screendumps
- un sleep 800 ms cĂŽtĂ© enfant pour garantir l'ordre A créée â B créée
- timeout 160 s aligné sur le compositor
Le compositor place automatiquement A Ă (60, 60) et B Ă (120, 120)
grĂące Ă son cascade offset 7.1, ce qui produit l'overlap voulu pour
tester le raise.
Au dĂ©but (avant tout clic) : B est au top car commit le plus rĂ©cent â politique 6.4 "derniĂšre surface commitĂ©e = au-dessus" (Ă raffiner en phase 7.6/7.7).
Méthode de validation runtime
Limitation runtime héritée 7.3 : Redox n'a pas de driver mouse
fonctionnel sous QEMU + virtio-vga (PS/2 mouse_button OK, PS/2 et USB
tablet mouse_move muets). Pour positionner le curseur dans une zone
précise avant le clic, le compositor a embarqué temporairement un
cycle de 4 phases qui appelaient frontend.set_cursor_position(x, y)
toutes les 15 s entre (80, 80) (uniquement sur A) et (400, 280)
(uniquement sur B).
Pendant chaque phase, le script de test envoie via QMP :
mouse_button 1 # press
mouse_button 0 # release
screendump /tmp/screen-N.ppm
Le clic, lui, passe par le pipeline réel et déclenche le code
production forward_input â hit_test â raise + set_focus. Le cycle
de positionnement est retiré du binaire aprÚs validation (comme en
7.3) ; seul le cùblage production est commité.
Le service init Redox utilisé (purement temporaire) :
# /usr/lib/init.d/40_phase74_focus
requires_weak 30_console
nowait /usr/bin/launch_phase74.sh
# /usr/bin/launch_phase74.sh
#!/bin/sh
sleep 2
/usr/bin/redox-wl-compositor > /tmp/comp.log 2>&1 &
sleep 4
/usr/bin/redox-wl-test-client-shm-two > /tmp/client.log 2>&1
Ă noter : l'init Redox ne sait pas parser correctement
nowait sh -c "..." avec guillemets dans la dĂ©finition de service â
il faut passer par un script wrapper sur disque pour fork + redirection.
Limitations connues (à traiter en sous-tickets ultérieurs)
- Events pointer/keyboard broadcast : le clic raise + focus est
correct, mais les events button/key sont encore broadcast Ă tous
les
wl_pointer/wl_keyboard(pas filtrage par client focused). Reportable à 7.6 (multi-clients). - Focus follows mouse non implémenté : on doit cliquer pour changer le focus (modÚle click-to-focus). Optionnel selon politique WM, pas dans le scope.
- Pas de transition press/release tracked : Ă chaque event
PointerButton { left: true, .. }, on rejoue le hit_test. En pratique inputd n'envoie qu'1 event par transition donc OK, mais Ă durcir en 7.5 si on observe des re-raises spurieux. - Surface dĂ©truite tout en Ă©tant focused : gĂ©rĂ© (focused_surface cleared, cursor_surface_id cleared), mais pas de re-focus auto sur la prochaine surface du Z-order. Le client suivant qui commit reprendra le focus via la politique 6.4 â acceptable pour 7.4.
- Pas encore de fenĂȘtre "popup" : focus-stealing par xdg_popup reportable.
CritĂšre de fin 7.4
Un clic gauche dans la fenĂȘtre cliquĂ©e la fait passer au top du Z-order et lui transfĂšre le keyboard focus, sans dĂ©stabiliser le compositor, multi-clients OK.
â ValidĂ©. 2 clients SHM en parallĂšle, 2 transitions Z-order distinctes, traces frontend explicites confirmant le hit_test et les changements de focus.
Code
crates/redox-wl-wayland-frontend/ # +~30 lignes (HashMap mapping, hit_test branch, logs)
crates/redox-wl-test-client-shm-two/ # nouveau crate (~330 lignes)
Suite phase 7.5
Robustesse paquet A : tests négatifs sur les protocoles. Clients qui :
- ferment sans destroy propre
- envoient ack_configure avec un mauvais serial
- détruisent un buffer encore attaché
- attachent un buffer avec width/height/stride invalides
- détruisent un xdg_surface avant son toplevel
- envoient des messages au mauvais moment du cycle de vie
But : le compositor doit dans tous les cas soit ignorer proprement,
soit fermer la connexion du client fautif avec un post_error, mais
JAMAIS paniquer.
Estimé : 1-2 sessions.
Fin du document de phase 7.4.