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:
@@ -48,6 +48,8 @@ pub struct WindowPlacement {
|
||||
pub focused: bool,
|
||||
/// `true` si flota (fuera del teselado): el Cuerpo la pinta encima.
|
||||
pub floating: bool,
|
||||
/// `true` si está en pantalla completa: cubre toda la salida.
|
||||
pub fullscreen: bool,
|
||||
}
|
||||
|
||||
/// Una orden del Cerebro al Cuerpo.
|
||||
@@ -140,20 +142,31 @@ pub fn read_frame<R: Read, T: DeserializeOwned>(r: &mut R) -> io::Result<Option<
|
||||
/// En modo [`LayoutMode::Monocle`] sólo la ventana enfocada queda
|
||||
/// `visible`; en el resto de modos todas lo están.
|
||||
pub fn placements(ws: &Workspace, screen: Rect) -> Vec<WindowPlacement> {
|
||||
let fullscreen = ws.fullscreen();
|
||||
let monocle = ws.params().mode == LayoutMode::Monocle;
|
||||
let focused = ws.focused();
|
||||
ws.layout(screen)
|
||||
.into_iter()
|
||||
.map(|(id, rect)| {
|
||||
let is_focused = focused == Some(id);
|
||||
let floating = ws.is_floating(id);
|
||||
let is_fs = fullscreen == Some(id);
|
||||
// Con una ventana en pantalla completa manda ella: ocupa toda
|
||||
// la salida, es la única visible y se lleva el foco.
|
||||
let (rect, visible, is_focused) = match fullscreen {
|
||||
Some(_) => (if is_fs { screen } else { rect }, is_fs, is_fs),
|
||||
None => {
|
||||
let f = focused == Some(id);
|
||||
// Una flotante siempre se ve; en `Monocle`, sólo la enfocada.
|
||||
(rect, floating || !monocle || f, f)
|
||||
}
|
||||
};
|
||||
WindowPlacement {
|
||||
id,
|
||||
rect,
|
||||
// Una flotante siempre se ve; en `Monocle`, sólo la enfocada.
|
||||
visible: floating || !monocle || is_focused,
|
||||
visible,
|
||||
focused: is_focused,
|
||||
floating,
|
||||
fullscreen: is_fs,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
@@ -183,6 +196,7 @@ mod tests {
|
||||
visible: true,
|
||||
focused: true,
|
||||
floating: false,
|
||||
fullscreen: false,
|
||||
}]);
|
||||
let mut buf = Vec::new();
|
||||
write_frame(&mut buf, &cmd).unwrap();
|
||||
@@ -277,6 +291,19 @@ mod tests {
|
||||
assert_eq!(f.rect, Rect::new(0, 0, 200, 200));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_fullscreen_window_covers_the_screen_and_hides_the_rest() {
|
||||
let mut w = ws(LayoutMode::Columns);
|
||||
w.set_fullscreen(Some(20));
|
||||
let p = placements(&w, SCREEN);
|
||||
let fs = p.iter().find(|x| x.id == 20).unwrap();
|
||||
assert!(fs.fullscreen);
|
||||
assert!(fs.focused, "la ventana en pantalla completa se lleva el foco");
|
||||
assert_eq!(fs.rect, SCREEN);
|
||||
// El resto queda oculto.
|
||||
assert!(p.iter().filter(|x| x.id != 20).all(|x| !x.visible));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn placements_fill_a_place_command_round_trip() {
|
||||
let cmd = BrainCommand::Place(placements(&ws(LayoutMode::Grid), SCREEN));
|
||||
|
||||
Reference in New Issue
Block a user