feat(mirada): ventanas flotantes — toggle-float
Una ventana puede salir del teselado y flotar: conserva su propio rectángulo y se compone por encima de las teseladas. - Workspace guarda las flotantes en un mapa aparte; layout() tesela sólo las no-flotantes y añade las flotantes al final (orden de pintado). set_floating / is_floating. - WindowPlacement y BodyOp::Configure llevan floating: bool. BodyState detecta el cambio de floating como cualquier otro reconfigure. - DesktopAction::ToggleFloat (Super+f): saca la enfocada a un rectángulo centrado al 60 % de la pantalla, o la devuelve al teselado. En Monocle, una flotante sigue visible. - mirada-compositor ordena las flotantes al frente de la lista front-to-back de elementos → se pintan encima. - HUD de mirada marca las flotantes; mirada-ctl toggle-float. Verificado end-to-end con headless-ctl. mirada-layout 30->32, mirada-protocol 9->10, mirada-body 13->14, mirada-brain 41->42. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -82,6 +82,8 @@ struct ManagedWindow {
|
||||
/// Esquina superior-izquierda en píxeles, según el Cerebro.
|
||||
loc: (i32, i32),
|
||||
visible: bool,
|
||||
/// `true` si flota: se compone por encima de las teseladas.
|
||||
floating: bool,
|
||||
}
|
||||
|
||||
/// El estado global del compositor.
|
||||
@@ -170,10 +172,11 @@ impl App {
|
||||
/// Ejecuta una operación concreta sobre las superficies reales.
|
||||
fn exec_op(&mut self, op: BodyOp) {
|
||||
match op {
|
||||
BodyOp::Configure { id, rect, visible } => {
|
||||
BodyOp::Configure { id, rect, visible, floating } => {
|
||||
if let Some(w) = self.windows.iter_mut().find(|w| w.id == id) {
|
||||
w.loc = (rect.x, rect.y);
|
||||
w.visible = visible;
|
||||
w.floating = floating;
|
||||
w.toplevel.with_pending_state(|s| {
|
||||
s.size = Some((rect.w.max(1), rect.h.max(1)).into());
|
||||
});
|
||||
@@ -244,6 +247,7 @@ impl App {
|
||||
surface,
|
||||
loc: (0, 0),
|
||||
visible: false,
|
||||
floating: false,
|
||||
});
|
||||
let ev = self.body.open_surface(id, app_id, title);
|
||||
self.brain_feed(ev);
|
||||
@@ -684,10 +688,15 @@ fn run() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let damage: Rectangle<i32, smithay::utils::Physical> = Rectangle::from_size(size);
|
||||
{
|
||||
let (renderer, mut framebuffer) = backend.bind().unwrap();
|
||||
let elements: Vec<WaylandSurfaceRenderElement<GlesRenderer>> = state
|
||||
.windows
|
||||
// Orden de pintado: la lista de elementos va front-to-back
|
||||
// (índice 0 = encima), así que las flotantes —que deben
|
||||
// quedar sobre las teseladas— se ordenan primero. `sort_by_key`
|
||||
// es estable: dentro de cada grupo se respeta el orden de apertura.
|
||||
let mut shown: Vec<&ManagedWindow> =
|
||||
state.windows.iter().filter(|w| w.visible).collect();
|
||||
shown.sort_by_key(|w| !w.floating);
|
||||
let elements: Vec<WaylandSurfaceRenderElement<GlesRenderer>> = shown
|
||||
.iter()
|
||||
.filter(|w| w.visible)
|
||||
.flat_map(|w| {
|
||||
render_elements_from_surface_tree(
|
||||
renderer,
|
||||
|
||||
@@ -120,6 +120,7 @@ Acciones de mirada-ctl:
|
||||
move-forward adelanta la ventana enfocada en el teselado
|
||||
move-backward la atrasa
|
||||
close-focused cierra la ventana enfocada
|
||||
toggle-float alterna flotante / teselada la enfocada
|
||||
cycle-layout pasa al siguiente modo de teselado
|
||||
layout <modo> master-stack · centered-master · spiral
|
||||
grid · columns · rows · monocle
|
||||
|
||||
@@ -21,10 +21,10 @@
|
||||
//! ```text
|
||||
//! n abre una ventana tab / espacio cicla layout
|
||||
//! w cierra la enfocada t m g c r d s layout directo
|
||||
//! j / k foco siguiente/anterior h / l área maestra −/+
|
||||
//! Shift+j / k mueve la enfocada , / . nmaster −/+
|
||||
//! Enter promueve a maestra 1..9 ir a escritorio
|
||||
//! Ctrl+1..9 enviar a escritorio
|
||||
//! f flota / tesela h / l área maestra −/+
|
||||
//! j / k foco siguiente/anterior , / . nmaster −/+
|
||||
//! Shift+j / k mueve la enfocada 1..9 ir a escritorio
|
||||
//! Enter promueve a maestra Ctrl+1..9 enviar a escritorio
|
||||
//! ```
|
||||
//!
|
||||
//! Los pips de escritorio y las ventanas del lienzo son **clicables**, y
|
||||
@@ -278,6 +278,7 @@ impl Mirada {
|
||||
match ks.key.as_str() {
|
||||
"n" if !connected => self.open_window(),
|
||||
"w" => self.act(DesktopAction::CloseFocused),
|
||||
"f" => self.act(DesktopAction::ToggleFloat),
|
||||
"j" if shift => self.act(DesktopAction::MoveForward),
|
||||
"k" if shift => self.act(DesktopAction::MoveBackward),
|
||||
"j" => self.act(DesktopAction::FocusNext),
|
||||
@@ -440,6 +441,11 @@ impl Render for Mirada {
|
||||
let tb_bg = if p.focused { theme.accent } else { theme.bg_row_hover };
|
||||
let tb_fg = if p.focused { on_accent } else { theme.fg_muted };
|
||||
let pid = p.id;
|
||||
let kind_label = if p.floating {
|
||||
"· ventana flotante ·"
|
||||
} else {
|
||||
"· superficie del Cuerpo ·"
|
||||
};
|
||||
|
||||
canvas = canvas.child(
|
||||
div()
|
||||
@@ -486,7 +492,7 @@ impl Render for Mirada {
|
||||
.gap(px(4.))
|
||||
.text_color(theme.fg_disabled)
|
||||
.child(SharedString::from(app_id))
|
||||
.child("· superficie del Cuerpo ·"),
|
||||
.child(kind_label),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user