tiling: Consider direction when moving across workspaces and outputs
Fixes second case of #113.
This commit is contained in:
parent
bf0eb97bea
commit
2f6d4da712
4 changed files with 113 additions and 43 deletions
|
|
@ -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(¤t_output, workspace)
|
.activate(¤t_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(¤t_output, workspace)
|
.activate(¤t_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 {
|
||||||
¤t_output,
|
¤t_output,
|
||||||
(¤t_output, Some(workspace as usize)),
|
(¤t_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 {
|
||||||
¤t_output,
|
¤t_output,
|
||||||
(¤t_output, Some(workspace as usize)),
|
(¤t_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 {
|
||||||
¤t_output,
|
¤t_output,
|
||||||
(¤t_output, Some(workspace as usize)),
|
(¤t_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 {
|
||||||
¤t_output,
|
¤t_output,
|
||||||
(¤t_output, Some(workspace as usize)),
|
(¤t_output, Some(workspace as usize)),
|
||||||
matches!(x, Action::MoveToLastWorkspace),
|
matches!(x, Action::MoveToLastWorkspace),
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Action::NextOutput => {
|
Action::NextOutput => {
|
||||||
|
|
@ -919,6 +926,7 @@ impl State {
|
||||||
¤t_output,
|
¤t_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 {
|
||||||
¤t_output,
|
¤t_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);
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue