feat(renaser): Fase 15 — la voz del sistema (acorde + eventos)
La bocina pertenecía al app enfocado (Fase 12), pero el kernel necesita hablar también. Ahora tiene voz propia, prioritaria. - `altavoz`: cola `SECUENCIA: Mutex<VecDeque<(u32,u32)>>` (freq, ms) + reloj `FIN_NOTA: AtomicU64`. `agendar(&[...])` encola; `atender()` (tarea del compositor cada fotograma) avanza la secuencia y silencia al acabar; `kernel_sonando()` gatea a los apps — mientras el kernel suena, `sys_tono` no-op. - Catálogo: VOZ_BIENVENIDA (Do5-Mi5-Sol5, 500 ms), VOZ_LANZAR (700→1050 Hz), VOZ_CERRAR (900→520 Hz), VOZ_DESALOJO (180 Hz). - Hitos: `kernel_main` agenda el acorde antes de `ejecutor.run`; `nacer_ventana` (Alt+N), `cerrar` (Alt+Q), `desalojar` (falla) agendan al hacer su trabajo. - De paso: las pestañas de la barra de tareas calculan su tinta por brillo del fondo (ITU-R BT.601); la pestaña crema del desalojo por memoria, que llevaba texto blanco invisible, ahora luce su nombre en tinta oscura. Verificado en QEMU con `-audiodev wav -machine pcspk-audiodev=spk`: el PCM crudo trae, en orden, el acorde de bienvenida (~520, 630, 760 Hz), un brevísimo 180 Hz (las balizas de discola/glotona desalojadas) y después la escala de Do mayor de tonada. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -356,6 +356,8 @@ pub fn desalojar(indice: usize, color: Color) {
|
||||
}
|
||||
ventana.baliza = Some(color);
|
||||
}
|
||||
// Fase 15: la voz del kernel anuncia el desalojo.
|
||||
crate::drivers::altavoz::agendar(&crate::drivers::altavoz::VOZ_DESALOJO);
|
||||
|
||||
if escritorio.flotantes.is_empty() {
|
||||
let marco = escritorio.ventanas[indice].marco;
|
||||
@@ -629,7 +631,7 @@ fn recomponer(escritorio: &Escritorio) {
|
||||
},
|
||||
nombre: &ventana.nombre,
|
||||
fondo,
|
||||
tinta: Color::TEXTO,
|
||||
tinta: tinta_para(fondo),
|
||||
});
|
||||
cx += CELDA_TASKBAR_ANCHO + CELDA_TASKBAR_HUECO;
|
||||
}
|
||||
@@ -690,6 +692,8 @@ fn cerrar() {
|
||||
Some(v) if v.baliza.is_none() && !v.cerrada => {}
|
||||
_ => return,
|
||||
}
|
||||
// Fase 15: el kernel se despide de la app con un repique descendente.
|
||||
crate::drivers::altavoz::agendar(&crate::drivers::altavoz::VOZ_CERRAR);
|
||||
// Marcar la baja y liberar el respaldo: la cache de un fotograma puede
|
||||
// pesar un megabyte — no tiene sentido retenerla en una ranura inerte.
|
||||
let ventana = &mut escritorio.ventanas[foco];
|
||||
@@ -752,6 +756,8 @@ pub fn nacer_ventana(nat_ancho: usize, nat_alto: usize, nombre: &str) -> usize {
|
||||
escritorio.orden.push(indice);
|
||||
aplicar_teselado(&mut escritorio);
|
||||
recomponer(&escritorio);
|
||||
// Fase 15: el kernel saluda al nacimiento con un repique ascendente.
|
||||
crate::drivers::altavoz::agendar(&crate::drivers::altavoz::VOZ_LANZAR);
|
||||
indice
|
||||
}
|
||||
|
||||
@@ -961,6 +967,21 @@ fn area_taskbar(ancho_pantalla: usize, alto_pantalla: usize) -> RegionPantalla {
|
||||
}
|
||||
}
|
||||
|
||||
/// El color de tinta —oscuro o claro— que da contraste legible sobre `fondo`.
|
||||
/// Sin esto, la pestaña amarilla palida del desalojo por memoria quedaba con
|
||||
/// texto blanco sobre crema: ilegible. La regla de luminancia ITU-R BT.601 fija
|
||||
/// el umbral: fondos claros llevan tinta oscura, fondos oscuros la clara.
|
||||
fn tinta_para(fondo: Color) -> Color {
|
||||
let brillo =
|
||||
(fondo.r as u32 * 299 + fondo.g as u32 * 587 + fondo.b as u32 * 114) / 1000;
|
||||
if brillo > 160 {
|
||||
// Fondo claro: tinta del reposo del lienzo, casi negra.
|
||||
Color::LIENZO_EN_REPOSO
|
||||
} else {
|
||||
Color::TEXTO
|
||||
}
|
||||
}
|
||||
|
||||
/// Tesela el area de apps en `n` marcos con el modo dado. El vector resultante
|
||||
/// tiene exactamente `n` elementos, en el orden de las celdas del teselado.
|
||||
fn teselar(n: usize, ancho: usize, alto: usize, modo: LayoutMode) -> Vec<RegionPantalla> {
|
||||
|
||||
Reference in New Issue
Block a user