tiling: Consider direction when moving across workspaces and outputs

Fixes second case of #113.
This commit is contained in:
Victoria Brekenfeld 2023-05-25 17:51:53 +02:00
parent bf0eb97bea
commit 2f6d4da712
4 changed files with 113 additions and 43 deletions

View file

@ -308,7 +308,7 @@ impl State {
) )
.flatten() .flatten()
{ {
self.handle_action(action, seat, serial, time, mods) self.handle_action(action, seat, serial, time, mods, None)
} }
break; break;
} }
@ -660,6 +660,7 @@ impl State {
serial: Serial, serial: Serial,
time: u32, time: u32,
mods: KeyModifiers, mods: KeyModifiers,
direction: Option<Direction>,
) { ) {
match action { match action {
Action::Terminate => { Action::Terminate => {
@ -716,7 +717,7 @@ impl State {
.activate(&current_output, workspace) .activate(&current_output, workspace)
.is_err() .is_err()
{ {
self.handle_action(Action::NextOutput, seat, serial, time, mods); self.handle_action(Action::NextOutput, seat, serial, time, mods, direction);
} }
} }
Action::PreviousWorkspace => { Action::PreviousWorkspace => {
@ -734,7 +735,7 @@ impl State {
.activate(&current_output, workspace) .activate(&current_output, workspace)
.is_err() .is_err()
{ {
self.handle_action(Action::PreviousOutput, seat, serial, time, mods); self.handle_action(Action::PreviousOutput, seat, serial, time, mods, direction);
} }
} }
Action::LastWorkspace => { Action::LastWorkspace => {
@ -761,6 +762,7 @@ impl State {
&current_output, &current_output,
(&current_output, Some(workspace as usize)), (&current_output, Some(workspace as usize)),
follow, follow,
None,
); );
} }
x @ Action::MoveToNextWorkspace | x @ Action::SendToNextWorkspace => { x @ Action::MoveToNextWorkspace | x @ Action::SendToNextWorkspace => {
@ -778,6 +780,7 @@ impl State {
&current_output, &current_output,
(&current_output, Some(workspace as usize)), (&current_output, Some(workspace as usize)),
matches!(x, Action::MoveToNextWorkspace), matches!(x, Action::MoveToNextWorkspace),
direction,
) )
.is_err() .is_err()
{ {
@ -791,6 +794,7 @@ impl State {
serial, serial,
time, time,
mods, mods,
direction,
) )
} }
} }
@ -810,6 +814,7 @@ impl State {
&current_output, &current_output,
(&current_output, Some(workspace as usize)), (&current_output, Some(workspace as usize)),
matches!(x, Action::MoveToPreviousWorkspace), matches!(x, Action::MoveToPreviousWorkspace),
direction,
) )
.is_err() .is_err()
{ {
@ -823,6 +828,7 @@ impl State {
serial, serial,
time, time,
mods, mods,
direction,
) )
} }
} }
@ -840,6 +846,7 @@ impl State {
&current_output, &current_output,
(&current_output, Some(workspace as usize)), (&current_output, Some(workspace as usize)),
matches!(x, Action::MoveToLastWorkspace), matches!(x, Action::MoveToLastWorkspace),
None,
); );
} }
Action::NextOutput => { Action::NextOutput => {
@ -919,6 +926,7 @@ impl State {
&current_output, &current_output,
(&next_output, None), (&next_output, None),
matches!(x, Action::MoveToNextOutput), matches!(x, Action::MoveToNextOutput),
direction,
) { ) {
if let Some(ptr) = seat.get_pointer() { if let Some(ptr) = seat.get_pointer() {
ptr.motion( ptr.motion(
@ -953,6 +961,7 @@ impl State {
&current_output, &current_output,
(&prev_output, None), (&prev_output, None),
matches!(x, Action::MoveToPreviousOutput), matches!(x, Action::MoveToPreviousOutput),
direction,
) { ) {
if let Some(ptr) = seat.get_pointer() { if let Some(ptr) = seat.get_pointer() {
ptr.motion( ptr.motion(
@ -984,19 +993,44 @@ impl State {
match (focus, self.common.config.static_conf.workspace_layout) { match (focus, self.common.config.static_conf.workspace_layout) {
(FocusDirection::Left, WorkspaceLayout::Horizontal) (FocusDirection::Left, WorkspaceLayout::Horizontal)
| (FocusDirection::Up, WorkspaceLayout::Vertical) => self | (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::Right, WorkspaceLayout::Horizontal)
| (FocusDirection::Down, WorkspaceLayout::Vertical) => { | (FocusDirection::Down, WorkspaceLayout::Vertical) => self
self.handle_action(Action::NextWorkspace, seat, serial, time, mods) .handle_action(
} Action::NextWorkspace,
seat,
serial,
time,
mods,
direction,
),
(FocusDirection::Left, WorkspaceLayout::Vertical) (FocusDirection::Left, WorkspaceLayout::Vertical)
| (FocusDirection::Up, WorkspaceLayout::Horizontal) => { | (FocusDirection::Up, WorkspaceLayout::Horizontal) => self
self.handle_action(Action::PreviousOutput, seat, serial, time, mods) .handle_action(
} Action::PreviousOutput,
seat,
serial,
time,
mods,
direction,
),
(FocusDirection::Right, WorkspaceLayout::Vertical) (FocusDirection::Right, WorkspaceLayout::Vertical)
| (FocusDirection::Down, WorkspaceLayout::Horizontal) => { | (FocusDirection::Down, WorkspaceLayout::Horizontal) => self
self.handle_action(Action::NextOutput, seat, serial, time, mods) .handle_action(
} Action::NextOutput,
seat,
serial,
time,
mods,
direction,
),
_ => {} _ => {}
} }
} }
@ -1026,6 +1060,7 @@ impl State {
serial, serial,
time, time,
mods, mods,
Some(direction),
), ),
(Direction::Right, WorkspaceLayout::Horizontal) (Direction::Right, WorkspaceLayout::Horizontal)
| (Direction::Down, WorkspaceLayout::Vertical) => self.handle_action( | (Direction::Down, WorkspaceLayout::Vertical) => self.handle_action(
@ -1034,6 +1069,7 @@ impl State {
serial, serial,
time, time,
mods, mods,
Some(direction),
), ),
(Direction::Left, WorkspaceLayout::Vertical) (Direction::Left, WorkspaceLayout::Vertical)
| (Direction::Up, WorkspaceLayout::Horizontal) => self.handle_action( | (Direction::Up, WorkspaceLayout::Horizontal) => self.handle_action(
@ -1042,11 +1078,17 @@ impl State {
serial, serial,
time, time,
mods, mods,
Some(direction),
), ),
(Direction::Right, WorkspaceLayout::Vertical) (Direction::Right, WorkspaceLayout::Vertical)
| (Direction::Down, WorkspaceLayout::Horizontal) => { | (Direction::Down, WorkspaceLayout::Horizontal) => self.handle_action(
self.handle_action(Action::MoveToNextOutput, seat, serial, time, mods) Action::MoveToNextOutput,
} seat,
serial,
time,
mods,
Some(direction),
),
} }
} else { } else {
let focus_stack = workspace.focus_stack.get(seat); let focus_stack = workspace.focus_stack.get(seat);

View file

@ -374,11 +374,12 @@ impl TilingLayout {
window: CosmicMapped, window: CosmicMapped,
seat: &Seat<State>, seat: &Seat<State>,
focus_stack: impl Iterator<Item = &'a CosmicMapped> + 'a, focus_stack: impl Iterator<Item = &'a CosmicMapped> + 'a,
direction: Option<Direction>,
) { ) {
let output = seat.active_output(); let output = seat.active_output();
window.output_enter(&output, window.bbox()); window.output_enter(&output, window.bbox());
window.set_bounds(output.geometry().size); 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>( fn map_internal<'a>(
@ -386,6 +387,7 @@ impl TilingLayout {
window: impl Into<CosmicMapped>, window: impl Into<CosmicMapped>,
output: &Output, output: &Output,
focus_stack: Option<impl Iterator<Item = &'a CosmicMapped> + 'a>, focus_stack: Option<impl Iterator<Item = &'a CosmicMapped> + 'a>,
direction: Option<Direction>,
) { ) {
let queue = self.queues.get_mut(output).expect("Output not mapped?"); let queue = self.queues.get_mut(output).expect("Output not mapped?");
let mut tree = queue.trees.back().unwrap().0.copy_clone(); 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)), last_geometry: Rectangle::from_loc_and_size((0, 0), (100, 100)),
}); });
let last_active = focus_stack let window_id = if let Some(direction) = direction {
.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
if let Some(root_id) = tree.root_node_id().cloned() { 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 orientation = {
let output_size = output.geometry().size; let window_size = tree.get(node_id).unwrap().data().geometry().size;
if output_size.w > output_size.h { if window_size.w > window_size.h {
Orientation::Vertical Orientation::Vertical
} else { } else {
Orientation::Horizontal Orientation::Horizontal
} }
}; };
let new_id = tree.insert(new_window, InsertBehavior::AsRoot).unwrap(); 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 new_id
} else { } 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()
}
} }
}; };

View file

@ -54,7 +54,7 @@ use self::{
grabs::ResizeEdge, grabs::ResizeEdge,
layout::{ layout::{
floating::FloatingLayout, 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); let focus_stack = workspace.focus_stack.get(&seat);
workspace workspace
.tiling_layer .tiling_layer
.map(mapped.clone(), &seat, focus_stack.iter()); .map(mapped.clone(), &seat, focus_stack.iter(), None);
} }
if let CosmicSurface::X11(_) = window { if let CosmicSurface::X11(_) = window {
@ -1275,6 +1275,7 @@ impl Shell {
from_output: &Output, from_output: &Output,
to: (&Output, Option<usize>), to: (&Output, Option<usize>),
follow: bool, follow: bool,
direction: Option<Direction>,
) -> Result<Option<Point<i32, Logical>>, InvalidWorkspaceIndex> { ) -> Result<Option<Point<i32, Logical>>, InvalidWorkspaceIndex> {
let (to_output, to_idx) = to; let (to_output, to_idx) = to;
let to_idx = to_idx.unwrap_or(state.common.shell.workspaces.active_num(to_output).1); let to_idx = to_idx.unwrap_or(state.common.shell.workspaces.active_num(to_output).1);
@ -1338,7 +1339,7 @@ impl Shell {
} else { } else {
to_workspace to_workspace
.tiling_layer .tiling_layer
.map(mapped.clone(), &seat, focus_stack.iter()); .map(mapped.clone(), &seat, focus_stack.iter(), direction);
} }
for (toplevel, _) in mapped.windows() { for (toplevel, _) in mapped.windows() {
if from_output != to_output { if from_output != to_output {

View file

@ -402,7 +402,8 @@ impl Workspace {
.into_iter() .into_iter()
{ {
self.floating_layer.unmap(&window); 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; self.tiling_enabled = true;
} }
@ -417,7 +418,8 @@ impl Workspace {
} else if self.floating_layer.mapped().any(|w| w == &window) { } else if self.floating_layer.mapped().any(|w| w == &window) {
let focus_stack = self.focus_stack.get(seat); let focus_stack = self.focus_stack.get(seat);
self.floating_layer.unmap(&window); self.floating_layer.unmap(&window);
self.tiling_layer.map(window, seat, focus_stack.iter()) self.tiling_layer
.map(window, seat, focus_stack.iter(), None)
} }
} }
} }