feat(mirada): fullscreen iniciado por el cliente + HUD multi-salida
Dos remates de la tanda WM.
Fullscreen del cliente:
- BodyEvent::FullscreenRequest { id, fullscreen }. mirada-compositor
implementa XdgShellHandler::fullscreen_request / unfullscreen_request
y avisa al Cerebro; Desktop::on_event fija el fullscreen en el
escritorio que tiene la ventana. Así un reproductor o un juego que
llama a xdg set_fullscreen entra a pantalla completa solo.
HUD multi-salida (app mirada):
- El lienzo dibuja todas las salidas a escala (encaja su caja
envolvente en el lienzo fijo; con una salida, 1:1), cada una con su
marco y su número/escritorio. En simulación, Shift+n añade un monitor.
mirada-brain 63->65 tests.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -72,7 +72,8 @@ ejecuta operaciones de geometría".
|
||||
devuelven los `BodyEvent` a mandar. Ejemplo `headless`: un Cuerpo sin
|
||||
gráficos guiado por stdin para ejercitar el bucle entero.
|
||||
- **`mirada` (app)** — envuelve `Desktop` y lo pinta (barra de
|
||||
escritorios + modo + foco, lienzo teselado). Con `MIRADA_SOCKET`
|
||||
escritorios + modo + foco, lienzo teselado). El lienzo dibuja **todas
|
||||
las salidas a escala**, cada una con su marco. Con `MIRADA_SOCKET`
|
||||
conecta a un Cuerpo; sin él corre en **simulación** (ventanas
|
||||
sintéticas, teclado de la propia ventana). Pips de escritorio y
|
||||
ventanas clicables.
|
||||
@@ -122,7 +123,9 @@ que un front-end (`Keybind` → `lookup` → `apply`); hay otros tres:
|
||||
- **Pantalla completa** — `ToggleFullscreen` (`Super+Shift+f`): la ventana
|
||||
cubre toda la salida (sin gap), oculta al resto y se lleva el foco;
|
||||
`Workspace.fullscreen: Option<WindowId>`, y el Cuerpo le fija el estado
|
||||
`xdg_toplevel Fullscreen`.
|
||||
`xdg_toplevel Fullscreen`. También atiende la petición del propio
|
||||
cliente (`xdg set_fullscreen` → `BodyEvent::FullscreenRequest`), así
|
||||
que un reproductor o un juego entran a pantalla completa solos.
|
||||
- **Multi-monitor** — cada `Output` muestra un escritorio distinto;
|
||||
`SwitchWorkspace` actúa sobre la salida enfocada (y la intercambia si
|
||||
el escritorio pedido ya lo muestra otra salida); `FocusOutputNext`
|
||||
@@ -175,7 +178,7 @@ a las ya abiertas.
|
||||
## Estado
|
||||
|
||||
Implementado y verde: `mirada-layout` (32 tests), `mirada-protocol`
|
||||
(11), `mirada-brain` (63), `mirada-link` (7), `mirada-body` (14), las
|
||||
(11), `mirada-brain` (65), `mirada-link` (7), `mirada-body` (14), las
|
||||
apps `mirada` y `mirada-compositor` (compilan; verificación visual
|
||||
manual) y `mirada-ctl` (CLI, probado vía el ejemplo `headless-ctl`).
|
||||
|
||||
|
||||
@@ -188,6 +188,27 @@ impl Desktop {
|
||||
Some(action) => self.apply(action),
|
||||
None => Vec::new(),
|
||||
},
|
||||
BodyEvent::FullscreenRequest { id, fullscreen } => {
|
||||
// El cliente (un reproductor, un juego) pidió pantalla
|
||||
// completa: la fijamos en el escritorio que tiene la ventana.
|
||||
let mut changed = false;
|
||||
for ws in &mut self.workspaces {
|
||||
if ws.windows().contains(&id) {
|
||||
if fullscreen {
|
||||
ws.set_fullscreen(Some(id));
|
||||
} else if ws.fullscreen() == Some(id) {
|
||||
ws.set_fullscreen(None);
|
||||
}
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if changed {
|
||||
self.relayout()
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -985,6 +1006,27 @@ mod tests {
|
||||
assert!(d.apply(DesktopAction::ToggleScratchpad).is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_client_fullscreen_request_is_honoured() {
|
||||
let mut d = desktop_with_screen();
|
||||
open(&mut d, 1);
|
||||
open(&mut d, 2);
|
||||
let cmds = d.on_event(BodyEvent::FullscreenRequest { id: 1, fullscreen: true });
|
||||
assert!(places(&cmds).iter().find(|x| x.id == 1).unwrap().fullscreen);
|
||||
// El cliente la suelta.
|
||||
let cmds = d.on_event(BodyEvent::FullscreenRequest { id: 1, fullscreen: false });
|
||||
assert!(!places(&cmds).iter().find(|x| x.id == 1).unwrap().fullscreen);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_fullscreen_request_for_an_unknown_window_does_nothing() {
|
||||
let mut d = desktop_with_screen();
|
||||
open(&mut d, 1);
|
||||
assert!(d
|
||||
.on_event(BodyEvent::FullscreenRequest { id: 99, fullscreen: true })
|
||||
.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn window_lines_show_a_stashed_window_as_workspace_zero() {
|
||||
let mut d = desktop_with_screen();
|
||||
|
||||
@@ -88,6 +88,9 @@ pub enum BodyEvent {
|
||||
Keybind(String),
|
||||
/// El puntero entró en una ventana — el Cerebro puede enfocar al pasar.
|
||||
PointerEntered { id: WindowId },
|
||||
/// Un cliente pidió pantalla completa para su ventana (`true`), o la
|
||||
/// soltó (`false`) — `xdg_toplevel.set_fullscreen`.
|
||||
FullscreenRequest { id: WindowId, fullscreen: bool },
|
||||
}
|
||||
|
||||
/// Tamaño máximo de un marco, en bytes. Acota el búfer de [`read_frame`]
|
||||
|
||||
Reference in New Issue
Block a user