feat(mirada): nmaster, promover a maestra y smart gaps (estilo dwm)

Tanda de funciones de tiling WM, toda pura (mirada-layout/brain), sin
tocar el protocolo:

- nmaster: LayoutParams.master_count — cuántas ventanas van en el área
  maestra. MasterStack y CenteredMaster apilan N maestras; sin pila, las
  maestras llenan la pantalla. Acciones inc-master/dec-master (Super+,
  Super+.), acotadas 1..9.
- Promover a maestra: Workspace::promote_focused lleva la ventana
  enfocada al puesto 0. Acción promote-to-master (Super+Return).
- Smart gaps: una sola ventana se tesela a sangre, sin margen.

combo_string del compositor canoniza ahora teclas con nombre (Return,
Tab, F5, flechas…) vía xkb::keysym_get_name, no sólo caracteres
imprimibles — sin eso Super+Return no sería un atajo expresable.

Cableado en keymap por defecto, HUD de mirada y mirada-ctl. Verificado
end-to-end con headless-ctl. mirada-layout 26->30, mirada-brain 39->41.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
sergio
2026-05-21 00:45:47 +00:00
parent 8821d34bd5
commit 2dd8ff139e
11 changed files with 228 additions and 42 deletions
@@ -46,6 +46,12 @@ pub enum DesktopAction {
GrowMaster,
/// Encoge el área de la ventana maestra.
ShrinkMaster,
/// Mete una ventana más en el área maestra (`nmaster`).
IncMaster,
/// Saca una ventana del área maestra.
DecMaster,
/// Lleva la ventana enfocada al puesto maestro (orden de teselado).
PromoteToMaster,
/// Activa el escritorio virtual `n` (índice 0-based).
SwitchWorkspace(usize),
/// Manda la ventana enfocada al escritorio virtual `n`.
@@ -96,6 +102,9 @@ impl fmt::Display for DesktopAction {
DesktopAction::SetLayout(m) => write!(f, "layout:{}", layout_slug(*m)),
DesktopAction::GrowMaster => f.write_str("grow-master"),
DesktopAction::ShrinkMaster => f.write_str("shrink-master"),
DesktopAction::IncMaster => f.write_str("inc-master"),
DesktopAction::DecMaster => f.write_str("dec-master"),
DesktopAction::PromoteToMaster => f.write_str("promote-to-master"),
// Los escritorios se numeran 1-based de cara al usuario.
DesktopAction::SwitchWorkspace(n) => write!(f, "workspace:{}", n + 1),
DesktopAction::SendToWorkspace(n) => write!(f, "send-to-workspace:{}", n + 1),
@@ -119,6 +128,9 @@ impl FromStr for DesktopAction {
"cycle-layout" => Self::CycleLayout,
"grow-master" => Self::GrowMaster,
"shrink-master" => Self::ShrinkMaster,
"inc-master" => Self::IncMaster,
"dec-master" => Self::DecMaster,
"promote-to-master" => Self::PromoteToMaster,
"quit" => Self::Quit,
_ => {
if let Some(slug) = s.strip_prefix("layout:") {
@@ -181,6 +193,9 @@ pub fn default_keymap() -> Vec<(String, DesktopAction)> {
("Super+s".into(), DesktopAction::SetLayout(LayoutMode::Spiral)),
("Super+h".into(), DesktopAction::ShrinkMaster),
("Super+l".into(), DesktopAction::GrowMaster),
("Super+Return".into(), DesktopAction::PromoteToMaster),
("Super+,".into(), DesktopAction::IncMaster),
("Super+.".into(), DesktopAction::DecMaster),
("Super+Shift+e".into(), DesktopAction::Quit),
];
// Un escritorio por dígito: `Super+1`..`Super+9` lo activan,