🎉 Phase 7.4 — focus + raise on click validés runtime
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
This commit is contained in:
parent
5f7587e79e
commit
c40ca9fcc8
7 changed files with 653 additions and 1 deletions
|
|
@ -215,6 +215,10 @@ pub struct WaylandFrontend {
|
|||
/// dernier `wl_pointer.set_cursor`. `None` = pas de curseur custom,
|
||||
/// on dessine le sprite par défaut (flèche 16x16).
|
||||
cursor_surface_id: Option<SurfaceId>,
|
||||
/// Phase 7.4 : mapping inverse SurfaceId → wl_surface, pour pouvoir
|
||||
/// faire set_focus(target) après un hit_test au clic. Peuplé au
|
||||
/// `wl_compositor.create_surface`, nettoyé au `wl_surface.destroy`.
|
||||
surfaces_by_id: HashMap<SurfaceId, wl_surface::WlSurface>,
|
||||
/// Hot-spot du curseur (offset à soustraire à cursor_x/y pour le placement).
|
||||
cursor_hot_x: i32,
|
||||
cursor_hot_y: i32,
|
||||
|
|
@ -259,6 +263,7 @@ impl WaylandFrontend {
|
|||
cursor_hot_x: 0,
|
||||
cursor_hot_y: 0,
|
||||
cursor_visible: false,
|
||||
surfaces_by_id: HashMap::new(),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -339,6 +344,18 @@ impl WaylandFrontend {
|
|||
if same {
|
||||
return;
|
||||
}
|
||||
let old_sid = self
|
||||
.focused_surface
|
||||
.as_ref()
|
||||
.and_then(|s| s.data::<Arc<SurfaceData>>())
|
||||
.and_then(|d| *d.id.lock().unwrap());
|
||||
let new_sid = new_focus
|
||||
.as_ref()
|
||||
.and_then(|s| s.data::<Arc<SurfaceData>>())
|
||||
.and_then(|d| *d.id.lock().unwrap());
|
||||
println!(
|
||||
"[frontend] focus change: {old_sid:?} → {new_sid:?}"
|
||||
);
|
||||
let serial_leave = self.alloc_input_serial();
|
||||
let serial_enter = self.alloc_input_serial();
|
||||
|
||||
|
|
@ -448,6 +465,32 @@ impl WaylandFrontend {
|
|||
middle,
|
||||
right,
|
||||
} => {
|
||||
// Phase 7.4 : sur clic gauche (left pressed), hit_test à la
|
||||
// position curseur et raise + set_focus à la surface ciblée.
|
||||
// À faire AVANT l'envoi des events button pour que la nouvelle
|
||||
// surface reçoive enter+modifiers en premier, puis le button.
|
||||
if *left {
|
||||
let hit = self.registry.hit_test(self.cursor_x, self.cursor_y);
|
||||
println!(
|
||||
"[frontend] left-click @ ({}, {}) → hit_test = {:?}",
|
||||
self.cursor_x, self.cursor_y, hit
|
||||
);
|
||||
if let Some(sid) = hit {
|
||||
// Ne pas réagir aux surfaces curseur (elles ne devraient pas
|
||||
// apparaître dans hit_test car visible=false, mais double-belt).
|
||||
if let Some(surf) = self.surfaces_by_id.get(&sid).cloned() {
|
||||
if !surf
|
||||
.data::<Arc<SurfaceData>>()
|
||||
.map(|d| d.is_cursor.load(Ordering::Relaxed))
|
||||
.unwrap_or(false)
|
||||
{
|
||||
self.registry.raise(sid);
|
||||
self.set_focus(Some(surf));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let time = self.alloc_input_time();
|
||||
// Code BTN_LEFT/MIDDLE/RIGHT linux/input-event-codes.h
|
||||
const BTN_LEFT: u32 = 0x110;
|
||||
|
|
@ -723,7 +766,10 @@ impl wayland_server::Dispatch<wl_compositor::WlCompositor, ()> for WaylandFronte
|
|||
xdg_pending_initial_configure: Mutex::new(false),
|
||||
is_cursor: AtomicBool::new(false),
|
||||
};
|
||||
data_init.init(id, Arc::new(data));
|
||||
let surf = data_init.init(id, Arc::new(data));
|
||||
// Phase 7.4 : enregistrer le mapping SurfaceId → WlSurface
|
||||
// pour permettre raise_at_cursor / set_focus depuis un hit_test.
|
||||
state.surfaces_by_id.insert(surface_id, surf);
|
||||
}
|
||||
wl_compositor::Request::CreateRegion { id } => {
|
||||
// Région no-op : on alloue la resource pour que le client
|
||||
|
|
@ -946,6 +992,18 @@ impl wayland_server::Dispatch<wl_surface::WlSurface, Arc<SurfaceData>> for Wayla
|
|||
let mut id_lock = data.id.lock().unwrap();
|
||||
if let Some(id) = id_lock.take() {
|
||||
state.registry.destroy(id);
|
||||
// Phase 7.4 : retirer du mapping inverse + clear focus
|
||||
// si c'était la surface focalisée (sinon des events seraient
|
||||
// envoyés à un wl_surface fantôme).
|
||||
if let Some(removed) = state.surfaces_by_id.remove(&id) {
|
||||
if state.focused_surface.as_ref() == Some(&removed) {
|
||||
state.focused_surface = None;
|
||||
}
|
||||
}
|
||||
// Si c'était le curseur custom, retomber sur le sprite par défaut.
|
||||
if state.cursor_surface_id == Some(id) {
|
||||
state.cursor_surface_id = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue