gioser

tawasuyu/brahman

Rust 459TOML 177Markdown 49JSON 176207 Sutichaykuna

fix(mirada-compositor): no pisar WAYLAND_DISPLAY antes de winit::init

winit lee WAYLAND_DISPLAY/DISPLAY para encontrar la sesión gráfica
anfitriona donde anidarse. El código publicaba antes su propio socket
en WAYLAND_DISPLAY, así que winit intentaba anidarse en el propio
compositor —un socket que aún no atiende a nadie— y se colgaba.

Ahora winit::init() va primero (conecta a la sesión real) y el socket
propio + set_var se publican después. Si no hay sesión gráfica, aborta
con un mensaje claro en vez de colgarse o fallar en seco.

README: sección Requisitos — hace falta sesión X11/Wayland anfitriona;
receta Xvfb + VNC para cajas headless.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

51398f89cf364d786aaa9ddb20f69e6798844b35 · ruwaq sergio · (5 killa ñawpaq) · tayta c69eec794 · kay commitpi sach'ata qhaway

Semántico sayk'uy · 1

crates/apps/mirada-compositor/src/main.rs

  • ukhunpi t'ikrakurqan fn run

2 qillqakuna · +49 −1

diff --git a/crates/apps/mirada-compositor/README.md b/crates/apps/mirada-compositor/README.md
index c49d6ef..c48d195 100644
--- a/crates/apps/mirada-compositor/README.md
+++ b/crates/apps/mirada-compositor/README.md
@@ -10,6 +10,27 @@ Backend `winit`: corre **anidado** — una ventana dentro de tu sesión
 gráfica actual, X11 o Wayland. No toca DRM/KMS, así que es seguro de
 arrancar sin dejar la sesión.
 
+## Requisitos
+
+Hace falta una **sesión gráfica anfitriona** (X11 o Wayland) donde
+dibujar la ventana del compositor — es donde `winit` se anida. En un
+servidor *headless* (SSH a una caja sin escritorio, `XDG_SESSION_TYPE=tty`,
+sin `/dev/dri`) no hay dónde mostrar nada y el arranque aborta con un
+mensaje que lo explica.
+
+Para verlo en una caja headless: levanta un servidor X virtual y
+conéctate por VNC.
+
+```sh
+Xvfb :99 -screen 0 1280x800x24 &
+x11vnc -display :99 -localhost -nopw &        # luego túnel SSH al :5900
+DISPLAY=:99 cargo run -p mirada-compositor
+```
+
+El backend nativo DRM/KMS —que pintaría directo en la pantalla sin
+sesión anfitriona— está pendiente (ver el SDD), y de todos modos
+necesitaría un `/dev/dri`.
+
 ## Dos modos
 
 - **Autónomo** (por defecto) — lleva un `Desktop` (de `mirada-brain`)
diff --git a/crates/apps/mirada-compositor/src/main.rs b/crates/apps/mirada-compositor/src/main.rs
index 67094cd..754d02e 100644
--- a/crates/apps/mirada-compositor/src/main.rs
+++ b/crates/apps/mirada-compositor/src/main.rs
@@ -475,6 +475,34 @@ fn run() -> Result<(), Box<dyn std::error::Error>> {
         state.apply_commands(vec![grab]);
     }
 
+    // El backend gráfico va primero. winit abre la ventana del compositor
+    // dentro de tu sesión gráfica anfitriona, y para encontrarla lee
+    // `WAYLAND_DISPLAY` / `DISPLAY` del entorno. Si publicáramos antes
+    // nuestro propio socket en `WAYLAND_DISPLAY`, winit intentaría
+    // anidarse en nosotros mismos —un socket que aún no atiende a nadie—
+    // y se quedaría colgado para siempre.
+    let (mut backend, mut winit) = match winit::init::<GlesRenderer>() {
+        Ok(pair) => pair,
+        Err(e) => {
+            eprintln!("mirada-compositor · no pude abrir la ventana: {e}");
+            eprintln!(
+                "   El backend `winit` necesita una sesión gráfica anfitriona\n   \
+                 (X11 o Wayland) donde dibujar la ventana del compositor.\n   \
+                 Aquí no hay ninguna: DISPLAY='{}', WAYLAND_DISPLAY='{}',\n   \
+                 XDG_SESSION_TYPE='{}'.\n   \
+                 Lánzalo desde un escritorio gráfico, o desde un servidor X\n   \
+                 virtual (Xvfb) al que te conectes por VNC.",
+                std::env::var("DISPLAY").unwrap_or_default(),
+                std::env::var("WAYLAND_DISPLAY").unwrap_or_default(),
+                std::env::var("XDG_SESSION_TYPE").unwrap_or_else(|_| "tty".into()),
+            );
+            return Err(e.into());
+        }
+    };
+
+    // Ahora sí, nuestro propio socket Wayland — y `WAYLAND_DISPLAY` se
+    // publica *después* de winit, sólo para los clientes que lancemos
+    // como procesos hijos.
     let listener = ListeningSocket::bind_auto("wayland", 1..32)?;
     let socket_name = listener
         .socket_name()
@@ -485,7 +513,6 @@ fn run() -> Result<(), Box<dyn std::error::Error>> {
     println!("mirada-compositor · escuchando en WAYLAND_DISPLAY={socket_name}");
     println!("   lanza un cliente:  WAYLAND_DISPLAY={socket_name} foot");
 
-    let (mut backend, mut winit) = winit::init::<GlesRenderer>()?;
     let start = Instant::now();
     let mut clients = Vec::new();