atagen

monolith

public
Star0
Watch0

Commit 03f06fcf10d6

tarball

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

3 files changed+30-32
frame: compute the shown windows once per frame

shown_windows ran again for frame callbacks and for presentation feedback, and render_surface arranged a third time for the VRR decision. A single Shown now carries the windows, the fullscreen window and the covered flag to all three.
Modified file: crates/monolith/src/drm.rs+5 additions−7 deletions
@@ -1014,7 +1014,8 @@ fn render_surface(state: &mut State, crtc: crtc::Handle, target: u64) -> bool {
10141014 return false;
10151015 }
10161016 surface.cursor_redraw = false;
1017- let fullscreen = wm.layout.arrange(surface.id).fullscreen;
1017+ let shown = crate::frame::shown_windows(wm, surface.id, &surface.output, target);
1018+ let fullscreen = shown.fullscreen;
10181019 let forced = fullscreen.and_then(|w| wm.get(w)?.rule.vrr);
10191020 let want_vrr = surface.vrr_capable
10201021 && forced.unwrap_or(match settings.config.output.vrr {
@@ -1070,9 +1071,8 @@ fn render_surface(state: &mut State, crtc: crtc::Handle, target: u64) -> bool {
10701071 wm,
10711072 lock,
10721073 xwayland.as_ref().map_or(&[], |x| &x.unmanaged),
1073- surface.id,
1074+ &shown,
10741075 &surface.output,
1075- now,
10761076 &result.states,
10771077 );
10781078 if direct {
@@ -1110,9 +1110,8 @@ fn render_surface(state: &mut State, crtc: crtc::Handle, target: u64) -> bool {
11101110 wm,
11111111 lock,
11121112 xwayland.as_ref().map_or(&[], |x| &x.unmanaged),
1113- surface.id,
1113+ &shown,
11141114 &surface.output,
1115- now,
11161115 &result.states,
11171116 ));
11181117 lock.shown(&surface.output);
@@ -1153,9 +1152,8 @@ fn render_surface(state: &mut State, crtc: crtc::Handle, target: u64) -> bool {
11531152 wm,
11541153 lock,
11551154 xwayland.as_ref().map_or(&[], |x| &x.unmanaged),
1156- surface.id,
1155+ &shown,
11571156 &surface.output,
1158- now,
11591157 elapsed,
11601158 input.dnd_icon.as_ref(),
11611159 );
Modified file: crates/monolith/src/frame.rs+22 additions−21 deletions
@@ -7,7 +7,7 @@ use crate::scene::Draw;
77 use crate::state::Input;
88 use crate::wm::Wm;
99 use monolith_config::Decoration;
10-use monolith_layout::OutputId;
10+use monolith_layout::{OutputId, WindowId};
1111 use monolith_render_vk::VulkanRenderer;
1212 use smithay::backend::renderer::element::RenderElementStates;
1313 use smithay::desktop::Window;
@@ -84,14 +84,12 @@ pub fn compose(
8484 /// window at rest only it and the overlay layer are shown, and anything
8585 /// else that kept drawing would hold the output, or a VRR panel, at full
8686 /// refresh for frames nobody sees.
87-#[expect(clippy::too_many_arguments)]
8887 pub fn send_frame_callbacks(
8988 wm: &Wm,
9089 lock: &Lock,
9190 unmanaged: &[X11Surface],
92- o: OutputId,
91+ shown: &Shown,
9392 output: &Output,
94- now: u64,
9593 elapsed: Duration,
9694 dnd_icon: Option<&DndIcon>,
9795 ) {
@@ -108,8 +106,7 @@ pub fn send_frame_callbacks(
108106 crate::lock::send_frames(lock, output, elapsed);
109107 return;
110108 }
111- let (windows, covered) = shown_windows(wm, o, output, now);
112- for window in windows {
109+ for window in &shown.windows {
113110 window.send_frame(
114111 output,
115112 elapsed,
@@ -117,7 +114,7 @@ pub fn send_frame_callbacks(
117114 crate::fifo::scanout(output),
118115 );
119116 }
120- crate::layers::send_frames(output, elapsed, covered);
117+ crate::layers::send_frames(output, elapsed, shown.covered);
121118 if let Some(geo) = wm.space.output_geometry(output) {
122119 for surface in unmanaged
123120 .iter()
@@ -131,14 +128,15 @@ pub fn send_frame_callbacks(
131128 }
132129 }
133130
134-/// The windows `output` shows at `now`, and whether a fullscreen window at
135-/// rest hides everything below the overlay layer.
136-fn shown_windows<'a>(
137- wm: &'a Wm,
138- o: OutputId,
139- output: &'a Output,
140- now: u64,
141-) -> (Vec<&'a Window>, bool) {
131+/// What `output` shows at one instant, worked out once per frame.
132+pub struct Shown {
133+ pub windows: Vec<Window>,
134+ pub fullscreen: Option<WindowId>,
135+ /// A fullscreen window at rest hides everything below the overlay layer.
136+ pub covered: bool,
137+}
138+
139+pub fn shown_windows(wm: &Wm, o: OutputId, output: &Output, now: u64) -> Shown {
142140 let arr = wm.layout.arrange(o);
143141 let covering = arr
144142 .fullscreen
@@ -149,8 +147,13 @@ fn shown_windows<'a>(
149147 .space
150148 .elements_for_output(output)
151149 .filter(|&w| covering.is_none_or(|c| c == w || over.contains(&w)))
150+ .cloned()
152151 .collect();
153- (windows, covering.is_some())
152+ Shown {
153+ windows,
154+ fullscreen: arr.fullscreen,
155+ covered: covering.is_some(),
156+ }
154157 }
155158
156159 /// Takes the presentation feedback of everything `output` shows at `now`,
@@ -160,9 +163,8 @@ pub fn take_presentation_feedback(
160163 wm: &Wm,
161164 lock: &Lock,
162165 unmanaged: &[X11Surface],
163- o: OutputId,
166+ shown: &Shown,
164167 output: &Output,
165- now: u64,
166168 states: &RenderElementStates,
167169 ) -> OutputPresentationFeedback {
168170 let mut feedback = OutputPresentationFeedback::new(output);
@@ -174,11 +176,10 @@ pub fn take_presentation_feedback(
174176 crate::lock::take_presentation_feedback(lock, output, &mut feedback, primary, flags);
175177 return feedback;
176178 }
177- let (windows, covered) = shown_windows(wm, o, output, now);
178- for window in windows {
179+ for window in &shown.windows {
179180 window.take_presentation_feedback(&mut feedback, primary, flags);
180181 }
181- crate::layers::take_presentation_feedback(output, covered, &mut feedback, primary, flags);
182+ crate::layers::take_presentation_feedback(output, shown.covered, &mut feedback, primary, flags);
182183 if let Some(geo) = wm.space.output_geometry(output) {
183184 for surface in unmanaged
184185 .iter()
Modified file: crates/monolith/src/nested/mod.rs+3 additions−4 deletions
@@ -277,6 +277,7 @@ pub fn render(state: &mut State) {
277277 }
278278 };
279279 let mut dmabuf = (*slot).clone();
280+ let shown = crate::frame::shown_windows(wm, host.output_id, &host.output, now);
280281 let (damage, feedback) = {
281282 let mut fb = match renderer.bind(&mut dmabuf) {
282283 Ok(fb) => fb,
@@ -307,9 +308,8 @@ pub fn render(state: &mut State) {
307308 wm,
308309 lock,
309310 xwayland.as_ref().map_or(&[], |x| &x.unmanaged),
310- o,
311+ &shown,
311312 &host.output,
312- now,
313313 &result.states,
314314 );
315315 (result.damage.cloned(), feedback)
@@ -327,9 +327,8 @@ pub fn render(state: &mut State) {
327327 wm,
328328 lock,
329329 xwayland.as_ref().map_or(&[], |x| &x.unmanaged),
330- host.output_id,
330+ &shown,
331331 &host.output,
332- now,
333332 elapsed,
334333 input.dnd_icon.as_ref(),
335334 );