feat(renaser): Fase 8a — el compositor teselante
El kernel deja de colocar las ventanas a mano: las tesela. El motor es mirada-layout — el mismo nucleo no_std que ordena el compositor Wayland de brahman, enlazado por path cruzando la frontera de workspace. Es el primer consumo REAL del nucleo compartido brahman <-> renaser. - kernel/compositor.rs: enlaza mirada-layout y calcula un marco por app con el algoritmo MasterStack, dentro del area de pantalla. - consola::volcar_marco centra el fotograma natural de la app dentro de su marco teselado (antes lo depositaba en region.x/y fijos). - ContextoCapacidades lleva marco + natural_ancho/alto; sys_render_frame valida el fotograma contra el tamaño natural. - cargar_userspace tesela con el compositor y pinta el escenario antes de encender las apps. Las apps NO cambian: el compositor reordena la pantalla sin que ninguna toque una instruccion. Verificado en QEMU (screendump): las cinco apps de genesis teseladas en MasterStack — hola como ventana maestra, el resto apiladas a la derecha, cada lienzo centrado en su panel. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
// =============================================================================
|
||||
// renaser :: kernel/src/compositor.rs — Fase 8 :: el compositor teselante
|
||||
// -----------------------------------------------------------------------------
|
||||
// Hasta la Fase 7, cada app llevaba su region escrita a mano en el manifiesto:
|
||||
// coordenadas fijas, una composicion rigida. La Fase 8 entrega esa decision a
|
||||
// un COMPOSITOR: el kernel ya no coloca las ventanas a mano, las TESELA.
|
||||
//
|
||||
// El motor de teselado es `mirada-layout` — el mismo nucleo `no_std` que
|
||||
// ordena las ventanas del compositor Wayland de brahman. Cruza la frontera de
|
||||
// workspace y se enlaza aqui sin una linea de codigo nueva: geometria pura,
|
||||
// determinista, la misma en Linux y en el bare-metal de renaser.
|
||||
//
|
||||
// Cada app conserva su tamaño NATURAL —el lienzo que sabe pintar, fijo—; el
|
||||
// compositor decide DONDE va ese lienzo. El kernel centra el fotograma natural
|
||||
// de la app dentro del marco teselado. Asi el compositor reordena la pantalla
|
||||
// sin que ninguna app cambie una sola instruccion.
|
||||
// =============================================================================
|
||||
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use mirada_layout::{tile, LayoutMode, LayoutParams, Rect};
|
||||
|
||||
use crate::grafico::RegionPantalla;
|
||||
|
||||
/// Altura del strip superior reservado a la consola; las apps teselan debajo.
|
||||
/// La consola conserva ahi su registro de arranque completo —seis lineas,
|
||||
/// hasta la sonda asincrona de disco— legible sobre el teselado.
|
||||
const FRANJA_CONSOLA: usize = 296;
|
||||
|
||||
/// El modo de teselado del compositor. Fijo por ahora — la Fase 8b lo hara
|
||||
/// conmutable en caliente desde el teclado, recorriendo los siete modos que
|
||||
/// `mirada-layout` ofrece.
|
||||
const MODO: LayoutMode = LayoutMode::MasterStack;
|
||||
|
||||
/// Margen entre ventanas teseladas, en pixeles — el aire que separa un marco
|
||||
/// de sus vecinos.
|
||||
const MARGEN: i32 = 14;
|
||||
|
||||
/// El area de pantalla que el compositor tesela: toda la pantalla menos la
|
||||
/// franja de la consola en la cima.
|
||||
pub fn area_apps(ancho_pantalla: usize, alto_pantalla: usize) -> RegionPantalla {
|
||||
RegionPantalla {
|
||||
x: 0,
|
||||
y: FRANJA_CONSOLA.min(alto_pantalla),
|
||||
ancho: ancho_pantalla,
|
||||
alto: alto_pantalla.saturating_sub(FRANJA_CONSOLA),
|
||||
}
|
||||
}
|
||||
|
||||
/// Tesela el area de apps en `n` marcos —uno por ventana, en el orden de las
|
||||
/// apps del manifiesto— con el algoritmo de `mirada-layout`. El vector
|
||||
/// resultante tiene exactamente `n` elementos.
|
||||
pub fn disponer(n: usize, ancho_pantalla: usize, alto_pantalla: usize) -> Vec<RegionPantalla> {
|
||||
let area = area_apps(ancho_pantalla, alto_pantalla);
|
||||
let pantalla = Rect::new(
|
||||
area.x as i32,
|
||||
area.y as i32,
|
||||
area.ancho as i32,
|
||||
area.alto as i32,
|
||||
);
|
||||
let params = LayoutParams {
|
||||
mode: MODO,
|
||||
gap: MARGEN,
|
||||
..LayoutParams::default()
|
||||
};
|
||||
tile(pantalla, n, ¶ms)
|
||||
.into_iter()
|
||||
.map(rect_a_region)
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Traduce un `Rect` de `mirada-layout` (`i32`, en teoria con signo) a la
|
||||
/// `RegionPantalla` del kernel (`usize`). Un rectangulo degenerado queda en
|
||||
/// cero — el kernel no compondra nada en el.
|
||||
fn rect_a_region(r: Rect) -> RegionPantalla {
|
||||
RegionPantalla {
|
||||
x: r.x.max(0) as usize,
|
||||
y: r.y.max(0) as usize,
|
||||
ancho: r.w.max(0) as usize,
|
||||
alto: r.h.max(0) as usize,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user