diff --git a/src/layout/floating.rs b/src/layout/floating.rs index 3fac30f22b..5c963950ac 100644 --- a/src/layout/floating.rs +++ b/src/layout/floating.rs @@ -739,6 +739,21 @@ impl FloatingSpace { self.interactive_resize_end(Some(&id)); } + fn should_skip_redundant_size_request(win: &W, win_size: Size) -> bool { + // Skip a same-size floating resize only when the concrete window size already matches and + // there is no other configure-worthy state change pending. That avoids redundant + // configures without suppressing the re-request path after a stale commit. + win_size.w > 0 + && win_size.h > 0 + && win.size() == win_size + && win.sizing_mode().is_normal() + && win.pending_sizing_mode().is_normal() + && matches!( + win.configure_intent(), + ConfigureIntent::NotNeeded | ConfigureIntent::Throttled + ) + } + pub fn set_window_width(&mut self, id: Option<&W::Id>, change: SizeChange, animate: bool) { let Some(id) = id.or(self.active_window_id.as_ref()) else { return; @@ -783,6 +798,9 @@ impl FloatingSpace { let win_height = ensure_min_max_size(win_height, min_size.h, max_size.h); let win_size = Size::from((win_width, win_height)); + if Self::should_skip_redundant_size_request(win, win_size) { + return; + } win.request_size_once(win_size, animate); } @@ -830,6 +848,9 @@ impl FloatingSpace { let win_width = ensure_min_max_size(win_width, min_size.w, max_size.w); let win_size = Size::from((win_width, win_height)); + if Self::should_skip_redundant_size_request(win, win_size) { + return; + } win.request_size_once(win_size, animate); } diff --git a/src/tests/floating.rs b/src/tests/floating.rs index 3ceedfd4f2..726d0c90ea 100644 --- a/src/tests/floating.rs +++ b/src/tests/floating.rs @@ -215,13 +215,9 @@ fn resize_to_same_size() { // This needn't request anything because we're already that size; the size in the current // server state matches the requested size. - // - // FIXME: However, currently it will request the size anyway because the code checks the - // current server state, and the last size niri requested of the window was 100×100 (even if - // the window already acked and committed in response). assert_snapshot!( f.client(id).window(&surface).format_recent_configures(), - @"size: 200 × 200, bounds: 1920 × 1080, states: [Activated]" + @"" ); } @@ -1357,10 +1353,8 @@ fn repeated_size_request() { f.double_roundtrip(id); // This should send a new configure since the window had committed. - // - // FIXME: doesn't request that currently. assert_snapshot!( f.client(id).window(&surface).format_recent_configures(), - @"" + @"size: 200 × 100, bounds: 1920 × 1080, states: [Activated]" ); } diff --git a/src/window/mapped.rs b/src/window/mapped.rs index e951e3324d..9334f9f85f 100644 --- a/src/window/mapped.rs +++ b/src/window/mapped.rs @@ -800,6 +800,13 @@ impl LayoutElement for Mapped { self.animate_next_configure = true; } + // If we requested a concrete size before and the client committed without applying it, + // role state may already contain that size even though the actual window size differs. + // In that case, force another configure on the next same-size request. + if !changed && size.w > 0 && size.h > 0 && self.window.geometry().size != size { + self.needs_configure = true; + } + self.request_size_once = Some(RequestSizeOnce::WaitingForConfigure); }