input: Take into account output layout

This commit is contained in:
Victoria Brekenfeld 2023-11-16 19:28:00 +01:00 committed by Victoria Brekenfeld
parent 92c16bd4ad
commit 59581f717f
4 changed files with 238 additions and 81 deletions

View file

@ -25,10 +25,14 @@
(modifiers: [Super, Shift], key: "9"): MoveToWorkspace(9), (modifiers: [Super, Shift], key: "9"): MoveToWorkspace(9),
(modifiers: [Super, Shift], key: "0"): MoveToLastWorkspace, (modifiers: [Super, Shift], key: "0"): MoveToLastWorkspace,
(modifiers: [Super, Ctrl, Alt], key: "Down"): MoveToNextOutput, (modifiers: [Super, Ctrl, Alt], key: "Left"): MoveToOutput(Left),
(modifiers: [Super, Ctrl, Alt], key: "Up"): MoveToPreviousOutput, (modifiers: [Super, Ctrl, Alt], key: "Down"): MoveToOutput(Down),
(modifiers: [Super, Ctrl, Alt], key: "j"): MoveToNextOutput, (modifiers: [Super, Ctrl, Alt], key: "Up"): MoveToOutput(Up),
(modifiers: [Super, Ctrl, Alt], key: "k"): MoveToPreviousOutput, (modifiers: [Super, Ctrl, Alt], key: "Right"): MoveToOutput(Right),
(modifiers: [Super, Ctrl, Alt], key: "h"): MoveToOutput(Left),
(modifiers: [Super, Ctrl, Alt], key: "k"): MoveToOutput(Down),
(modifiers: [Super, Ctrl, Alt], key: "j"): MoveToOutput(Up),
(modifiers: [Super, Ctrl, Alt], key: "l"): MoveToOutput(Right),
(modifiers: [Super], key: "Period"): NextOutput, (modifiers: [Super], key: "Period"): NextOutput,
(modifiers: [Super], key: "Comma"): PreviousOutput, (modifiers: [Super], key: "Comma"): PreviousOutput,

View file

@ -101,6 +101,16 @@ impl KeyPattern {
key, key,
} }
} }
pub fn inferred_direction(&self) -> Option<Direction> {
match self.key? {
Keysym::Left | Keysym::h | Keysym::H => Some(Direction::Left),
Keysym::Down | Keysym::j | Keysym::J => Some(Direction::Down),
Keysym::Up | Keysym::k | Keysym::K => Some(Direction::Up),
Keysym::Right | Keysym::l | Keysym::L => Some(Direction::Right),
_ => None,
}
}
} }
impl ToString for KeyPattern { impl ToString for KeyPattern {
@ -153,6 +163,9 @@ pub enum Action {
MoveToPreviousOutput, MoveToPreviousOutput,
SendToNextOutput, SendToNextOutput,
SendToPreviousOutput, SendToPreviousOutput,
SwitchOutput(Direction),
MoveToOutput(Direction),
SendToOutput(Direction),
Focus(FocusDirection), Focus(FocusDirection),
Move(Direction), Move(Direction),
@ -195,19 +208,23 @@ pub fn add_default_bindings(
key_bindings: &mut HashMap<KeyPattern, Action>, key_bindings: &mut HashMap<KeyPattern, Action>,
workspace_layout: WorkspaceLayout, workspace_layout: WorkspaceLayout,
) { ) {
let (workspace_previous, workspace_next, output_previous, output_next) = match workspace_layout let (
{ workspace_previous,
workspace_next,
(output_previous, output_previous_dir),
(output_next, output_next_dir),
) = match workspace_layout {
WorkspaceLayout::Horizontal => ( WorkspaceLayout::Horizontal => (
[Keysym::Left, Keysym::h], [Keysym::Left, Keysym::h],
[Keysym::Right, Keysym::l], [Keysym::Right, Keysym::l],
[Keysym::Up, Keysym::k], ([Keysym::Up, Keysym::k], Direction::Up),
[Keysym::Down, Keysym::j], ([Keysym::Down, Keysym::j], Direction::Down),
), ),
WorkspaceLayout::Vertical => ( WorkspaceLayout::Vertical => (
[Keysym::Up, Keysym::k], [Keysym::Up, Keysym::k],
[Keysym::Down, Keysym::j], [Keysym::Down, Keysym::j],
[Keysym::Left, Keysym::h], ([Keysym::Left, Keysym::h], Direction::Left),
[Keysym::Right, Keysym::l], ([Keysym::Right, Keysym::l], Direction::Right),
), ),
}; };
@ -262,7 +279,7 @@ pub fn add_default_bindings(
..Default::default() ..Default::default()
}, },
output_previous.iter().copied(), output_previous.iter().copied(),
Action::PreviousOutput, Action::SwitchOutput(output_previous_dir),
); );
insert_binding( insert_binding(
key_bindings, key_bindings,
@ -272,7 +289,7 @@ pub fn add_default_bindings(
..Default::default() ..Default::default()
}, },
output_next.iter().copied(), output_next.iter().copied(),
Action::NextOutput, Action::SwitchOutput(output_next_dir),
); );
insert_binding( insert_binding(
key_bindings, key_bindings,
@ -283,7 +300,7 @@ pub fn add_default_bindings(
..Default::default() ..Default::default()
}, },
output_previous.iter().copied(), output_previous.iter().copied(),
Action::MoveToPreviousOutput, Action::MoveToOutput(output_previous_dir),
); );
insert_binding( insert_binding(
key_bindings, key_bindings,
@ -294,6 +311,6 @@ pub fn add_default_bindings(
..Default::default() ..Default::default()
}, },
output_next.iter().copied(), output_next.iter().copied(),
Action::MoveToNextOutput, Action::MoveToOutput(output_next_dir),
); );
} }

