atagen

monolith

public
Star0
Watch0

Commit 3c7b8405eb7d

tarball

atagen <boss@atagen.co>2026-10-19 07:54 UTC

1 file changed+22-1
layers: skip focus sync unless a layer's focus claim changed

Every surface commit searched all layer maps, and reserve_layers ended in sync_focus even when nothing changed, so a 60 Hz bar reran focus sync at 60 Hz. Now only layer surfaces take the path, and focus syncs only when the layer keyboard target differs from the seat's focus.
Modified file: crates/monolith/src/layers.rs+22 additions−1 deletions
@@ -1,5 +1,6 @@
11 //! wlr-layer-shell, for bars, launchers, wallpapers and notifications.
22
3+use crate::focus::Focus;
34 use crate::scene::Draw;
45 use crate::state::State;
56 use monolith_layout::{Insets, OutputId};
@@ -13,6 +14,7 @@ use smithay::reexports::wayland_server::protocol::wl_output::WlOutput;
1314 use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;
1415 use smithay::utils::{Logical, Point, Scale};
1516 use smithay::wayland::compositor::with_states;
17+use smithay::wayland::seat::WaylandFocus;
1618 use smithay::wayland::shell::wlr_layer::{
1719 KeyboardInteractivity, Layer, LayerSurface as WlrLayerSurface, LayerSurfaceData,
1820 WlrLayerShellHandler, WlrLayerShellState,
@@ -82,6 +84,9 @@ impl State {
8284 /// anchors and size, and picks up exclusive zone changes after that.
8385 /// Returns false for surfaces that are not layer surfaces.
8486 pub fn layer_commit(&mut self, surface: &WlSurface) -> bool {
87+ if with_states(surface, |s| s.data_map.get::<LayerSurfaceData>().is_none()) {
88+ return false;
89+ }
8590 let Some(output) = self
8691 .wm
8792 .space
@@ -160,11 +165,27 @@ impl State {
160165 }
161166 if changed {
162167 self.apply_layout();
163- } else {
168+ } else if self.layer_focus_stale() {
164169 self.sync_focus();
165170 }
166171 }
167172
173+ fn layer_focus_stale(&self) -> bool {
174+ if self.services.lock.active() {
175+ return false;
176+ }
177+ let Some(keyboard) = self.input.seat.get_keyboard() else {
178+ return false;
179+ };
180+ let current = keyboard.current_focus();
181+ match self.layer_keyboard_focus() {
182+ Some(wanted) => current != Some(Focus::from(wanted)),
183+ None => current
184+ .and_then(|f| f.wl_surface().map(|s| s.into_owned()))
185+ .is_some_and(|s| self.layer_maps_contain(&s)),
186+ }
187+ }
188+
168189 /// The layer surface that should hold the keyboard, if any. One asking
169190 /// for exclusive focus above the windows wins over everything.
170191 pub fn layer_keyboard_focus(&self) -> Option<WlSurface> {