aboutsummaryrefslogtreecommitdiff
path: root/src/layout/monitor.rs
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2025-09-25 16:45:39 +0300
committerIvan Molodetskikh <yalterz@gmail.com>2025-10-02 09:33:08 +0300
commit8c3345807ace2c2b9afcec550277a822e3e3f701 (patch)
tree24c6d0dc0e8320fea1921f43b4b659911666707f /src/layout/monitor.rs
parentc353a7dae900382893cde03a84a85add24abfc45 (diff)
downloadniri-8c3345807ace2c2b9afcec550277a822e3e3f701.tar.gz
niri-8c3345807ace2c2b9afcec550277a822e3e3f701.tar.bz2
niri-8c3345807ace2c2b9afcec550277a822e3e3f701.zip
layout: Extract Monitor::verify_invariants()
Diffstat (limited to 'src/layout/monitor.rs')
-rw-r--r--src/layout/monitor.rs106
1 files changed, 106 insertions, 0 deletions
diff --git a/src/layout/monitor.rs b/src/layout/monitor.rs
index bcb6a5c3..21cbfcab 100644
--- a/src/layout/monitor.rs
+++ b/src/layout/monitor.rs
@@ -1881,4 +1881,110 @@ impl<W: LayoutElement> Monitor<W> {
pub fn working_area(&self) -> Rectangle<f64, Logical> {
self.working_area
}
+
+ #[cfg(test)]
+ pub(super) fn verify_invariants(&self) {
+ use approx::assert_abs_diff_eq;
+
+ assert!(
+ !self.workspaces.is_empty(),
+ "monitor must have at least one workspace"
+ );
+ assert!(self.active_workspace_idx < self.workspaces.len());
+
+ if let Some(WorkspaceSwitch::Animation(anim)) = &self.workspace_switch {
+ let before_idx = anim.from() as usize;
+ let after_idx = anim.to() as usize;
+
+ assert!(before_idx < self.workspaces.len());
+ assert!(after_idx < self.workspaces.len());
+ }
+
+ assert!(
+ !self.workspaces.last().unwrap().has_windows(),
+ "monitor must have an empty workspace in the end"
+ );
+ if self.options.layout.empty_workspace_above_first {
+ assert!(
+ !self.workspaces.first().unwrap().has_windows(),
+ "first workspace must be empty when empty_workspace_above_first is set"
+ )
+ }
+
+ assert!(
+ self.workspaces.last().unwrap().name.is_none(),
+ "monitor must have an unnamed workspace in the end"
+ );
+ if self.options.layout.empty_workspace_above_first {
+ assert!(
+ self.workspaces.first().unwrap().name.is_none(),
+ "first workspace must be unnamed when empty_workspace_above_first is set"
+ )
+ }
+
+ if self.options.layout.empty_workspace_above_first {
+ assert!(
+ self.workspaces.len() != 2,
+ "if empty_workspace_above_first is set there must be just 1 or 3+ workspaces"
+ )
+ }
+
+ // If there's no workspace switch in progress, there can't be any non-last non-active
+ // empty workspaces. If empty_workspace_above_first is set then the first workspace
+ // will be empty too.
+ let pre_skip = if self.options.layout.empty_workspace_above_first {
+ 1
+ } else {
+ 0
+ };
+ if self.workspace_switch.is_none() {
+ for (idx, ws) in self
+ .workspaces
+ .iter()
+ .enumerate()
+ .skip(pre_skip)
+ .rev()
+ // skip last
+ .skip(1)
+ {
+ if idx != self.active_workspace_idx {
+ assert!(
+ ws.has_windows_or_name(),
+ "non-active workspace can't be empty and unnamed except the last one"
+ );
+ }
+ }
+ }
+
+ for workspace in &self.workspaces {
+ assert_eq!(self.clock, workspace.clock);
+
+ assert_eq!(
+ self.scale().integer_scale(),
+ workspace.scale().integer_scale()
+ );
+ assert_eq!(
+ self.scale().fractional_scale(),
+ workspace.scale().fractional_scale()
+ );
+ assert_eq!(self.view_size, workspace.view_size());
+ assert_eq!(self.working_area, workspace.working_area());
+
+ assert_eq!(
+ workspace.base_options, self.options,
+ "workspace options must be synchronized with layout"
+ );
+ }
+
+ let scale = self.scale().fractional_scale();
+ let iter = self.workspaces_with_render_geo();
+ for (_ws, ws_geo) in iter {
+ let pos = ws_geo.loc;
+ let rounded_pos = pos.to_physical_precise_round(scale).to_logical(scale);
+
+ // Workspace positions must be rounded to physical pixels.
+ assert_abs_diff_eq!(pos.x, rounded_pos.x, epsilon = 1e-5);
+ assert_abs_diff_eq!(pos.y, rounded_pos.y, epsilon = 1e-5);
+ }
+ }
}