shell: Implement Workspace Layout
This commit is contained in:
parent
cb3e8d42a7
commit
be918152d5
7 changed files with 261 additions and 80 deletions
23
config.ron
23
config.ron
|
|
@ -25,24 +25,10 @@
|
||||||
(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,
|
||||||
|
|
||||||
// TODO: Depends on workspace orientation
|
(modifiers: [Super, Ctrl, Alt], key: "Down"): MoveToNextOutput,
|
||||||
(modifiers: [Super, Ctrl], key: "Right"): NextWorkspace,
|
(modifiers: [Super, Ctrl, Alt], key: "Up"): MoveToPreviousOutput,
|
||||||
(modifiers: [Super, Ctrl], key: "Left"): PreviousWorkspace,
|
(modifiers: [Super, Ctrl, Alt], key: "j"): MoveToNextOutput,
|
||||||
(modifiers: [Super, Ctrl, Shift], key: "Right"): MoveToNextWorkspace,
|
(modifiers: [Super, Ctrl, Alt], key: "k"): MoveToPreviousOutput,
|
||||||
(modifiers: [Super, Ctrl, Shift], key: "Left"): MoveToPreviousWorkspace,
|
|
||||||
(modifiers: [Super, Ctrl], key: "l"): NextWorkspace,
|
|
||||||
(modifiers: [Super, Ctrl], key: "h"): PreviousWorkspace,
|
|
||||||
(modifiers: [Super, Ctrl, Shift], key: "l"): MoveToNextWorkspace,
|
|
||||||
(modifiers: [Super, Ctrl, Shift], key: "h"): MoveToPreviousWorkspace,
|
|
||||||
|
|
||||||
(modifiers: [Super, Ctrl], key: "Down"): NextOutput,
|
|
||||||
(modifiers: [Super, Ctrl], key: "Up"): PreviousOutput,
|
|
||||||
(modifiers: [Super, Ctrl, Alt], key: "Down"): NextOutput,
|
|
||||||
(modifiers: [Super, Ctrl, Alt], key: "Up"): PreviousOutput,
|
|
||||||
(modifiers: [Super, Ctrl], key: "j"): NextOutput,
|
|
||||||
(modifiers: [Super, Ctrl], key: "k"): PreviousOutput,
|
|
||||||
(modifiers: [Super, Ctrl, Alt], key: "j"): NextOutput,
|
|
||||||
(modifiers: [Super, Ctrl, Alt], key: "k"): PreviousOutput,
|
|
||||||
|
|
||||||
(modifiers: [Super], key: "Period"): NextOutput,
|
(modifiers: [Super], key: "Period"): NextOutput,
|
||||||
(modifiers: [Super], key: "Comma"): PreviousOutput,
|
(modifiers: [Super], key: "Comma"): PreviousOutput,
|
||||||
|
|
@ -93,5 +79,6 @@
|
||||||
},
|
},
|
||||||
workspace_mode: OutputBound,
|
workspace_mode: OutputBound,
|
||||||
workspace_amount: Dynamic,
|
workspace_amount: Dynamic,
|
||||||
|
workspace_layout: Vertical,
|
||||||
tiling_enabled: false,
|
tiling_enabled: false,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -396,7 +396,7 @@ where
|
||||||
|
|
||||||
let offset = match previous.as_ref() {
|
let offset = match previous.as_ref() {
|
||||||
Some((previous, previous_idx, start)) => {
|
Some((previous, previous_idx, start)) => {
|
||||||
let layout = WorkspaceLayout::Vertical;
|
let layout = state.config.static_conf.workspace_layout;
|
||||||
|
|
||||||
let workspace = state
|
let workspace = state
|
||||||
.shell
|
.shell
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,8 @@ pub struct StaticConfig {
|
||||||
pub key_bindings: HashMap<KeyPattern, Action>,
|
pub key_bindings: HashMap<KeyPattern, Action>,
|
||||||
pub workspace_mode: WorkspaceMode,
|
pub workspace_mode: WorkspaceMode,
|
||||||
pub workspace_amount: WorkspaceAmount,
|
pub workspace_amount: WorkspaceAmount,
|
||||||
|
#[serde(default = "default_workspace_layout")]
|
||||||
|
pub workspace_layout: WorkspaceLayout,
|
||||||
pub tiling_enabled: bool,
|
pub tiling_enabled: bool,
|
||||||
#[serde(default = "default_active_hint")]
|
#[serde(default = "default_active_hint")]
|
||||||
pub active_hint: u8,
|
pub active_hint: u8,
|
||||||
|
|
@ -95,6 +97,10 @@ fn default_gaps() -> (u8, u8) {
|
||||||
(0, 4)
|
(0, 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_workspace_layout() -> WorkspaceLayout {
|
||||||
|
WorkspaceLayout::Vertical
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
|
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
|
||||||
pub struct OutputConfig {
|
pub struct OutputConfig {
|
||||||
pub mode: ((i32, i32), Option<u32>),
|
pub mode: ((i32, i32), Option<u32>),
|
||||||
|
|
@ -232,8 +238,132 @@ impl Config {
|
||||||
debug!("Trying config location: {}", path.display());
|
debug!("Trying config location: {}", path.display());
|
||||||
if path.exists() {
|
if path.exists() {
|
||||||
info!("Using config at {}", path.display());
|
info!("Using config at {}", path.display());
|
||||||
return ron::de::from_reader(OpenOptions::new().read(true).open(path).unwrap())
|
let mut config: StaticConfig =
|
||||||
.expect("Malformed config file");
|
ron::de::from_reader(OpenOptions::new().read(true).open(path).unwrap())
|
||||||
|
.expect("Malformed config file");
|
||||||
|
|
||||||
|
let (workspace_previous, workspace_next, output_previous, output_next) =
|
||||||
|
match config.workspace_layout {
|
||||||
|
WorkspaceLayout::Horizontal => (
|
||||||
|
[KeySyms::KEY_Left, KeySyms::KEY_h],
|
||||||
|
[KeySyms::KEY_Right, KeySyms::KEY_j],
|
||||||
|
[KeySyms::KEY_Up, KeySyms::KEY_k],
|
||||||
|
[KeySyms::KEY_Down, KeySyms::KEY_j],
|
||||||
|
),
|
||||||
|
WorkspaceLayout::Vertical => (
|
||||||
|
[KeySyms::KEY_Up, KeySyms::KEY_k],
|
||||||
|
[KeySyms::KEY_Down, KeySyms::KEY_j],
|
||||||
|
[KeySyms::KEY_Left, KeySyms::KEY_h],
|
||||||
|
[KeySyms::KEY_Right, KeySyms::KEY_j],
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
fn insert_binding(
|
||||||
|
key_bindings: &mut HashMap<KeyPattern, Action>,
|
||||||
|
modifiers: KeyModifiers,
|
||||||
|
keys: impl Iterator<Item = u32>,
|
||||||
|
action: Action,
|
||||||
|
) {
|
||||||
|
if !key_bindings.values().any(|a| a == &action) {
|
||||||
|
for key in keys {
|
||||||
|
let pattern = KeyPattern {
|
||||||
|
modifiers: modifiers.clone(),
|
||||||
|
key,
|
||||||
|
};
|
||||||
|
if !key_bindings.contains_key(&pattern) {
|
||||||
|
key_bindings.insert(pattern, action.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
insert_binding(
|
||||||
|
&mut config.key_bindings,
|
||||||
|
KeyModifiers {
|
||||||
|
logo: true,
|
||||||
|
ctrl: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
workspace_previous.iter().copied(),
|
||||||
|
Action::PreviousWorkspace,
|
||||||
|
);
|
||||||
|
insert_binding(
|
||||||
|
&mut config.key_bindings,
|
||||||
|
KeyModifiers {
|
||||||
|
logo: true,
|
||||||
|
ctrl: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
workspace_next.iter().copied(),
|
||||||
|
Action::NextWorkspace,
|
||||||
|
);
|
||||||
|
insert_binding(
|
||||||
|
&mut config.key_bindings,
|
||||||
|
KeyModifiers {
|
||||||
|
logo: true,
|
||||||
|
ctrl: true,
|
||||||
|
shift: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
workspace_previous.iter().copied(),
|
||||||
|
Action::MoveToPreviousWorkspace,
|
||||||
|
);
|
||||||
|
insert_binding(
|
||||||
|
&mut config.key_bindings,
|
||||||
|
KeyModifiers {
|
||||||
|
logo: true,
|
||||||
|
ctrl: true,
|
||||||
|
shift: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
workspace_next.iter().copied(),
|
||||||
|
Action::MoveToNextWorkspace,
|
||||||
|
);
|
||||||
|
|
||||||
|
insert_binding(
|
||||||
|
&mut config.key_bindings,
|
||||||
|
KeyModifiers {
|
||||||
|
logo: true,
|
||||||
|
ctrl: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
output_previous.iter().copied(),
|
||||||
|
Action::PreviousOutput,
|
||||||
|
);
|
||||||
|
insert_binding(
|
||||||
|
&mut config.key_bindings,
|
||||||
|
KeyModifiers {
|
||||||
|
logo: true,
|
||||||
|
ctrl: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
output_next.iter().copied(),
|
||||||
|
Action::NextOutput,
|
||||||
|
);
|
||||||
|
insert_binding(
|
||||||
|
&mut config.key_bindings,
|
||||||
|
KeyModifiers {
|
||||||
|
logo: true,
|
||||||
|
ctrl: true,
|
||||||
|
shift: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
output_previous.iter().copied(),
|
||||||
|
Action::MoveToPreviousOutput,
|
||||||
|
);
|
||||||
|
insert_binding(
|
||||||
|
&mut config.key_bindings,
|
||||||
|
KeyModifiers {
|
||||||
|
logo: true,
|
||||||
|
ctrl: true,
|
||||||
|
shift: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
output_next.iter().copied(),
|
||||||
|
Action::MoveToNextOutput,
|
||||||
|
);
|
||||||
|
|
||||||
|
return config;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -241,6 +371,7 @@ impl Config {
|
||||||
key_bindings: HashMap::new(),
|
key_bindings: HashMap::new(),
|
||||||
workspace_mode: WorkspaceMode::Global,
|
workspace_mode: WorkspaceMode::Global,
|
||||||
workspace_amount: WorkspaceAmount::Dynamic,
|
workspace_amount: WorkspaceAmount::Dynamic,
|
||||||
|
workspace_layout: WorkspaceLayout::Vertical,
|
||||||
tiling_enabled: false,
|
tiling_enabled: false,
|
||||||
active_hint: default_active_hint(),
|
active_hint: default_active_hint(),
|
||||||
gaps: default_gaps(),
|
gaps: default_gaps(),
|
||||||
|
|
@ -776,7 +907,7 @@ pub enum KeyModifier {
|
||||||
NumLock,
|
NumLock,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
|
||||||
pub struct KeyModifiers {
|
pub struct KeyModifiers {
|
||||||
pub ctrl: bool,
|
pub ctrl: bool,
|
||||||
pub alt: bool,
|
pub alt: bool,
|
||||||
|
|
@ -880,6 +1011,8 @@ pub enum Action {
|
||||||
PreviousOutput,
|
PreviousOutput,
|
||||||
MoveToNextOutput,
|
MoveToNextOutput,
|
||||||
MoveToPreviousOutput,
|
MoveToPreviousOutput,
|
||||||
|
SendToNextOutput,
|
||||||
|
SendToPreviousOutput,
|
||||||
|
|
||||||
Focus(FocusDirection),
|
Focus(FocusDirection),
|
||||||
Move(Direction),
|
Move(Direction),
|
||||||
|
|
|
||||||
116
src/input/mod.rs
116
src/input/mod.rs
|
|
@ -1,7 +1,7 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{Action, Config, KeyModifiers},
|
config::{Action, Config, KeyModifiers, WorkspaceLayout},
|
||||||
shell::{
|
shell::{
|
||||||
focus::{target::PointerFocusTarget, FocusDirection},
|
focus::{target::PointerFocusTarget, FocusDirection},
|
||||||
layout::{
|
layout::{
|
||||||
|
|
@ -710,8 +710,14 @@ impl State {
|
||||||
.active_num(¤t_output)
|
.active_num(¤t_output)
|
||||||
.1
|
.1
|
||||||
.saturating_add(1);
|
.saturating_add(1);
|
||||||
// TODO: Possibly move to next output, if idx to large
|
if self
|
||||||
let _ = self.common.shell.activate(¤t_output, workspace);
|
.common
|
||||||
|
.shell
|
||||||
|
.activate(¤t_output, workspace)
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
self.handle_action(Action::NextOutput, seat, serial, time, mods);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Action::PreviousWorkspace => {
|
Action::PreviousWorkspace => {
|
||||||
let current_output = seat.active_output();
|
let current_output = seat.active_output();
|
||||||
|
|
@ -722,8 +728,14 @@ impl State {
|
||||||
.active_num(¤t_output)
|
.active_num(¤t_output)
|
||||||
.1
|
.1
|
||||||
.saturating_sub(1);
|
.saturating_sub(1);
|
||||||
// TODO: Possibly move to prev output, if idx < 0
|
if self
|
||||||
let _ = self.common.shell.activate(¤t_output, workspace);
|
.common
|
||||||
|
.shell
|
||||||
|
.activate(¤t_output, workspace)
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
self.handle_action(Action::PreviousOutput, seat, serial, time, mods);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Action::LastWorkspace => {
|
Action::LastWorkspace => {
|
||||||
let current_output = seat.active_output();
|
let current_output = seat.active_output();
|
||||||
|
|
@ -743,7 +755,7 @@ impl State {
|
||||||
Action::MoveToWorkspace(x) | Action::SendToWorkspace(x) => x - 1,
|
Action::MoveToWorkspace(x) | Action::SendToWorkspace(x) => x - 1,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
Shell::move_current_window(
|
let _ = Shell::move_current_window(
|
||||||
self,
|
self,
|
||||||
seat,
|
seat,
|
||||||
¤t_output,
|
¤t_output,
|
||||||
|
|
@ -760,14 +772,27 @@ impl State {
|
||||||
.active_num(¤t_output)
|
.active_num(¤t_output)
|
||||||
.1
|
.1
|
||||||
.saturating_add(1);
|
.saturating_add(1);
|
||||||
// TODO: Possibly move to next output, if idx too large
|
if Shell::move_current_window(
|
||||||
Shell::move_current_window(
|
|
||||||
self,
|
self,
|
||||||
seat,
|
seat,
|
||||||
¤t_output,
|
¤t_output,
|
||||||
(¤t_output, Some(workspace as usize)),
|
(¤t_output, Some(workspace as usize)),
|
||||||
matches!(x, Action::MoveToNextWorkspace),
|
matches!(x, Action::MoveToNextWorkspace),
|
||||||
);
|
)
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
self.handle_action(
|
||||||
|
if matches!(x, Action::MoveToNextWorkspace) {
|
||||||
|
Action::MoveToNextOutput
|
||||||
|
} else {
|
||||||
|
Action::SendToNextOutput
|
||||||
|
},
|
||||||
|
seat,
|
||||||
|
serial,
|
||||||
|
time,
|
||||||
|
mods,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
x @ Action::MoveToPreviousWorkspace | x @ Action::SendToPreviousWorkspace => {
|
x @ Action::MoveToPreviousWorkspace | x @ Action::SendToPreviousWorkspace => {
|
||||||
let current_output = seat.active_output();
|
let current_output = seat.active_output();
|
||||||
|
|
@ -779,13 +804,27 @@ impl State {
|
||||||
.1
|
.1
|
||||||
.saturating_sub(1);
|
.saturating_sub(1);
|
||||||
// TODO: Possibly move to prev output, if idx < 0
|
// TODO: Possibly move to prev output, if idx < 0
|
||||||
Shell::move_current_window(
|
if Shell::move_current_window(
|
||||||
self,
|
self,
|
||||||
seat,
|
seat,
|
||||||
¤t_output,
|
¤t_output,
|
||||||
(¤t_output, Some(workspace as usize)),
|
(¤t_output, Some(workspace as usize)),
|
||||||
matches!(x, Action::MoveToPreviousWorkspace),
|
matches!(x, Action::MoveToPreviousWorkspace),
|
||||||
);
|
)
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
self.handle_action(
|
||||||
|
if matches!(x, Action::MoveToNextWorkspace) {
|
||||||
|
Action::MoveToPreviousOutput
|
||||||
|
} else {
|
||||||
|
Action::SendToPreviousOutput
|
||||||
|
},
|
||||||
|
seat,
|
||||||
|
serial,
|
||||||
|
time,
|
||||||
|
mods,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
x @ Action::MoveToLastWorkspace | x @ Action::SendToLastWorkspace => {
|
x @ Action::MoveToLastWorkspace | x @ Action::SendToLastWorkspace => {
|
||||||
let current_output = seat.active_output();
|
let current_output = seat.active_output();
|
||||||
|
|
@ -795,7 +834,7 @@ impl State {
|
||||||
.workspaces
|
.workspaces
|
||||||
.len(¤t_output)
|
.len(¤t_output)
|
||||||
.saturating_sub(1);
|
.saturating_sub(1);
|
||||||
Shell::move_current_window(
|
let _ = Shell::move_current_window(
|
||||||
self,
|
self,
|
||||||
seat,
|
seat,
|
||||||
¤t_output,
|
¤t_output,
|
||||||
|
|
@ -816,7 +855,7 @@ impl State {
|
||||||
.cloned()
|
.cloned()
|
||||||
{
|
{
|
||||||
let idx = self.common.shell.workspaces.active_num(&next_output).1;
|
let idx = self.common.shell.workspaces.active_num(&next_output).1;
|
||||||
if let Some(new_pos) = self.common.shell.activate(&next_output, idx) {
|
if let Ok(Some(new_pos)) = self.common.shell.activate(&next_output, idx) {
|
||||||
seat.set_active_output(&next_output);
|
seat.set_active_output(&next_output);
|
||||||
if let Some(ptr) = seat.get_pointer() {
|
if let Some(ptr) = seat.get_pointer() {
|
||||||
ptr.motion(
|
ptr.motion(
|
||||||
|
|
@ -846,7 +885,7 @@ impl State {
|
||||||
.cloned()
|
.cloned()
|
||||||
{
|
{
|
||||||
let idx = self.common.shell.workspaces.active_num(&prev_output).1;
|
let idx = self.common.shell.workspaces.active_num(&prev_output).1;
|
||||||
if let Some(new_pos) = self.common.shell.activate(&prev_output, idx) {
|
if let Ok(Some(new_pos)) = self.common.shell.activate(&prev_output, idx) {
|
||||||
seat.set_active_output(&prev_output);
|
seat.set_active_output(&prev_output);
|
||||||
if let Some(ptr) = seat.get_pointer() {
|
if let Some(ptr) = seat.get_pointer() {
|
||||||
ptr.motion(
|
ptr.motion(
|
||||||
|
|
@ -862,7 +901,7 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Action::MoveToNextOutput => {
|
x @ Action::MoveToNextOutput | x @ Action::SendToNextOutput => {
|
||||||
let current_output = seat.active_output();
|
let current_output = seat.active_output();
|
||||||
if let Some(next_output) = self
|
if let Some(next_output) = self
|
||||||
.common
|
.common
|
||||||
|
|
@ -874,12 +913,12 @@ impl State {
|
||||||
.next()
|
.next()
|
||||||
.cloned()
|
.cloned()
|
||||||
{
|
{
|
||||||
if let Some(new_pos) = Shell::move_current_window(
|
if let Ok(Some(new_pos)) = Shell::move_current_window(
|
||||||
self,
|
self,
|
||||||
seat,
|
seat,
|
||||||
¤t_output,
|
¤t_output,
|
||||||
(&next_output, None),
|
(&next_output, None),
|
||||||
true,
|
matches!(x, Action::MoveToNextOutput),
|
||||||
) {
|
) {
|
||||||
if let Some(ptr) = seat.get_pointer() {
|
if let Some(ptr) = seat.get_pointer() {
|
||||||
ptr.motion(
|
ptr.motion(
|
||||||
|
|
@ -895,7 +934,7 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Action::MoveToPreviousOutput => {
|
x @ Action::MoveToPreviousOutput | x @ Action::SendToPreviousOutput => {
|
||||||
let current_output = seat.active_output();
|
let current_output = seat.active_output();
|
||||||
if let Some(prev_output) = self
|
if let Some(prev_output) = self
|
||||||
.common
|
.common
|
||||||
|
|
@ -908,12 +947,12 @@ impl State {
|
||||||
.next()
|
.next()
|
||||||
.cloned()
|
.cloned()
|
||||||
{
|
{
|
||||||
if let Some(new_pos) = Shell::move_current_window(
|
if let Ok(Some(new_pos)) = Shell::move_current_window(
|
||||||
self,
|
self,
|
||||||
seat,
|
seat,
|
||||||
¤t_output,
|
¤t_output,
|
||||||
(&prev_output, None),
|
(&prev_output, None),
|
||||||
true,
|
matches!(x, Action::MoveToPreviousOutput),
|
||||||
) {
|
) {
|
||||||
if let Some(ptr) = seat.get_pointer() {
|
if let Some(ptr) = seat.get_pointer() {
|
||||||
ptr.motion(
|
ptr.motion(
|
||||||
|
|
@ -942,22 +981,20 @@ impl State {
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
FocusResult::None => {
|
FocusResult::None => {
|
||||||
// TODO: Handle Workspace orientation
|
match (focus, self.common.config.static_conf.workspace_layout) {
|
||||||
match focus {
|
(FocusDirection::Left, WorkspaceLayout::Horizontal)
|
||||||
FocusDirection::Left => self.handle_action(
|
| (FocusDirection::Up, WorkspaceLayout::Vertical) => self
|
||||||
Action::PreviousWorkspace,
|
.handle_action(Action::PreviousWorkspace, seat, serial, time, mods),
|
||||||
seat,
|
(FocusDirection::Right, WorkspaceLayout::Horizontal)
|
||||||
serial,
|
| (FocusDirection::Down, WorkspaceLayout::Vertical) => {
|
||||||
time,
|
|
||||||
mods,
|
|
||||||
),
|
|
||||||
FocusDirection::Right => {
|
|
||||||
self.handle_action(Action::NextWorkspace, seat, serial, time, mods)
|
self.handle_action(Action::NextWorkspace, seat, serial, time, mods)
|
||||||
}
|
}
|
||||||
FocusDirection::Up => {
|
(FocusDirection::Left, WorkspaceLayout::Vertical)
|
||||||
|
| (FocusDirection::Up, WorkspaceLayout::Horizontal) => {
|
||||||
self.handle_action(Action::PreviousOutput, seat, serial, time, mods)
|
self.handle_action(Action::PreviousOutput, seat, serial, time, mods)
|
||||||
}
|
}
|
||||||
FocusDirection::Down => {
|
(FocusDirection::Right, WorkspaceLayout::Vertical)
|
||||||
|
| (FocusDirection::Down, WorkspaceLayout::Horizontal) => {
|
||||||
self.handle_action(Action::NextOutput, seat, serial, time, mods)
|
self.handle_action(Action::NextOutput, seat, serial, time, mods)
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
@ -980,31 +1017,34 @@ impl State {
|
||||||
if let Some(_move_further) =
|
if let Some(_move_further) =
|
||||||
workspace.tiling_layer.move_current_window(direction, seat)
|
workspace.tiling_layer.move_current_window(direction, seat)
|
||||||
{
|
{
|
||||||
// TODO: Handle Workspace orientation
|
|
||||||
// TODO: Being able to move Groups (move_further should be KeyboardFocusTarget instead)
|
// TODO: Being able to move Groups (move_further should be KeyboardFocusTarget instead)
|
||||||
match direction {
|
match (direction, self.common.config.static_conf.workspace_layout) {
|
||||||
Direction::Left => self.handle_action(
|
(Direction::Left, WorkspaceLayout::Horizontal)
|
||||||
|
| (Direction::Up, WorkspaceLayout::Vertical) => self.handle_action(
|
||||||
Action::MoveToPreviousWorkspace,
|
Action::MoveToPreviousWorkspace,
|
||||||
seat,
|
seat,
|
||||||
serial,
|
serial,
|
||||||
time,
|
time,
|
||||||
mods,
|
mods,
|
||||||
),
|
),
|
||||||
Direction::Right => self.handle_action(
|
(Direction::Right, WorkspaceLayout::Horizontal)
|
||||||
|
| (Direction::Down, WorkspaceLayout::Vertical) => self.handle_action(
|
||||||
Action::MoveToNextWorkspace,
|
Action::MoveToNextWorkspace,
|
||||||
seat,
|
seat,
|
||||||
serial,
|
serial,
|
||||||
time,
|
time,
|
||||||
mods,
|
mods,
|
||||||
),
|
),
|
||||||
Direction::Up => self.handle_action(
|
(Direction::Left, WorkspaceLayout::Vertical)
|
||||||
|
| (Direction::Up, WorkspaceLayout::Horizontal) => self.handle_action(
|
||||||
Action::MoveToPreviousOutput,
|
Action::MoveToPreviousOutput,
|
||||||
seat,
|
seat,
|
||||||
serial,
|
serial,
|
||||||
time,
|
time,
|
||||||
mods,
|
mods,
|
||||||
),
|
),
|
||||||
Direction::Down => {
|
(Direction::Right, WorkspaceLayout::Vertical)
|
||||||
|
| (Direction::Down, WorkspaceLayout::Horizontal) => {
|
||||||
self.handle_action(Action::MoveToNextOutput, seat, serial, time, mods)
|
self.handle_action(Action::MoveToNextOutput, seat, serial, time, mods)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -167,13 +167,24 @@ impl WorkspaceSet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn activate(&mut self, idx: usize, state: &mut WorkspaceUpdateGuard<'_, State>) {
|
fn activate(
|
||||||
if idx < self.workspaces.len() && self.active != idx {
|
&mut self,
|
||||||
|
idx: usize,
|
||||||
|
state: &mut WorkspaceUpdateGuard<'_, State>,
|
||||||
|
) -> Result<bool, InvalidWorkspaceIndex> {
|
||||||
|
if idx >= self.workspaces.len() {
|
||||||
|
return Err(InvalidWorkspaceIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.active != idx {
|
||||||
let old_active = self.active;
|
let old_active = self.active;
|
||||||
state.remove_workspace_state(&self.workspaces[old_active].handle, WState::Active);
|
state.remove_workspace_state(&self.workspaces[old_active].handle, WState::Active);
|
||||||
state.add_workspace_state(&self.workspaces[idx].handle, WState::Active);
|
state.add_workspace_state(&self.workspaces[idx].handle, WState::Active);
|
||||||
self.previously_active = Some((old_active, Instant::now()));
|
self.previously_active = Some((old_active, Instant::now()));
|
||||||
self.active = idx;
|
self.active = idx;
|
||||||
|
Ok(true)
|
||||||
|
} else {
|
||||||
|
Ok(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -476,6 +487,8 @@ impl WorkspaceMode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct InvalidWorkspaceIndex;
|
||||||
|
|
||||||
impl Shell {
|
impl Shell {
|
||||||
pub fn new(config: &Config, dh: &DisplayHandle) -> Self {
|
pub fn new(config: &Config, dh: &DisplayHandle) -> Self {
|
||||||
// TODO: Privileged protocols
|
// TODO: Privileged protocols
|
||||||
|
|
@ -893,20 +906,28 @@ impl Shell {
|
||||||
self.refresh(); // get rid of empty workspaces and enforce potential maximum
|
self.refresh(); // get rid of empty workspaces and enforce potential maximum
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn activate(&mut self, output: &Output, idx: usize) -> Option<Point<i32, Logical>> {
|
pub fn activate(
|
||||||
match &mut self.workspaces {
|
&mut self,
|
||||||
|
output: &Output,
|
||||||
|
idx: usize,
|
||||||
|
) -> Result<Option<Point<i32, Logical>>, InvalidWorkspaceIndex> {
|
||||||
|
if match &mut self.workspaces {
|
||||||
WorkspaceMode::OutputBound(sets, _) => {
|
WorkspaceMode::OutputBound(sets, _) => {
|
||||||
if let Some(set) = sets.get_mut(output) {
|
if let Some(set) = sets.get_mut(output) {
|
||||||
set.activate(idx, &mut self.workspace_state.update());
|
set.activate(idx, &mut self.workspace_state.update())?
|
||||||
|
} else {
|
||||||
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WorkspaceMode::Global(set) => {
|
WorkspaceMode::Global(set) => set.activate(idx, &mut self.workspace_state.update())?,
|
||||||
set.activate(idx, &mut self.workspace_state.update());
|
} {
|
||||||
}
|
let output_geo = output.geometry();
|
||||||
|
Ok(Some(
|
||||||
|
output_geo.loc + Point::from((output_geo.size.w / 2, output_geo.size.h / 2)),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
let output_geo = output.geometry();
|
|
||||||
Some(output_geo.loc + Point::from((output_geo.size.w / 2, output_geo.size.h / 2)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn active_space(&self, output: &Output) -> &Workspace {
|
pub fn active_space(&self, output: &Output) -> &Workspace {
|
||||||
|
|
@ -1254,7 +1275,7 @@ impl Shell {
|
||||||
from_output: &Output,
|
from_output: &Output,
|
||||||
to: (&Output, Option<usize>),
|
to: (&Output, Option<usize>),
|
||||||
follow: bool,
|
follow: bool,
|
||||||
) -> Option<Point<i32, Logical>> {
|
) -> 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);
|
||||||
if state
|
if state
|
||||||
|
|
@ -1264,20 +1285,20 @@ impl Shell {
|
||||||
.get(to_idx, to_output)
|
.get(to_idx, to_output)
|
||||||
.is_none()
|
.is_none()
|
||||||
{
|
{
|
||||||
return None;
|
return Err(InvalidWorkspaceIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if from_output == to_output
|
if from_output == to_output
|
||||||
&& to_idx == state.common.shell.workspaces.active_num(from_output).1
|
&& to_idx == state.common.shell.workspaces.active_num(from_output).1
|
||||||
{
|
{
|
||||||
return None;
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
let from_workspace = state.common.shell.workspaces.active_mut(from_output);
|
let from_workspace = state.common.shell.workspaces.active_mut(from_output);
|
||||||
let maybe_window = from_workspace.focus_stack.get(seat).last().cloned();
|
let maybe_window = from_workspace.focus_stack.get(seat).last().cloned();
|
||||||
|
|
||||||
let Some(mapped) = maybe_window else { return None; };
|
let Some(mapped) = maybe_window else { return Ok(None); };
|
||||||
let Some(window_state) = from_workspace.unmap(&mapped) else { return None; };
|
let Some(window_state) = from_workspace.unmap(&mapped) else { return Ok(None); };
|
||||||
|
|
||||||
for (toplevel, _) in mapped.windows() {
|
for (toplevel, _) in mapped.windows() {
|
||||||
state
|
state
|
||||||
|
|
@ -1300,7 +1321,7 @@ impl Shell {
|
||||||
}
|
}
|
||||||
let new_pos = if follow {
|
let new_pos = if follow {
|
||||||
seat.set_active_output(&to_output);
|
seat.set_active_output(&to_output);
|
||||||
state.common.shell.activate(to_output, to_idx)
|
state.common.shell.activate(to_output, to_idx)?
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
@ -1345,7 +1366,7 @@ impl Shell {
|
||||||
if follow {
|
if follow {
|
||||||
Common::set_focus(state, Some(&KeyboardFocusTarget::from(mapped)), &seat, None);
|
Common::set_focus(state, Some(&KeyboardFocusTarget::from(mapped)), &seat, None);
|
||||||
}
|
}
|
||||||
new_pos
|
Ok(new_pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_reactive_popups(&self, mapped: &CosmicMapped) {
|
pub fn update_reactive_popups(&self, mapped: &CosmicMapped) {
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ impl ToplevelManagementHandler for State {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.clone();
|
.clone();
|
||||||
|
|
||||||
self.common.shell.activate(&output, idx as usize);
|
let _ = self.common.shell.activate(&output, idx as usize); // TODO: Move pointer?
|
||||||
mapped.focus_window(window);
|
mapped.focus_window(window);
|
||||||
Common::set_focus(self, Some(&mapped.clone().into()), &seat, None);
|
Common::set_focus(self, Some(&mapped.clone().into()), &seat, None);
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ impl WorkspaceHandler for State {
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some((output, idx)) = maybe {
|
if let Some((output, idx)) = maybe {
|
||||||
self.common.shell.activate(&output, idx);
|
let _ = self.common.shell.activate(&output, idx); // TODO: move cursor?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue