🎉 Phase 13.1.b — simple_window upstream validé runtime sur Redox

4 bugs identifiés et corrigés grâce au client tiers :
- ESC mangée par le compositor au lieu d'être forwardée (raccourci compo
  déplacé sur Ctrl+Q + tracking ctrl_held)
- Cursor accumulait les deltas PS/2 hors-écran (ajout screen_w/h +
  clamp_cursor + set_screen_size au boot)
- Keycode envoyé scancode+8 au lieu d'evdev brut (bug racine — le +8
  est entre evdev et X11, pas entre PS/2 et evdev)
- Event loop client ne tolérait pas Interrupted/BrokenPipe transitoires
  → FAIL au lieu de PASS sur sortie normale (5e adaptation Redox côté
  client, upstream-compatible)

Plus : tick log compo passé en debug! pour silencer la console série,
run-qemu.sh durci (check /dev/fuse, IMAGE/REDOXFS overridables).

6/6 checkpoints 13.1 verts. Bugs secondaires (curseur stuck en bas-droite,
ion page fault sur broken pipe d'un job background) listés dans le doc
pour follow-up en 13.1.c.

Leyoda 2026 – GPLv3
This commit is contained in:
Votre Nom 2026-05-16 10:59:35 +02:00
parent 0d8032b5ff
commit 18391c85f7
5 changed files with 401 additions and 15 deletions

View file

@ -70,6 +70,23 @@ fn dlog(s: &str) {
SINK.get_or_init(DebugSink::new).writeln(s);
}
fn is_interrupted_error(err: &(dyn std::error::Error + 'static)) -> bool {
if let Some(ioe) = err.downcast_ref::<std::io::Error>() {
return ioe.kind() == std::io::ErrorKind::Interrupted;
}
err.source().is_some_and(is_interrupted_error)
}
fn is_connection_closed_error(err: &(dyn std::error::Error + 'static)) -> bool {
if let Some(ioe) = err.downcast_ref::<std::io::Error>() {
return matches!(
ioe.kind(),
std::io::ErrorKind::BrokenPipe | std::io::ErrorKind::ConnectionReset
);
}
err.source().is_some_and(is_connection_closed_error)
}
// ---------- Buffer SHM (équivalent de tempfile + draw upstream) ----------
const INIT_W: u32 = 320;
const INIT_H: u32 = 240;
@ -350,7 +367,15 @@ fn run() -> Result<(), Box<dyn std::error::Error>> {
dlog("[real-client] entering event loop");
while state.running {
event_queue.blocking_dispatch(&mut state)?;
match event_queue.blocking_dispatch(&mut state) {
Ok(_) => {}
Err(e) if is_interrupted_error(&e) => continue,
Err(e) if is_connection_closed_error(&e) => {
dlog("[real-client] compositor disconnected → exit cleanly");
break;
}
Err(e) => return Err(e.into()),
}
}
dlog("[real-client] loop exited cleanly");
Ok(())