View file

@ -1221,7 +1221,16 @@ impl State {
.activate(&current_output, workspace) .activate(&current_output, workspace)
.is_err() .is_err()
{ {
self.handle_action(Action::NextOutput, seat, serial, time, pattern, direction); if let Some(inferred) = pattern.inferred_direction() {
self.handle_action(
Action::SwitchOutput(inferred),
seat,
serial,
time,
pattern,
direction,
)
};
} }
} }
Action::PreviousWorkspace => { Action::PreviousWorkspace => {
@ -1239,14 +1248,16 @@ impl State {
.activate(&current_output, workspace) .activate(&current_output, workspace)
.is_err() .is_err()
{ {
self.handle_action( if let Some(inferred) = pattern.inferred_direction() {
Action::PreviousOutput, self.handle_action(
seat, Action::SwitchOutput(inferred),
serial, seat,
time, serial,
pattern, time,
direction, pattern,
); direction,
)
};
} }
} }
Action::LastWorkspace => { Action::LastWorkspace => {
@ -1295,18 +1306,20 @@ impl State {
) )
.is_err() .is_err()
{ {
self.handle_action( if let Some(inferred) = pattern.inferred_direction() {
if matches!(x, Action::MoveToNextWorkspace) { self.handle_action(
Action::MoveToNextOutput if matches!(x, Action::MoveToNextWorkspace) {
} else { Action::MoveToOutput(inferred)
Action::SendToNextOutput } else {
}, Action::SendToOutput(inferred)
seat, },
serial, seat,
time, serial,
pattern, time,
direction, pattern,
) direction,
)
}
} }
} }
x @ Action::MoveToPreviousWorkspace | x @ Action::SendToPreviousWorkspace => { x @ Action::MoveToPreviousWorkspace | x @ Action::SendToPreviousWorkspace => {
@ -1329,18 +1342,20 @@ impl State {
) )
.is_err() .is_err()
{ {
self.handle_action( if let Some(inferred) = pattern.inferred_direction() {
if matches!(x, Action::MoveToNextWorkspace) { self.handle_action(
Action::MoveToPreviousOutput if matches!(x, Action::MoveToPreviousWorkspace) {
} else { Action::MoveToOutput(inferred)
Action::SendToPreviousOutput } else {
}, Action::SendToOutput(inferred)
seat, },
serial, seat,
time, serial,
pattern, time,
direction, pattern,
) direction,
)
}
} }
} }
x @ Action::MoveToLastWorkspace | x @ Action::SendToLastWorkspace => { x @ Action::MoveToLastWorkspace | x @ Action::SendToLastWorkspace => {
@ -1360,6 +1375,39 @@ impl State {
None, None,
); );
} }
Action::SwitchOutput(direction) => {
let current_output = seat.active_output();
let next_output = self
.common
.shell
.next_output(&current_output, direction)
.cloned();
if let Some(next_output) = next_output {
let idx = self.common.shell.workspaces.active_num(&next_output).1;
match self.common.shell.activate(&next_output, idx) {
Ok(Some(new_pos)) => {
seat.set_active_output(&next_output);
if let Some(ptr) = seat.get_pointer() {
ptr.motion(
self,
None,
&MotionEvent {
location: new_pos.to_f64().as_logical(),
serial,
time,
},
);
ptr.frame(self);
}
}
Ok(None) => {
seat.set_active_output(&next_output);
}
_ => {}
}
}
}
Action::NextOutput => { Action::NextOutput => {
let current_output = seat.active_output(); let current_output = seat.active_output();
let next_output = self let next_output = self
@ -1431,6 +1479,45 @@ impl State {
} }
} }
} }
action @ Action::MoveToOutput(_) | action @ Action::SendToOutput(_) => {
let is_move_action = matches!(action, Action::MoveToOutput(_));
let direction = match action {
Action::MoveToOutput(dir) => dir,
Action::SendToOutput(dir) => dir,
_ => unreachable!(),
};
let current_output = seat.active_output();
let next_output = self
.common
.shell
.next_output(&current_output, direction)
.cloned();
if let Some(next_output) = next_output {
if let Ok(Some(new_pos)) = Shell::move_current_window(
self,
seat,
&current_output,
(&next_output, None),
is_move_action,
Some(direction),
) {
if let Some(ptr) = seat.get_pointer() {
ptr.motion(
self,
None,
&MotionEvent {
location: new_pos.to_f64().as_logical(),
serial,
time,
},
);
ptr.frame(self);
}
}
}
}
x @ Action::MoveToNextOutput | x @ Action::SendToNextOutput => { x @ Action::MoveToNextOutput | x @ Action::SendToNextOutput => {
let current_output = seat.active_output(); let current_output = seat.active_output();
let next_output = self let next_output = self
@ -1537,25 +1624,31 @@ impl State {
direction, direction,
), ),
(FocusDirection::Left, WorkspaceLayout::Vertical) (FocusDirection::Left, WorkspaceLayout::Vertical)
| (FocusDirection::Up, WorkspaceLayout::Horizontal) => self | (FocusDirection::Up, WorkspaceLayout::Horizontal) => {
.handle_action( if let Some(inferred) = pattern.inferred_direction() {
Action::PreviousOutput, self.handle_action(
seat, Action::SwitchOutput(inferred),
serial, seat,
time, serial,
pattern, time,
direction, pattern,
), direction,
)
}
}
(FocusDirection::Right, WorkspaceLayout::Vertical) (FocusDirection::Right, WorkspaceLayout::Vertical)
| (FocusDirection::Down, WorkspaceLayout::Horizontal) => self | (FocusDirection::Down, WorkspaceLayout::Horizontal) => {
.handle_action( if let Some(inferred) = pattern.inferred_direction() {
Action::NextOutput, self.handle_action(
seat, Action::SwitchOutput(inferred),
serial, seat,
time, serial,
pattern, time,
direction, pattern,
), direction,
)
}
}
_ => {} _ => {}
} }
} }
@ -1591,23 +1684,31 @@ impl State {
Some(direction), Some(direction),
), ),
(Direction::Left, WorkspaceLayout::Vertical) (Direction::Left, WorkspaceLayout::Vertical)
| (Direction::Up, WorkspaceLayout::Horizontal) => self.handle_action( | (Direction::Up, WorkspaceLayout::Horizontal) => {
Action::MoveToPreviousOutput, if let Some(inferred) = pattern.inferred_direction() {
seat, self.handle_action(
serial, Action::MoveToOutput(inferred),
time, seat,
pattern, serial,
Some(direction), time,
), pattern,
Some(direction),
)
}
}
(Direction::Right, WorkspaceLayout::Vertical) (Direction::Right, WorkspaceLayout::Vertical)
| (Direction::Down, WorkspaceLayout::Horizontal) => self.handle_action( | (Direction::Down, WorkspaceLayout::Horizontal) => {
Action::MoveToNextOutput, if let Some(inferred) = pattern.inferred_direction() {
seat, self.handle_action(
serial, Action::MoveToOutput(inferred),
time, seat,
pattern, serial,
Some(direction), time,
), pattern,
Some(direction),
)
}
}
} }
} }
MoveResult::ShiftFocus(shift) => { MoveResult::ShiftFocus(shift) => {

View file

@ -1146,6 +1146,41 @@ impl Shell {
) )
} }
pub fn next_output(&self, current_output: &Output, direction: Direction) -> Option<&Output> {
let current_output_geo = current_output.geometry();
self.outputs()
.filter(|o| *o != current_output)
.filter(|o| {
let geo = o.geometry();
match direction {
Direction::Left | Direction::Right => {
!(geo.loc.y + geo.size.h < current_output_geo.loc.y
|| geo.loc.y > current_output_geo.loc.y + current_output_geo.size.h)
}
Direction::Up | Direction::Down => {
!(geo.loc.x + geo.size.w < current_output_geo.loc.x
|| geo.loc.x > current_output_geo.loc.x + current_output_geo.size.w)
}
}
})
.filter_map(|o| {
let origin = o.geometry().loc;
let res = match direction {
Direction::Up => current_output_geo.loc.y - origin.y,
Direction::Down => origin.y - current_output_geo.loc.y,
Direction::Left => current_output_geo.loc.x - origin.x,
Direction::Right => origin.x - current_output_geo.loc.x,
};
if res > 0 {
Some((o, res))
} else {
None
}
})
.min_by_key(|(_, res)| *res)
.map(|(o, _)| o)
}
pub fn global_space(&self) -> Rectangle<i32, Global> { pub fn global_space(&self) -> Rectangle<i32, Global> {
self.outputs() self.outputs()
.fold( .fold(