diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/layout/mod.rs | 3172 | ||||
| -rw-r--r-- | src/layout/tests.rs | 3163 |
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(¶ms.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::MoveColumnRightOrToMonitorRight(id) => { - let name = format!("output{id}"); - let Some(output) = layout.outputs().find(|o| o.name() == name).cloned() else { - return; - }; - - layout.move_column_right_or_to_output(&output); - } - Op::MoveWindowDown => layout.move_down(), - Op::MoveWindowUp => layout.move_up(), - Op::MoveWindowDownOrToWorkspaceDown => layout.move_down_or_to_workspace_down(), - Op::MoveWindowUpOrToWorkspaceUp => layout.move_up_or_to_workspace_up(), - Op::ConsumeOrExpelWindowLeft { id } => { - let id = id.filter(|id| layout.has_window(id)); - layout.consume_or_expel_window_left(id.as_ref()); - } - Op::ConsumeOrExpelWindowRight { id } => { - let id = id.filter(|id| layout.has_window(id)); - layout.consume_or_expel_window_right(id.as_ref()); - } - Op::ConsumeWindowIntoColumn => layout.consume_into_column(), - Op::ExpelWindowFromColumn => layout.expel_from_column(), - Op::SwapWindowInDirection(direction) => layout.swap_window_in_direction(direction), - Op::CenterColumn => layout.center_column(), - Op::CenterWindow { id } => { - let |
