feat(mirada): pantalla completa real — toggle-fullscreen

ToggleFullscreen (Super+Shift+f) lleva la ventana enfocada a pantalla
completa: cubre toda la salida sin gap, oculta al resto y se lleva el
foco. Distinto del modo Monocle (un modo de teselado): es un estado
por ventana que ignora el layout.

- Workspace.fullscreen: Option<WindowId>; set_fullscreen / fullscreen();
  remove() lo limpia si se cierra esa ventana.
- placements() da a la fullscreen el rect completo y marca al resto
  visible: false. WindowPlacement y BodyOp::Configure llevan
  fullscreen: bool.
- mirada-compositor fija el estado xdg_toplevel::Fullscreen en la
  superficie, para que el cliente lo sepa.
- Cableado en keymap, HUD de mirada y mirada-ctl.

Verificado end-to-end con headless-ctl. mirada-protocol 10->11,
mirada-brain 51->52.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
sergio
2026-05-21 01:07:01 +00:00
parent 6dfd9e62ac
commit be61ddb6eb
12 changed files with 133 additions and 11 deletions
@@ -21,6 +21,9 @@ pub struct Workspace {
/// Ventanas flotantes y su rectángulo: salen del teselado y se pintan
/// encima. Las que no están aquí se teselan normalmente.
floating: BTreeMap<WindowId, Rect>,
/// La ventana en pantalla completa, si hay alguna: cubre toda la
/// salida y oculta al resto.
fullscreen: Option<WindowId>,
}
impl Workspace {
@@ -31,6 +34,7 @@ impl Workspace {
focus: 0,
params,
floating: BTreeMap::new(),
fullscreen: None,
}
}
@@ -84,6 +88,9 @@ impl Workspace {
};
self.windows.remove(i);
self.floating.remove(&window);
if self.fullscreen == Some(window) {
self.fullscreen = None;
}
if i < self.focus {
self.focus -= 1;
}
@@ -111,6 +118,16 @@ impl Workspace {
self.floating.contains_key(&window)
}
/// La ventana en pantalla completa de este escritorio, si hay alguna.
pub fn fullscreen(&self) -> Option<WindowId> {
self.fullscreen
}
/// Pone (o quita, con `None`) la ventana en pantalla completa.
pub fn set_fullscreen(&mut self, window: Option<WindowId>) {
self.fullscreen = window;
}
/// Ventana enfocada, o `None` si el escritorio está vacío.
pub fn focused(&self) -> Option<WindowId> {
self.windows.get(self.focus).copied()