feat(mirada): marco de ventana — distinguir y resaltar el foco

Sin decoración, las ventanas se confundían entre sí. Ahora el backend
DRM dibuja un marco fino alrededor de cada ventana: azul la que tiene
el foco del teclado, gris las demás.

- `ManagedWindow` gana `focused: bool` (lo fija `exec_op` al atender
  `BodyOp::Focus`/`Unfocus`) y `borders: [SolidColorBuffer; 4]` — un
  búfer por lado, cada uno con su `Id` estable para el seguimiento de
  daño; `SolidColorBuffer` sube su contador sólo si tamaño o color
  cambian, así un marco quieto no fuerza recomposición.
- El enum `Frame` pasa de `Cursor` a `Solid`: una variante de color
  sólido que sirve para el cursor y para los marcos (dos variantes con
  el mismo tipo chocarían en el `From` que genera `render_elements!`).
- `render()` en dos pasos: refresca los búferes (tamaño = contenido,
  color = foco) y luego arma los elementos. El marco va metido hacia
  adentro, sobre el borde de la superficie, así no pisa al vecino.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
sergio
2026-05-21 04:10:32 +00:00
parent fb3091d995
commit 751416252f
5 changed files with 81 additions and 10 deletions
+13 -1
View File
@@ -24,6 +24,7 @@ use smithay::backend::input::{InputEvent, KeyState, KeyboardKeyEvent};
use smithay::backend::renderer::element::surface::{
render_elements_from_surface_tree, WaylandSurfaceRenderElement,
};
use smithay::backend::renderer::element::solid::SolidColorBuffer;
use smithay::backend::renderer::element::Kind;
use smithay::backend::renderer::gles::GlesRenderer;
use smithay::backend::renderer::utils::{
@@ -99,6 +100,11 @@ struct ManagedWindow {
visible: bool,
/// `true` si flota: se compone por encima de las teseladas.
floating: bool,
/// `true` si tiene el foco del teclado — pinta el marco resaltado.
focused: bool,
/// Búferes de los 4 lados del marco (arriba, abajo, izq., der.) —
/// cada uno con su `Id` estable para el seguimiento de daño.
borders: [SolidColorBuffer; 4],
}
/// Un arrastre de ratón en curso: mueve o redimensiona una ventana.
@@ -232,8 +238,9 @@ impl App {
}
BodyOp::Focus(id) => {
let mut target = None;
for w in &self.windows {
for w in &mut self.windows {
let active = w.id == id;
w.focused = active;
if active {
target = Some(w.surface.clone());
}
@@ -251,6 +258,9 @@ impl App {
}
}
BodyOp::Unfocus => {
for w in &mut self.windows {
w.focused = false;
}
if let Some(kb) = self.keyboard.clone() {
kb.set_focus(self, Option::<WlSurface>::None, SERIAL_COUNTER.next_serial());
}
@@ -297,6 +307,8 @@ impl App {
size: (0, 0),
visible: false,
floating: false,
focused: false,
borders: std::array::from_fn(|_| SolidColorBuffer::default()),
});
let ev = self.body.open_surface(id, app_id, title);
self.brain_feed(ev);