From 0920ea9f9fdf0b744e79e8dea57d5945ba74f312 Mon Sep 17 00:00:00 2001 From: Ivan Molodetskikh Date: Mon, 24 Nov 2025 15:10:14 +0300 Subject: layout: Round focus ring/border width to physical at the right place Before this, focus ring/border width was incorrectly rounded only for layout config, which does not take into account window rules overrides. This means that setting width in window rules prevented correct rounding altogether. Tests didn't check this because window rules weren't tested. This commit also adds basic window rules random generation, making the tests catch this problem too. --- src/layout/mod.rs | 7 +------ src/layout/tests.rs | 32 ++++++++++++++++++++++++++------ src/layout/tile.rs | 21 ++++++++++++++++----- src/window/mod.rs | 2 +- 4 files changed, 44 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 9fd99a32..f0fb7704 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -618,12 +618,7 @@ impl Options { } fn adjusted_for_scale(mut self, scale: f64) -> Self { - let round = |logical: f64| round_logical_in_physical_max1(scale, logical); - - self.layout.gaps = round(self.layout.gaps); - self.layout.focus_ring.width = round(self.layout.focus_ring.width); - self.layout.border.width = round(self.layout.border.width); - + self.layout.gaps = round_logical_in_physical_max1(scale, self.layout.gaps); self } } diff --git a/src/layout/tests.rs b/src/layout/tests.rs index 17a8a30e..e022475a 100644 --- a/src/layout/tests.rs +++ b/src/layout/tests.rs @@ -40,12 +40,13 @@ struct TestWindowInner { is_pending_windowed_fullscreen: Cell, animate_next_configure: Cell, animation_snapshot: RefCell>, + rules: ResolvedWindowRules, } #[derive(Debug, Clone)] struct TestWindow(Rc); -#[derive(Debug, Clone, Copy, Arbitrary)] +#[derive(Debug, Clone, Arbitrary)] struct TestWindowParams { #[proptest(strategy = "1..=5usize")] id: usize, @@ -56,6 +57,8 @@ struct TestWindowParams { bbox: Rectangle, #[proptest(strategy = "arbitrary_min_max_size()")] min_max_size: (Size, Size), + #[proptest(strategy = "prop::option::of(arbitrary_rules())")] + rules: Option, } impl TestWindowParams { @@ -66,6 +69,7 @@ impl TestWindowParams { is_floating: false, bbox: Rectangle::from_size(Size::from((100, 200))), min_max_size: Default::default(), + rules: None, } } } @@ -88,6 +92,7 @@ impl TestWindow { is_pending_windowed_fullscreen: Cell::new(false), animate_next_configure: Cell::new(false), animation_snapshot: RefCell::new(None), + rules: params.rules.unwrap_or(ResolvedWindowRules::empty()), })) } @@ -262,8 +267,7 @@ impl LayoutElement for TestWindow { fn refresh(&self) {} fn rules(&self) -> &ResolvedWindowRules { - static EMPTY: ResolvedWindowRules = ResolvedWindowRules::empty(); - &EMPTY + &self.0.rules } fn take_animation_snapshot(&mut self) -> Option { @@ -345,6 +349,19 @@ fn arbitrary_min_max_size() -> impl Strategy, Size ResolvedWindowRules { + ResolvedWindowRules { + focus_ring, + border, + ..ResolvedWindowRules::empty() + } + } +} + fn arbitrary_view_offset_gesture_delta() -> impl Strategy { prop_oneof![(-10f64..10f64), (-50000f64..50000f64),] } @@ -891,6 +908,7 @@ impl Op { } } + let is_floating = params.is_floating; let win = TestWindow::new(params); layout.add_window( win, @@ -898,7 +916,7 @@ impl Op { None, None, false, - params.is_floating, + is_floating, ActivateWindow::default(), ); } @@ -959,6 +977,7 @@ impl Op { } } + let is_floating = params.is_floating; let win = TestWindow::new(params); layout.add_window( win, @@ -966,7 +985,7 @@ impl Op { None, None, false, - params.is_floating, + is_floating, ActivateWindow::default(), ); } @@ -1032,6 +1051,7 @@ impl Op { } } + let is_floating = params.is_floating; let win = TestWindow::new(params); layout.add_window( win, @@ -1039,7 +1059,7 @@ impl Op { None, None, false, - params.is_floating, + is_floating, ActivateWindow::default(), ); } diff --git a/src/layout/tile.rs b/src/layout/tile.rs index bc39db6d..beaa981f 100644 --- a/src/layout/tile.rs +++ b/src/layout/tile.rs @@ -29,7 +29,9 @@ use crate::render_helpers::snapshot::RenderSnapshot; use crate::render_helpers::solid_color::{SolidColorBuffer, SolidColorRenderElement}; use crate::render_helpers::RenderTarget; use crate::utils::transaction::Transaction; -use crate::utils::{baba_is_float_offset, round_logical_in_physical}; +use crate::utils::{ + baba_is_float_offset, round_logical_in_physical, round_logical_in_physical_max1, +}; /// Toplevel window with decorations. #[derive(Debug)] @@ -228,16 +230,20 @@ impl Tile { self.scale = scale; self.options = options; + let round_max1 = |logical| round_logical_in_physical_max1(self.scale, logical); + let rules = self.window.rules(); - let border_config = self.options.layout.border.merged_with(&rules.border); + let mut border_config = self.options.layout.border.merged_with(&rules.border); + border_config.width = round_max1(border_config.width); self.border.update_config(border_config.into()); - let focus_ring_config = self + let mut focus_ring_config = self .options .layout .focus_ring .merged_with(&rules.focus_ring); + focus_ring_config.width = round_max1(focus_ring_config.width); self.focus_ring.update_config(focus_ring_config); let shadow_config = self.options.layout.shadow.merged_with(&rules.shadow); @@ -373,14 +379,19 @@ impl Tile { } } + let round_max1 = |logical| round_logical_in_physical_max1(self.scale, logical); + let rules = self.window.rules(); - let border_config = self.options.layout.border.merged_with(&rules.border); + let mut border_config = self.options.layout.border.merged_with(&rules.border); + border_config.width = round_max1(border_config.width); self.border.update_config(border_config.into()); - let focus_ring_config = self + + let mut focus_ring_config = self .options .layout .focus_ring .merged_with(&rules.focus_ring); + focus_ring_config.width = round_max1(focus_ring_config.width); self.focus_ring.update_config(focus_ring_config); let shadow_config = self.options.layout.shadow.merged_with(&rules.shadow); diff --git a/src/window/mod.rs b/src/window/mod.rs index a329edd7..89669fe1 100644 --- a/src/window/mod.rs +++ b/src/window/mod.rs @@ -30,7 +30,7 @@ pub enum WindowRef<'a> { } /// Rules fully resolved for a window. -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Clone)] pub struct ResolvedWindowRules { /// Default width for this window. /// -- cgit