diff --git a/src/input/mod.rs b/src/input/mod.rs index 8427827f..733fb479 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -308,7 +308,7 @@ impl State { ) .flatten() { - self.handle_action(action, seat, serial, time, mods) + self.handle_action(action, seat, serial, time, mods, None) } break; } @@ -660,6 +660,7 @@ impl State { serial: Serial, time: u32, mods: KeyModifiers, + direction: Option, ) { match action { Action::Terminate => { @@ -716,7 +717,7 @@ impl State { .activate(¤t_output, workspace) .is_err() { - self.handle_action(Action::NextOutput, seat, serial, time, mods); + self.handle_action(Action::NextOutput, seat, serial, time, mods, direction); } } Action::PreviousWorkspace => { @@ -734,7 +735,7 @@ impl State { .activate(¤t_output, workspace) .is_err() { - self.handle_action(Action::PreviousOutput, seat, serial, time, mods); + self.handle_action(Action::PreviousOutput, seat, serial, time, mods, direction); } } Action::LastWorkspace => { @@ -761,6 +762,7 @@ impl State { ¤t_output, (¤t_output, Some(workspace as usize)), follow, + None, ); } x @ Action::MoveToNextWorkspace | x @ Action::SendToNextWorkspace => { @@ -778,6 +780,7 @@ impl State { ¤t_output, (¤t_output, Some(workspace as usize)), matches!(x, Action::MoveToNextWorkspace), + direction, ) .is_err() { @@ -791,6 +794,7 @@ impl State { serial, time, mods, + direction, ) } } @@ -810,6 +814,7 @@ impl State { ¤t_output, (¤t_output, Some(workspace as usize)), matches!(x, Action::MoveToPreviousWorkspace), + direction, ) .is_err() { @@ -823,6 +828,7 @@ impl State { serial, time, mods, + direction, ) } } @@ -840,6 +846,7 @@ impl State { ¤t_output, (¤t_output, Some(workspace as usize)), matches!(x, Action::MoveToLastWorkspace), + None, ); } Action::NextOutput => { @@ -919,6 +926,7 @@ impl State { ¤t_output, (&next_output, None), matches!(x, Action::MoveToNextOutput), + direction, ) { if let Some(ptr) = seat.get_pointer() { ptr.motion( @@ -953,6 +961,7 @@ impl State { ¤t_output, (&prev_output, None), matches!(x, Action::MoveToPreviousOutput), + direction, ) { if let Some(ptr) = seat.get_pointer() { ptr.motion( @@ -984,19 +993,44 @@ impl State { match (focus, self.common.config.static_conf.workspace_layout) { (FocusDirection::Left, WorkspaceLayout::Horizontal) | (FocusDirection::Up, WorkspaceLayout::Vertical) => self - .handle_action(Action::PreviousWorkspace, seat, serial, time, mods), + .handle_action( + Action::PreviousWorkspace, + seat, + serial, + time, + mods, + direction, + ), (FocusDirection::Right, WorkspaceLayout::Horizontal) - | (FocusDirection::Down, WorkspaceLayout::Vertical) => { - self.handle_action(Action::NextWorkspace, seat, serial, time, mods) - } + | (FocusDirection::Down, WorkspaceLayout::Vertical) => self + .handle_action( + Action::NextWorkspace, + seat, + serial, + time, + mods, + direction, + ), (FocusDirection::Left, WorkspaceLayout::Vertical) - | (FocusDirection::Up, WorkspaceLayout::Horizontal) => { - self.handle_action(Action::PreviousOutput, seat, serial, time, mods) - } + | (FocusDirection::Up, WorkspaceLayout::Horizontal) => self + .handle_action( + Action::PreviousOutput, + seat, + serial, + time, + mods, + direction, + ), (FocusDirection::Right, WorkspaceLayout::Vertical) - | (FocusDirection::Down, WorkspaceLayout::Horizontal) => { - self.handle_action(Action::NextOutput, seat, serial, time, mods) - } + | (FocusDirection::Down, WorkspaceLayout::Horizontal) => self + .handle_action( + Action::NextOutput, + seat, + serial, + time, + mods, + direction, + ), _ => {} } } @@ -1026,6 +1060,7 @@ impl State { serial, time, mods, + Some(direction), ), (Direction::Right, WorkspaceLayout::Horizontal) | (Direction::Down, WorkspaceLayout::Vertical) => self.handle_action( @@ -1034,6 +1069,7 @@ impl State { serial, time, mods, + Some(direction), ), (Direction::Left, WorkspaceLayout::Vertical) | (Direction::Up, WorkspaceLayout::Horizontal) => self.handle_action( @@ -1042,11 +1078,17 @@ impl State { serial, time, mods, + Some(direction), ), (Direction::Right, WorkspaceLayout::Vertical) - | (Direction::Down, WorkspaceLayout::Horizontal) => { - self.handle_action(Action::MoveToNextOutput, seat, serial, time, mods) - } + | (Direction::Down, WorkspaceLayout::Horizontal) => self.handle_action( + Action::MoveToNextOutput, + seat, + serial, + time, + mods, + Some(direction), + ), } } else { let focus_stack = workspace.focus_stack.get(seat); diff --git a/src/shell/layout/tiling/mod.rs b/src/shell/layout/tiling/mod.rs index 127ccfd7..5fcb7683 100644 --- a/src/shell/layout/tiling/mod.rs +++ b/src/shell/layout/tiling/mod.rs @@ -374,11 +374,12 @@ impl TilingLayout { window: CosmicMapped, seat: &Seat, focus_stack: impl Iterator + 'a, + direction: Option, ) { let output = seat.active_output(); window.output_enter(&output, window.bbox()); window.set_bounds(output.geometry().size); - self.map_internal(window, &output, Some(focus_stack)); + self.map_internal(window, &output, Some(focus_stack), direction); } fn map_internal<'a>( @@ -386,6 +387,7 @@ impl TilingLayout { window: impl Into, output: &Output, focus_stack: Option + 'a>, + direction: Option, ) { let queue = self.queues.get_mut(output).expect("Output not mapped?"); let mut tree = queue.trees.back().unwrap().0.copy_clone(); @@ -396,37 +398,60 @@ impl TilingLayout { last_geometry: Rectangle::from_loc_and_size((0, 0), (100, 100)), }); - let last_active = focus_stack - .and_then(|focus_stack| TilingLayout::last_active_window(&mut tree, focus_stack)); - - let window_id = if let Some((_last_active_window, ref node_id)) = last_active { - let orientation = { - let window_size = tree.get(node_id).unwrap().data().geometry().size; - if window_size.w > window_size.h { - Orientation::Vertical - } else { - Orientation::Horizontal - } - }; - let new_id = tree.insert(new_window, InsertBehavior::AsRoot).unwrap(); - TilingLayout::new_group(&mut tree, &node_id, &new_id, orientation).unwrap(); - new_id - } else { - // nothing? then we add to the root + let window_id = if let Some(direction) = direction { if let Some(root_id) = tree.root_node_id().cloned() { + let orientation = match direction { + Direction::Left | Direction::Right => Orientation::Vertical, + Direction::Up | Direction::Down => Orientation::Horizontal, + }; + + let new_id = tree.insert(new_window, InsertBehavior::AsRoot).unwrap(); + TilingLayout::new_group(&mut tree, &root_id, &new_id, orientation).unwrap(); + tree.make_nth_sibling( + &new_id, + match direction { + Direction::Left | Direction::Up => 1, + Direction::Right | Direction::Down => 0, + }, + ) + .unwrap(); + new_id + } else { + tree.insert(new_window, InsertBehavior::AsRoot).unwrap() + } + } else { + let last_active = focus_stack + .and_then(|focus_stack| TilingLayout::last_active_window(&mut tree, focus_stack)); + + if let Some((_last_active_window, ref node_id)) = last_active { let orientation = { - let output_size = output.geometry().size; - if output_size.w > output_size.h { + let window_size = tree.get(node_id).unwrap().data().geometry().size; + if window_size.w > window_size.h { Orientation::Vertical } else { Orientation::Horizontal } }; let new_id = tree.insert(new_window, InsertBehavior::AsRoot).unwrap(); - TilingLayout::new_group(&mut tree, &root_id, &new_id, orientation).unwrap(); + TilingLayout::new_group(&mut tree, &node_id, &new_id, orientation).unwrap(); new_id } else { - tree.insert(new_window, InsertBehavior::AsRoot).unwrap() + // nothing? then we add to the root + if let Some(root_id) = tree.root_node_id().cloned() { + let orientation = { + let output_size = output.geometry().size; + if output_size.w > output_size.h { + Orientation::Vertical + } else { + Orientation::Horizontal + } + }; + let new_id = tree.insert(new_window, InsertBehavior::AsRoot).unwrap(); + TilingLayout::new_group(&mut tree, &root_id, &new_id, orientation).unwrap(); + new_id + } else { + tree.insert(new_window, InsertBehavior::AsRoot).unwrap() + } } }; diff --git a/src/shell/mod.rs b/src/shell/mod.rs index bc24d642..f08e9081 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -54,7 +54,7 @@ use self::{ grabs::ResizeEdge, layout::{ floating::FloatingLayout, - tiling::{TilingLayout, ANIMATION_DURATION}, + tiling::{Direction, TilingLayout, ANIMATION_DURATION}, }, }; @@ -1204,7 +1204,7 @@ impl Shell { let focus_stack = workspace.focus_stack.get(&seat); workspace .tiling_layer - .map(mapped.clone(), &seat, focus_stack.iter()); + .map(mapped.clone(), &seat, focus_stack.iter(), None); } if let CosmicSurface::X11(_) = window { @@ -1275,6 +1275,7 @@ impl Shell { from_output: &Output, to: (&Output, Option), follow: bool, + direction: Option, ) -> Result>, InvalidWorkspaceIndex> { let (to_output, to_idx) = to; let to_idx = to_idx.unwrap_or(state.common.shell.workspaces.active_num(to_output).1); @@ -1338,7 +1339,7 @@ impl Shell { } else { to_workspace .tiling_layer - .map(mapped.clone(), &seat, focus_stack.iter()); + .map(mapped.clone(), &seat, focus_stack.iter(), direction); } for (toplevel, _) in mapped.windows() { if from_output != to_output { diff --git a/src/shell/workspace.rs b/src/shell/workspace.rs index 832f7b6f..2ee47c93 100644 --- a/src/shell/workspace.rs +++ b/src/shell/workspace.rs @@ -402,7 +402,8 @@ impl Workspace { .into_iter() { self.floating_layer.unmap(&window); - self.tiling_layer.map(window, seat, focus_stack.iter()) + self.tiling_layer + .map(window, seat, focus_stack.iter(), None) } self.tiling_enabled = true; } @@ -417,7 +418,8 @@ impl Workspace { } else if self.floating_layer.mapped().any(|w| w == &window) { let focus_stack = self.focus_stack.get(seat); self.floating_layer.unmap(&window); - self.tiling_layer.map(window, seat, focus_stack.iter()) + self.tiling_layer + .map(window, seat, focus_stack.iter(), None) } } }