gioser

tawasuyu/brahman

Rust 582TOML 222Markdown 83JSON 198635 Definiciones

fix(mirada-compositor): anunciar un wl_output — los clientes lo exigen

foot (y casi todo cliente Wayland) aborta con «no monitors available»
si el compositor no anuncia ningún wl_output. carmen no lo hacía.

- OutputHandler para App + delegate_output!.
- announce_output(): crea un Output, lo publica como global wl_output y
  le fija el modo. Helper compartido por los dos backends.
- winit y DRM lo llaman con su tamaño/modo real.

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

8cd34bf17311d89f73e89de51c8a61ce203ca453 · por sergio · (hace 5 meses) · padre fb2f3a2d0 · ver el árbol en este commit

Delta semántico · 3

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

  • cambió por dentro fn run pub

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

2 archivos · +53 −4

diff --git a/crates/apps/mirada-compositor/src/drm_backend.rs b/crates/apps/mirada-compositor/src/drm_backend.rs
index 18eda47..8946c52 100644
--- a/crates/apps/mirada-compositor/src/drm_backend.rs
+++ b/crates/apps/mirada-compositor/src/drm_backend.rs
@@ -327,6 +327,14 @@ pub fn run() -> Result<(), Box<dyn Error>> {
     // La salida del Cerebro = el modo del monitor.
     let ev = app.body.add_output(0, mode_w as i32, mode_h as i32);
     app.brain_feed(ev);
+    // Anuncia el monitor en el protocolo Wayland — los clientes lo exigen.
+    let _wl_output = crate::announce_output(
+        &display.handle(),
+        &out_name,
+        mode_w as i32,
+        mode_h as i32,
+        mode.vrefresh() as i32 * 1000,
+    );
 
     // El socket Wayland por el que se conectan los clientes.
     let listener = ListeningSocket::bind_auto("wayland", 1..32)?;
diff --git a/crates/apps/mirada-compositor/src/main.rs b/crates/apps/mirada-compositor/src/main.rs
index 7e64689..9340ea3 100644
--- a/crates/apps/mirada-compositor/src/main.rs
+++ b/crates/apps/mirada-compositor/src/main.rs
@@ -37,7 +37,7 @@ use smithay::reexports::wayland_server::protocol::wl_buffer;
 use smithay::reexports::wayland_server::protocol::wl_output;
 use smithay::reexports::wayland_server::protocol::wl_seat;
 use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;
-use smithay::reexports::wayland_server::{Client, Display, ListeningSocket};
+use smithay::reexports::wayland_server::{Client, Display, DisplayHandle, ListeningSocket};
 use smithay::reexports::winit::platform::pump_events::PumpStatus;
 use smithay::utils::{Rectangle, SERIAL_COUNTER};
 use smithay::utils::{Serial, Transform};
@@ -54,9 +54,11 @@ use smithay::wayland::shell::xdg::{
     PopupSurface, PositionerState, ToplevelSurface, XdgShellHandler, XdgShellState,
     XdgToplevelSurfaceData,
 };
+use smithay::wayland::output::OutputHandler;
 use smithay::wayland::shm::{ShmHandler, ShmState};
 use smithay::{
-    delegate_compositor, delegate_data_device, delegate_seat, delegate_shm, delegate_xdg_shell,
+    delegate_compositor, delegate_data_device, delegate_output, delegate_seat, delegate_shm,
+    delegate_xdg_shell,
 };
 
 use mirada_body::{BodyOp, BodyState};
@@ -411,11 +413,16 @@ impl SeatHandler for App {
     }
 }
 
+/// El protocolo `wl_output` no necesita estado propio — basta con
+/// anunciar el global para que los clientes vean que hay un monitor.
+impl OutputHandler for App {}
+
 delegate_compositor!(App);
 delegate_xdg_shell!(App);
 delegate_shm!(App);
 delegate_seat!(App);
 delegate_data_device!(App);
+delegate_output!(App);
 
 // ---------------------------------------------------------------------
 // Datos por cliente
@@ -513,6 +520,39 @@ fn load_user_rules() -> Rules {
     }
 }
 
+/// Crea y anuncia un `wl_output` (un monitor) en el protocolo Wayland —
+/// muchos clientes (`foot` entre ellos) se niegan a arrancar sin uno.
+/// Devuelve el [`Output`](smithay::output::Output); hay que mantenerlo
+/// vivo mientras el compositor corra.
+fn announce_output(
+    dh: &DisplayHandle,
+    name: &str,
+    width: i32,
+    height: i32,
+    refresh_mhz: i32,
+) -> smithay::output::Output {
+    use smithay::output::{Mode, Output, PhysicalProperties, Scale, Subpixel};
+    let output = Output::new(
+        name.to_string(),
+        PhysicalProperties {
+            size: (0, 0).into(),
+            subpixel: Subpixel::Unknown,
+            make: "mirada".into(),
+            model: name.to_string(),
+        },
+    );
+    output.create_global::<App>(dh);
+    let mode = Mode { size: (width, height).into(), refresh: refresh_mhz };
+    output.change_current_state(
+        Some(mode),
+        Some(Transform::Normal),
+        Some(Scale::Integer(1)),
+        Some((0, 0).into()),
+    );
+    output.set_preferred(mode);
+    output
+}
+
 /// Lo que comparten los dos backends gráficos: el `Display` de Wayland,
 /// el `App` ya armado y la maquinaria de keymap y control.
 struct Setup {
@@ -668,9 +708,10 @@ fn run_winit() -> Result<(), Box<dyn std::error::Error>> {
     let mut clients = Vec::new();
 
     // Salida inicial = el tamaño de la ventana winit.
+    let win_size = backend.window_size();
+    let _wl_output = announce_output(&display.handle(), "winit", win_size.w, win_size.h, 60_000);
     {
-        let size = backend.window_size();
-        let ev = state.body.add_output(0, size.w, size.h);
+        let ev = state.body.add_output(0, win_size.w, win_size.h);
         state.brain_feed(ev);
     }