aboutsummaryrefslogtreecommitdiff
path: root/src/layout
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2025-01-31 17:55:15 +0300
committerIvan Molodetskikh <yalterz@gmail.com>2025-01-31 17:56:43 +0300
commit49ddf66c2f77d6dab8bdb84de7345b9c3a28f9df (patch)
treef4eb339823bf84b1b70da4c7b51910045dbe6dba /src/layout
parenta169e0335d2773edd31a1959a3ff4fca994a422a (diff)
downloadniri-49ddf66c2f77d6dab8bdb84de7345b9c3a28f9df.tar.gz
niri-49ddf66c2f77d6dab8bdb84de7345b9c3a28f9df.tar.bz2
niri-49ddf66c2f77d6dab8bdb84de7345b9c3a28f9df.zip
layout: Move tests to separate file
This way changing just the tests won't rebuild the main library.
Diffstat (limited to 'src/layout')
-rw-r--r--src/layout/mod.rs3172
-rw-r--r--src/layout/tests.rs3163
2 files changed, 3166 insertions, 3169 deletions
diff --git a/src/layout/mod.rs b/src/layout/mod.rs
index 683592b2..1dd93eac 100644
--- a/src/layout/mod.rs
+++ b/src/layout/mod.rs
@@ -81,6 +81,9 @@ pub mod shadow;
pub mod tile;
pub mod workspace;
+#[cfg(test)]
+mod tests;
+
/// Size changes up to this many pixels don't animate.
pub const RESIZE_ANIMATION_THRESHOLD: f64 = 10.;
@@ -4311,3172 +4314,3 @@ impl<W: LayoutElement> Default for MonitorSet<W> {
Self::NoOutputs { workspaces: vec![] }
}
}
-
-#[cfg(test)]
-mod tests {
- use std::cell::Cell;
-
- use niri_config::{FloatOrInt, OutputName, WorkspaceName, WorkspaceReference};
- use proptest::prelude::*;
- use proptest_derive::Arbitrary;
- use smithay::output::{Mode, PhysicalProperties, Subpixel};
- use smithay::utils::Rectangle;
-
- use super::*;
-
- impl<W: LayoutElement> Default for Layout<W> {
- fn default() -> Self {
- Self::with_options(Clock::with_time(Duration::ZERO), Default::default())
- }
- }
-
- #[derive(Debug)]
- struct TestWindowInner {
- id: usize,
- parent_id: Cell<Option<usize>>,
- bbox: Cell<Rectangle<i32, Logical>>,
- initial_bbox: Rectangle<i32, Logical>,
- requested_size: Cell<Option<Size<i32, Logical>>>,
- min_size: Size<i32, Logical>,
- max_size: Size<i32, Logical>,
- pending_fullscreen: Cell<bool>,
- pending_activated: Cell<bool>,
- }
-
- #[derive(Debug, Clone)]
- struct TestWindow(Rc<TestWindowInner>);
-
- #[derive(Debug, Clone, Copy, Arbitrary)]
- struct TestWindowParams {
- #[proptest(strategy = "1..=5usize")]
- id: usize,
- #[proptest(strategy = "arbitrary_parent_id()")]
- parent_id: Option<usize>,
- is_floating: bool,
- #[proptest(strategy = "arbitrary_bbox()")]
- bbox: Rectangle<i32, Logical>,
- #[proptest(strategy = "arbitrary_min_max_size()")]
- min_max_size: (Size<i32, Logical>, Size<i32, Logical>),
- }
-
- impl TestWindowParams {
- pub fn new(id: usize) -> Self {
- Self {
- id,
- parent_id: None,
- is_floating: false,
- bbox: Rectangle::from_size(Size::from((100, 200))),
- min_max_size: Default::default(),
- }
- }
- }
-
- impl TestWindow {
- fn new(params: TestWindowParams) -> Self {
- Self(Rc::new(TestWindowInner {
- id: params.id,
- parent_id: Cell::new(params.parent_id),
- bbox: Cell::new(params.bbox),
- initial_bbox: params.bbox,
- requested_size: Cell::new(None),
- min_size: params.min_max_size.0,
- max_size: params.min_max_size.1,
- pending_fullscreen: Cell::new(false),
- pending_activated: Cell::new(false),
- }))
- }
-
- fn communicate(&self) -> bool {
- if let Some(size) = self.0.requested_size.get() {
- assert!(size.w >= 0);
- assert!(size.h >= 0);
-
- let mut new_bbox = self.0.initial_bbox;
- if size.w != 0 {
- new_bbox.size.w = size.w;
- }
- if size.h != 0 {
- new_bbox.size.h = size.h;
- }
-
- if self.0.bbox.get() != new_bbox {
- self.0.bbox.set(new_bbox);
- return true;
- }
- }
-
- false
- }
- }
-
- impl LayoutElement for TestWindow {
- type Id = usize;
-
- fn id(&self) -> &Self::Id {
- &self.0.id
- }
-
- fn size(&self) -> Size<i32, Logical> {
- self.0.bbox.get().size
- }
-
- fn buf_loc(&self) -> Point<i32, Logical> {
- (0, 0).into()
- }
-
- fn is_in_input_region(&self, _point: Point<f64, Logical>) -> bool {
- false
- }
-
- fn render<R: NiriRenderer>(
- &self,
- _renderer: &mut R,
- _location: Point<f64, Logical>,
- _scale: Scale<f64>,
- _alpha: f32,
- _target: RenderTarget,
- ) -> SplitElements<LayoutElementRenderElement<R>> {
- SplitElements::default()
- }
-
- fn request_size(
- &mut self,
- size: Size<i32, Logical>,
- _animate: bool,
- _transaction: Option<Transaction>,
- ) {
- self.0.requested_size.set(Some(size));
- self.0.pending_fullscreen.set(false);
- }
-
- fn request_fullscreen(&mut self, _size: Size<i32, Logical>) {
- self.0.pending_fullscreen.set(true);
- }
-
- fn min_size(&self) -> Size<i32, Logical> {
- self.0.min_size
- }
-
- fn max_size(&self) -> Size<i32, Logical> {
- self.0.max_size
- }
-
- fn is_wl_surface(&self, _wl_surface: &WlSurface) -> bool {
- false
- }
-
- fn set_preferred_scale_transform(&self, _scale: output::Scale, _transform: Transform) {}
-
- fn has_ssd(&self) -> bool {
- false
- }
-
- fn output_enter(&self, _output: &Output) {}
-
- fn output_leave(&self, _output: &Output) {}
-
- fn set_offscreen_element_id(&self, _id: Option<Id>) {}
-
- fn set_activated(&mut self, active: bool) {
- self.0.pending_activated.set(active);
- }
-
- fn set_bounds(&self, _bounds: Size<i32, Logical>) {}
-
- fn is_ignoring_opacity_window_rule(&self) -> bool {
- false
- }
-
- fn configure_intent(&self) -> ConfigureIntent {
- ConfigureIntent::CanSend
- }
-
- fn send_pending_configure(&mut self) {}
-
- fn set_active_in_column(&mut self, _active: bool) {}
-
- fn set_floating(&mut self, _floating: bool) {}
-
- fn is_fullscreen(&self) -> bool {
- false
- }
-
- fn is_pending_fullscreen(&self) -> bool {
- self.0.pending_fullscreen.get()
- }
-
- fn requested_size(&self) -> Option<Size<i32, Logical>> {
- self.0.requested_size.get()
- }
-
- fn is_child_of(&self, parent: &Self) -> bool {
- self.0.parent_id.get() == Some(parent.0.id)
- }
-
- fn refresh(&self) {}
-
- fn rules(&self) -> &ResolvedWindowRules {
- static EMPTY: ResolvedWindowRules = ResolvedWindowRules::empty();
- &EMPTY
- }
-
- fn animation_snapshot(&self) -> Option<&LayoutElementRenderSnapshot> {
- None
- }
-
- fn take_animation_snapshot(&mut self) -> Option<LayoutElementRenderSnapshot> {
- None
- }
-
- fn set_interactive_resize(&mut self, _data: Option<InteractiveResizeData>) {}
-
- fn cancel_interactive_resize(&mut self) {}
-
- fn on_commit(&mut self, _serial: Serial) {}
-
- fn interactive_resize_data(&self) -> Option<InteractiveResizeData> {
- None
- }
- }
-
- fn arbitrary_bbox() -> impl Strategy<Value = Rectangle<i32, Logical>> {
- any::<(i16, i16, u16, u16)>().prop_map(|(x, y, w, h)| {
- let loc: Point<i32, _> = Point::from((x.into(), y.into()));
- let size: Size<i32, _> = Size::from((w.max(1).into(), h.max(1).into()));
- Rectangle::new(loc, size)
- })
- }
-
- fn arbitrary_size_change() -> impl Strategy<Value = SizeChange> {
- prop_oneof![
- (0..).prop_map(SizeChange::SetFixed),
- (0f64..).prop_map(SizeChange::SetProportion),
- any::<i32>().prop_map(SizeChange::AdjustFixed),
- any::<f64>().prop_map(SizeChange::AdjustProportion),
- // Interactive resize can have negative values here.
- Just(SizeChange::SetFixed(-100)),
- ]
- }
-
- fn arbitrary_position_change() -> impl Strategy<Value = PositionChange> {
- prop_oneof![
- (-1000f64..1000f64).prop_map(PositionChange::SetFixed),
- (-1000f64..1000f64).prop_map(PositionChange::AdjustFixed),
- any::<f64>().prop_map(PositionChange::SetFixed),
- any::<f64>().prop_map(PositionChange::AdjustFixed),
- ]
- }
-
- fn arbitrary_min_max() -> impl Strategy<Value = (i32, i32)> {
- prop_oneof![
- Just((0, 0)),
- (1..65536).prop_map(|n| (n, n)),
- (1..65536).prop_map(|min| (min, 0)),
- (1..).prop_map(|max| (0, max)),
- (1..65536, 1..).prop_map(|(min, max): (i32, i32)| (min, max.max(min))),
- ]
- }
-
- fn arbitrary_min_max_size() -> impl Strategy<Value = (Size<i32, Logical>, Size<i32, Logical>)> {
- prop_oneof![
- 5 => (arbitrary_min_max(), arbitrary_min_max()).prop_map(
- |((min_w, max_w), (min_h, max_h))| {
- let min_size = Size::from((min_w, min_h));
- let max_size = Size::from((max_w, max_h));
- (min_size, max_size)
- },
- ),
- 1 => arbitrary_min_max().prop_map(|(w, h)| {
- let size = Size::from((w, h));
- (size, size)
- }),
- ]
- }
-
- fn arbitrary_view_offset_gesture_delta() -> impl Strategy<Value = f64> {
- prop_oneof![(-10f64..10f64), (-50000f64..50000f64),]
- }
-
- fn arbitrary_resize_edge() -> impl Strategy<Value = ResizeEdge> {
- prop_oneof![
- Just(ResizeEdge::RIGHT),
- Just(ResizeEdge::BOTTOM),
- Just(ResizeEdge::LEFT),
- Just(ResizeEdge::TOP),
- Just(ResizeEdge::BOTTOM_RIGHT),
- Just(ResizeEdge::BOTTOM_LEFT),
- Just(ResizeEdge::TOP_RIGHT),
- Just(ResizeEdge::TOP_LEFT),
- Just(ResizeEdge::empty()),
- ]
- }
-
- fn arbitrary_scale() -> impl Strategy<Value = f64> {
- prop_oneof![Just(1.), Just(1.5), Just(2.),]
- }
-
- fn arbitrary_msec_delta() -> impl Strategy<Value = i32> {
- prop_oneof![
- 1 => Just(-1000),
- 2 => Just(-10),
- 1 => Just(0),
- 2 => Just(10),
- 6 => Just(1000),
- ]
- }
-
- fn arbitrary_parent_id() -> impl Strategy<Value = Option<usize>> {
- prop_oneof![
- 5 => Just(None),
- 1 => prop::option::of(1..=5usize),
- ]
- }
-
- fn arbitrary_scroll_direction() -> impl Strategy<Value = ScrollDirection> {
- prop_oneof![Just(ScrollDirection::Left), Just(ScrollDirection::Right)]
- }
-
- #[derive(Debug, Clone, Copy, Arbitrary)]
- enum Op {
- AddOutput(#[proptest(strategy = "1..=5usize")] usize),
- AddScaledOutput {
- #[proptest(strategy = "1..=5usize")]
- id: usize,
- #[proptest(strategy = "arbitrary_scale()")]
- scale: f64,
- },
- RemoveOutput(#[proptest(strategy = "1..=5usize")] usize),
- FocusOutput(#[proptest(strategy = "1..=5usize")] usize),
- AddNamedWorkspace {
- #[proptest(strategy = "1..=5usize")]
- ws_name: usize,
- #[proptest(strategy = "prop::option::of(1..=5usize)")]
- output_name: Option<usize>,
- },
- UnnameWorkspace {
- #[proptest(strategy = "1..=5usize")]
- ws_name: usize,
- },
- AddWindow {
- params: TestWindowParams,
- },
- AddWindowNextTo {
- params: TestWindowParams,
- #[proptest(strategy = "1..=5usize")]
- next_to_id: usize,
- },
- AddWindowToNamedWorkspace {
- params: TestWindowParams,
- #[proptest(strategy = "1..=5usize")]
- ws_name: usize,
- },
- CloseWindow(#[proptest(strategy = "1..=5usize")] usize),
- FullscreenWindow(#[proptest(strategy = "1..=5usize")] usize),
- SetFullscreenWindow {
- #[proptest(strategy = "1..=5usize")]
- window: usize,
- is_fullscreen: bool,
- },
- FocusColumnLeft,
- FocusColumnRight,
- FocusColumnFirst,
- FocusColumnLast,
- FocusColumnRightOrFirst,
- FocusColumnLeftOrLast,
- FocusWindowOrMonitorUp(#[proptest(strategy = "1..=2u8")] u8),
- FocusWindowOrMonitorDown(#[proptest(strategy = "1..=2u8")] u8),
- FocusColumnOrMonitorLeft(#[proptest(strategy = "1..=2u8")] u8),
- FocusColumnOrMonitorRight(#[proptest(strategy = "1..=2u8")] u8),
- FocusWindowDown,
- FocusWindowUp,
- FocusWindowDownOrColumnLeft,
- FocusWindowDownOrColumnRight,
- FocusWindowUpOrColumnLeft,
- FocusWindowUpOrColumnRight,
- FocusWindowOrWorkspaceDown,
- FocusWindowOrWorkspaceUp,
- FocusWindow(#[proptest(strategy = "1..=5usize")] usize),
- MoveColumnLeft,
- MoveColumnRight,
- MoveColumnToFirst,
- MoveColumnToLast,
- MoveColumnLeftOrToMonitorLeft(#[proptest(strategy = "1..=2u8")] u8),
- MoveColumnRightOrToMonitorRight(#[proptest(strategy = "1..=2u8")] u8),
- MoveWindowDown,
- MoveWindowUp,
- MoveWindowDownOrToWorkspaceDown,
- MoveWindowUpOrToWorkspaceUp,
- ConsumeOrExpelWindowLeft {
- #[proptest(strategy = "proptest::option::of(1..=5usize)")]
- id: Option<usize>,
- },
- ConsumeOrExpelWindowRight {
- #[proptest(strategy = "proptest::option::of(1..=5usize)")]
- id: Option<usize>,
- },
- ConsumeWindowIntoColumn,
- ExpelWindowFromColumn,
- SwapWindowInDirection(
- #[proptest(strategy = "arbitrary_scroll_direction()")] ScrollDirection,
- ),
- CenterColumn,
- CenterWindow {
- #[proptest(strategy = "proptest::option::of(1..=5usize)")]
- id: Option<usize>,
- },
- FocusWorkspaceDown,
- FocusWorkspaceUp,
- FocusWorkspace(#[proptest(strategy = "0..=4usize")] usize),
- FocusWorkspaceAutoBackAndForth(#[proptest(strategy = "0..=4usize")] usize),
- FocusWorkspacePrevious,
- MoveWindowToWorkspaceDown,
- MoveWindowToWorkspaceUp,
- MoveWindowToWorkspace {
- #[proptest(strategy = "proptest::option::of(1..=5usize)")]
- window_id: Option<usize>,
- #[proptest(strategy = "0..=4usize")]
- workspace_idx: usize,
- },
- MoveColumnToWorkspaceDown,
- MoveColumnToWorkspaceUp,
- MoveColumnToWorkspace(#[proptest(strategy = "0..=4usize")] usize),
- MoveWorkspaceDown,
- MoveWorkspaceUp,
- MoveWorkspaceToIndex {
- #[proptest(strategy = "proptest::option::of(1..=5usize)")]
- ws_name: Option<usize>,
- #[proptest(strategy = "0..=4usize")]
- target_idx: usize,
- },
- MoveWorkspaceToMonitor {
- #[proptest(strategy = "proptest::option::of(1..=5usize)")]
- ws_name: Option<usize>,
- #[proptest(strategy = "0..=5usize")]
- output_id: usize,
- },
- SetWorkspaceName {
- #[proptest(strategy = "1..=5usize")]
- new_ws_name: usize,
- #[proptest(strategy = "proptest::option::of(1..=5usize)")]
- ws_name: Option<usize>,
- },
- UnsetWorkspaceName {
- #[proptest(strategy = "proptest::option::of(1..=5usize)")]
- ws_name: Option<usize>,
- },
- MoveWindowToOutput {
- #[proptest(strategy = "proptest::option::of(1..=5usize)")]
- window_id: Option<usize>,
- #[proptest(strategy = "1..=5usize")]
- output_id: usize,
- #[proptest(strategy = "proptest::option::of(0..=4usize)")]
- target_ws_idx: Option<usize>,
- },
- MoveColumnToOutput(#[proptest(strategy = "1..=5usize")] usize),
- SwitchPresetColumnWidth,
- SwitchPresetWindowWidth {
- #[proptest(strategy = "proptest::option::of(1..=5usize)")]
- id: Option<usize>,
- },
- SwitchPresetWindowHeight {
- #[proptest(strategy = "proptest::option::of(1..=5usize)")]
- id: Option<usize>,
- },
- MaximizeColumn,
- SetColumnWidth(#[proptest(strategy = "arbitrary_size_change()")] SizeChange),
- SetWindowWidth {
- #[proptest(strategy = "proptest::option::of(1..=5usize)")]
- id: Option<usize>,
- #[proptest(strategy = "arbitrary_size_change()")]
- change: SizeChange,
- },
- SetWindowHeight {
- #[proptest(strategy = "proptest::option::of(1..=5usize)")]
- id: Option<usize>,
- #[proptest(strategy = "arbitrary_size_change()")]
- change: SizeChange,
- },
- ResetWindowHeight {
- #[proptest(strategy = "proptest::option::of(1..=5usize)")]
- id: Option<usize>,
- },
- ToggleWindowFloating {
- #[proptest(strategy = "proptest::option::of(1..=5usize)")]
- id: Option<usize>,
- },
- SetWindowFloating {
- #[proptest(strategy = "proptest::option::of(1..=5usize)")]
- id: Option<usize>,
- floating: bool,
- },
- FocusFloating,
- FocusTiling,
- SwitchFocusFloatingTiling,
- MoveFloatingWindow {
- #[proptest(strategy = "proptest::option::of(1..=5usize)")]
- id: Option<usize>,
- #[proptest(strategy = "arbitrary_position_change()")]
- x: PositionChange,
- #[proptest(strategy = "arbitrary_position_change()")]
- y: PositionChange,
- animate: bool,
- },
- SetParent {
- #[proptest(strategy = "1..=5usize")]
- id: usize,
- #[proptest(strategy = "prop::option::of(1..=5usize)")]
- new_parent_id: Option<usize>,
- },
- Communicate(#[proptest(strategy = "1..=5usize")] usize),
- Refresh {
- is_active: bool,
- },
- AdvanceAnimations {
- #[proptest(strategy = "arbitrary_msec_delta()")]
- msec_delta: i32,
- },
- MoveWorkspaceToOutput(#[proptest(strategy = "1..=5usize")] usize),
- ViewOffsetGestureBegin {
- #[proptest(strategy = "1..=5usize")]
- output_idx: usize,
- is_touchpad: bool,
- },
- ViewOffsetGestureUpdate {
- #[proptest(strategy = "arbitrary_view_offset_gesture_delta()")]
- delta: f64,
- timestamp: Duration,
- is_touchpad: bool,
- },
- ViewOffsetGestureEnd {
- is_touchpad: Option<bool>,
- },
- WorkspaceSwitchGestureBegin {
- #[proptest(strategy = "1..=5usize")]
- output_idx: usize,
- is_touchpad: bool,
- },
- WorkspaceSwitchGestureUpdate {
- #[proptest(strategy = "-400f64..400f64")]
- delta: f64,
- timestamp: Duration,
- is_touchpad: bool,
- },
- WorkspaceSwitchGestureEnd {
- cancelled: bool,
- is_touchpad: Option<bool>,
- },
- InteractiveMoveBegin {
- #[proptest(strategy = "1..=5usize")]
- window: usize,
- #[proptest(strategy = "1..=5usize")]
- output_idx: usize,
- #[proptest(strategy = "-20000f64..20000f64")]
- px: f64,
- #[proptest(strategy = "-20000f64..20000f64")]
- py: f64,
- },
- InteractiveMoveUpdate {
- #[proptest(strategy = "1..=5usize")]
- window: usize,
- #[proptest(strategy = "-20000f64..20000f64")]
- dx: f64,
- #[proptest(strategy = "-20000f64..20000f64")]
- dy: f64,
- #[proptest(strategy = "1..=5usize")]
- output_idx: usize,
- #[proptest(strategy = "-20000f64..20000f64")]
- px: f64,
- #[proptest(strategy = "-20000f64..20000f64")]
- py: f64,
- },
- InteractiveMoveEnd {
- #[proptest(strategy = "1..=5usize")]
- window: usize,
- },
- InteractiveResizeBegin {
- #[proptest(strategy = "1..=5usize")]
- window: usize,
- #[proptest(strategy = "arbitrary_resize_edge()")]
- edges: ResizeEdge,
- },
- InteractiveResizeUpdate {
- #[proptest(strategy = "1..=5usize")]
- window: usize,
- #[proptest(strategy = "-20000f64..20000f64")]
- dx: f64,
- #[proptest(strategy = "-20000f64..20000f64")]
- dy: f64,
- },
- InteractiveResizeEnd {
- #[proptest(strategy = "1..=5usize")]
- window: usize,
- },
- }
-
- impl Op {
- fn apply(self, layout: &mut Layout<TestWindow>) {
- match self {
- Op::AddOutput(id) => {
- let name = format!("output{id}");
- if layout.outputs().any(|o| o.name() == name) {
- return;
- }
-
- let output = Output::new(
- name.clone(),
- PhysicalProperties {
- size: Size::from((1280, 720)),
- subpixel: Subpixel::Unknown,
- make: String::new(),
- model: String::new(),
- },
- );
- output.change_current_state(
- Some(Mode {
- size: Size::from((1280, 720)),
- refresh: 60000,
- }),
- None,
- None,
- None,
- );
- output.user_data().insert_if_missing(|| OutputName {
- connector: name,
- make: None,
- model: None,
- serial: None,
- });
- layout.add_output(output.clone());
- }
- Op::AddScaledOutput { id, scale } => {
- let name = format!("output{id}");
- if layout.outputs().any(|o| o.name() == name) {
- return;
- }
-
- let output = Output::new(
- name.clone(),
- PhysicalProperties {
- size: Size::from((1280, 720)),
- subpixel: Subpixel::Unknown,
- make: String::new(),
- model: String::new(),
- },
- );
- output.change_current_state(
- Some(Mode {
- size: Size::from((1280, 720)),
- refresh: 60000,
- }),
- None,
- Some(smithay::output::Scale::Fractional(scale)),
- None,
- );
- output.user_data().insert_if_missing(|| OutputName {
- connector: name,
- make: None,
- model: None,
- serial: None,
- });
- layout.add_output(output.clone());
- }
- Op::RemoveOutput(id) => {
- let name = format!("output{id}");
- let Some(output) = layout.outputs().find(|o| o.name() == name).cloned() else {
- return;
- };
-
- layout.remove_output(&output);
- }
- Op::FocusOutput(id) => {
- let name = format!("output{id}");
- let Some(output) = layout.outputs().find(|o| o.name() == name).cloned() else {
- return;
- };
-
- layout.focus_output(&output);
- }
- Op::AddNamedWorkspace {
- ws_name,
- output_name,
- } => {
- layout.ensure_named_workspace(&WorkspaceConfig {
- name: WorkspaceName(format!("ws{ws_name}")),
- open_on_output: output_name.map(|name| format!("output{name}")),
- });
- }
- Op::UnnameWorkspace { ws_name } => {
- layout.unname_workspace(&format!("ws{ws_name}"));
- }
- Op::SetWorkspaceName {
- new_ws_name,
- ws_name,
- } => {
- let ws_ref =
- ws_name.map(|ws_name| WorkspaceReference::Name(format!("ws{ws_name}")));
- layout.set_workspace_name(format!("ws{new_ws_name}"), ws_ref);
- }
- Op::UnsetWorkspaceName { ws_name } => {
- let ws_ref =
- ws_name.map(|ws_name| WorkspaceReference::Name(format!("ws{ws_name}")));
- layout.unset_workspace_name(ws_ref);
- }
- Op::AddWindow { mut params } => {
- if layout.has_window(&params.id) {
- return;
- }
- if let Some(parent_id) = params.parent_id {
- if parent_id_causes_loop(layout, params.id, parent_id) {
- params.parent_id = None;
- }
- }
-
- let win = TestWindow::new(params);
- layout.add_window(
- win,
- AddWindowTarget::Auto,
- None,
- None,
- false,
- params.is_floating,
- ActivateWindow::default(),
- );
- }
- Op::AddWindowNextTo {
- mut params,
- next_to_id,
- } => {
- let mut found_next_to = false;
-
- if let Some(InteractiveMoveState::Moving(move_)) = &layout.interactive_move {
- let win_id = move_.tile.window().0.id;
- if win_id == params.id {
- return;
- }
- if win_id == next_to_id {
- found_next_to = true;
- }
- }
-
- match &mut layout.monitor_set {
- MonitorSet::Normal { monitors, .. } => {
- for mon in monitors {
- for ws in &mut mon.workspaces {
- for win in ws.windows() {
- if win.0.id == params.id {
- return;
- }
-
- if win.0.id == next_to_id {
- found_next_to = true;
- }
- }
- }
- }
- }
- MonitorSet::NoOutputs { workspaces, .. } => {
- for ws in workspaces {
- for win in ws.windows() {
- if win.0.id == params.id {
- return;
- }
-
- if win.0.id == next_to_id {
- found_next_to = true;
- }
- }
- }
- }
- }
-
- if !found_next_to {
- return;
- }
-
- if let Some(parent_id) = params.parent_id {
- if parent_id_causes_loop(layout, params.id, parent_id) {
- params.parent_id = None;
- }
- }
-
- let win = TestWindow::new(params);
- layout.add_window(
- win,
- AddWindowTarget::NextTo(&next_to_id),
- None,
- None,
- false,
- params.is_floating,
- ActivateWindow::default(),
- );
- }
- Op::AddWindowToNamedWorkspace {
- mut params,
- ws_name,
- } => {
- let ws_name = format!("ws{ws_name}");
- let mut ws_id = None;
-
- if let Some(InteractiveMoveState::Moving(move_)) = &layout.interactive_move {
- if move_.tile.window().0.id == params.id {
- return;
- }
- }
-
- match &mut layout.monitor_set {
- MonitorSet::Normal { monitors, .. } => {
- for mon in monitors {
- for ws in &mut mon.workspaces {
- for win in ws.windows() {
- if win.0.id == params.id {
- return;
- }
- }
-
- if ws
- .name
- .as_ref()
- .is_some_and(|name| name.eq_ignore_ascii_case(&ws_name))
- {
- ws_id = Some(ws.id());
- }
- }
- }
- }
- MonitorSet::NoOutputs { workspaces, .. } => {
- for ws in workspaces {
- for win in ws.windows() {
- if win.0.id == params.id {
- return;
- }
- }
-
- if ws
- .name
- .as_ref()
- .is_some_and(|name| name.eq_ignore_ascii_case(&ws_name))
- {
- ws_id = Some(ws.id());
- }
- }
- }
- }
-
- let Some(ws_id) = ws_id else {
- return;
- };
-
- if let Some(parent_id) = params.parent_id {
- if parent_id_causes_loop(layout, params.id, parent_id) {
- params.parent_id = None;
- }
- }
-
- let win = TestWindow::new(params);
- layout.add_window(
- win,
- AddWindowTarget::Workspace(ws_id),
- None,
- None,
- false,
- params.is_floating,
- ActivateWindow::default(),
- );
- }
- Op::CloseWindow(id) => {
- layout.remove_window(&id, Transaction::new());
- }
- Op::FullscreenWindow(id) => {
- layout.toggle_fullscreen(&id);
- }
- Op::SetFullscreenWindow {
- window,
- is_fullscreen,
- } => {
- layout.set_fullscreen(&window, is_fullscreen);
- }
- Op::FocusColumnLeft => layout.focus_left(),
- Op::FocusColumnRight => layout.focus_right(),
- Op::FocusColumnFirst => layout.focus_column_first(),
- Op::FocusColumnLast => layout.focus_column_last(),
- Op::FocusColumnRightOrFirst => layout.focus_column_right_or_first(),
- Op::FocusColumnLeftOrLast => layout.focus_column_left_or_last(),
- Op::FocusWindowOrMonitorUp(id) => {
- let name = format!("output{id}");
- let Some(output) = layout.outputs().find(|o| o.name() == name).cloned() else {
- return;
- };
-
- layout.focus_window_up_or_output(&output);
- }
- Op::FocusWindowOrMonitorDown(id) => {
- let name = format!("output{id}");
- let Some(output) = layout.outputs().find(|o| o.name() == name).cloned() else {
- return;
- };
-
- layout.focus_window_down_or_output(&output);
- }
- Op::FocusColumnOrMonitorLeft(id) => {
- let name = format!("output{id}");
- let Some(output) = layout.outputs().find(|o| o.name() == name).cloned() else {
- return;
- };
-
- layout.focus_column_left_or_output(&output);
- }
- Op::FocusColumnOrMonitorRight(id) => {
- let name = format!("output{id}");
- let Some(output) = layout.outputs().find(|o| o.name() == name).cloned() else {
- return;
- };
-
- layout.focus_column_right_or_output(&output);
- }
- Op::FocusWindowDown => layout.focus_down(),
- Op::FocusWindowUp => layout.focus_up(),
- Op::FocusWindowDownOrColumnLeft => layout.focus_down_or_left(),
- Op::FocusWindowDownOrColumnRight => layout.focus_down_or_right(),
- Op::FocusWindowUpOrColumnLeft => layout.focus_up_or_left(),
- Op::FocusWindowUpOrColumnRight => layout.focus_up_or_right(),
- Op::FocusWindowOrWorkspaceDown => layout.focus_window_or_workspace_down(),
- Op::FocusWindowOrWorkspaceUp => layout.focus_window_or_workspace_up(),
- Op::FocusWindow(id) => layout.activate_window(&id),
- Op::MoveColumnLeft => layout.move_left(),
- Op::MoveColumnRight => layout.move_right(),
- Op::MoveColumnToFirst => layout.move_column_to_first(),
- Op::MoveColumnToLast => layout.move_column_to_last(),
- Op::MoveColumnLeftOrToMonitorLeft(id) => {
- let name = format!("output{id}");
- let Some(output) = layout.outputs().find(|o| o.name() == name).cloned() else {
- return;
- };
-
- layout.move_column_left_or_to_output(&output);
- }
- Op: