diff --git a/data/keybindings.ron b/data/keybindings.ron index 84981e6f..68970595 100644 --- a/data/keybindings.ron +++ b/data/keybindings.ron @@ -5,6 +5,25 @@ (modifiers: [Super], key: "Escape"): System(LockScreen), (modifiers: [Super], key: "q"): Close, + (modifiers: [Super], key: "Left"): Focus(Left), + (modifiers: [Super], key: "Right"): Focus(Right), + (modifiers: [Super], key: "Up"): Focus(Up), + (modifiers: [Super], key: "Down"): Focus(Down), + (modifiers: [Super], key: "h"): Focus(Left), + (modifiers: [Super], key: "j"): Focus(Down), + (modifiers: [Super], key: "k"): Focus(Up), + (modifiers: [Super], key: "l"): Focus(Right), + (modifiers: [Super], key: "u"): Focus(Out), + (modifiers: [Super], key: "i"): Focus(In), + (modifiers: [Super, Shift], key: "Left"): Move(Left), + (modifiers: [Super, Shift], key: "Right"): Move(Right), + (modifiers: [Super, Shift], key: "Up"): Move(Up), + (modifiers: [Super, Shift], key: "Down"): Move(Down), + (modifiers: [Super, Shift], key: "h"): Move(Left), + (modifiers: [Super, Shift], key: "j"): Move(Down), + (modifiers: [Super, Shift], key: "k"): Move(Up), + (modifiers: [Super, Shift], key: "l"): Move(Right), + (modifiers: [Super], key: "1"): Workspace(1), (modifiers: [Super], key: "2"): Workspace(2), (modifiers: [Super], key: "3"): Workspace(3), @@ -26,39 +45,39 @@ (modifiers: [Super, Shift], key: "9"): MoveToWorkspace(9), (modifiers: [Super, Shift], key: "0"): MoveToLastWorkspace, - (modifiers: [Super, Ctrl, Alt], key: "Left"): MoveToOutput(Left), - (modifiers: [Super, Ctrl, Alt], key: "Down"): MoveToOutput(Down), - (modifiers: [Super, Ctrl, Alt], key: "Up"): MoveToOutput(Up), - (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, Ctrl], key: "Left"): PreviousWorkspace, + (modifiers: [Super, Ctrl], key: "Down"): NextWorkspace, + (modifiers: [Super, Ctrl], key: "Up"): PreviousWorkspace, + (modifiers: [Super, Ctrl], key: "Right"): NextWorkspace, + (modifiers: [Super, Ctrl], key: "h"): PreviousWorkspace, + (modifiers: [Super, Ctrl], key: "k"): NextWorkspace, + (modifiers: [Super, Ctrl], key: "j"): PreviousWorkspace, + (modifiers: [Super, Ctrl], key: "l"): NextWorkspace, + (modifiers: [Super, Shift, Ctrl], key: "Left"): MoveToPreviousWorkspace, + (modifiers: [Super, Shift, Ctrl], key: "Down"): MoveToNextWorkspace, + (modifiers: [Super, Shift, Ctrl], key: "Up"): MoveToPreviousWorkspace, + (modifiers: [Super, Shift, Ctrl], key: "Right"): MoveToNextWorkspace, + (modifiers: [Super, Shift, Ctrl], key: "h"): MoveToPreviousWorkspace, + (modifiers: [Super, Shift, Ctrl], key: "k"): MoveToNextWorkspace, + (modifiers: [Super, Shift, Ctrl], key: "j"): MoveToPreviousWorkspace, + (modifiers: [Super, Shift, Ctrl], key: "l"): MoveToNextWorkspace, - (modifiers: [Super], key: "Period"): NextOutput, - (modifiers: [Super], key: "Comma"): PreviousOutput, - (modifiers: [Super, Shift], key: "Period"): MoveToNextOutput, - (modifiers: [Super, Shift], key: "Comma"): MoveToPreviousOutput, - - (modifiers: [Super], key: "Left"): Focus(Left), - (modifiers: [Super], key: "Right"): Focus(Right), - (modifiers: [Super], key: "Up"): Focus(Up), - (modifiers: [Super], key: "Down"): Focus(Down), - (modifiers: [Super], key: "h"): Focus(Left), - (modifiers: [Super], key: "j"): Focus(Down), - (modifiers: [Super], key: "k"): Focus(Up), - (modifiers: [Super], key: "l"): Focus(Right), - (modifiers: [Super], key: "u"): Focus(Out), - (modifiers: [Super], key: "i"): Focus(In), - - (modifiers: [Super, Shift], key: "Left"): Move(Left), - (modifiers: [Super, Shift], key: "Right"): Move(Right), - (modifiers: [Super, Shift], key: "Up"): Move(Up), - (modifiers: [Super, Shift], key: "Down"): Move(Down), - (modifiers: [Super, Shift], key: "h"): Move(Left), - (modifiers: [Super, Shift], key: "j"): Move(Down), - (modifiers: [Super, Shift], key: "k"): Move(Up), - (modifiers: [Super, Shift], key: "l"): Move(Right), + (modifiers: [Super, Alt], key: "Left"): SwitchOutput(Left), + (modifiers: [Super, Alt], key: "Down"): SwitchOutput(Down), + (modifiers: [Super, Alt], key: "Up"): SwitchOutput(Up), + (modifiers: [Super, Alt], key: "Right"): SwitchOutput(Right), + (modifiers: [Super, Alt], key: "h"): SwitchOutput(Left), + (modifiers: [Super, Alt], key: "k"): SwitchOutput(Down), + (modifiers: [Super, Alt], key: "j"): SwitchOutput(Up), + (modifiers: [Super, Alt], key: "l"): SwitchOutput(Right), + (modifiers: [Super, Shift, Alt], key: "Left"): MoveToOutput(Left), + (modifiers: [Super, Shift, Alt], key: "Down"): MoveToOutput(Down), + (modifiers: [Super, Shift, Alt], key: "Up"): MoveToOutput(Up), + (modifiers: [Super, Shift, Alt], key: "Right"): MoveToOutput(Right), + (modifiers: [Super, Shift, Alt], key: "h"): MoveToOutput(Left), + (modifiers: [Super, Shift, Alt], key: "k"): MoveToOutput(Down), + (modifiers: [Super, Shift, Alt], key: "j"): MoveToOutput(Up), + (modifiers: [Super, Shift, Alt], key: "l"): MoveToOutput(Right), (modifiers: [Super], key: "o"): ToggleOrientation, (modifiers: [Super], key: "s"): ToggleStacking, @@ -72,6 +91,8 @@ (modifiers: [Super], key: "equal"): ZoomIn, (modifiers: [Super], key: "minus"): ZoomOut, + (modifiers: [Super], key: "Period"): ZoomIn, + (modifiers: [Super], key: "Comma"): ZoomOut, (modifiers: [Super], key: "b"): System(WebBrowser), (modifiers: [Super], key: "f"): System(HomeFolder), diff --git a/src/config/key_bindings.rs b/src/config/key_bindings.rs index 31e858f0..006f1d39 100644 --- a/src/config/key_bindings.rs +++ b/src/config/key_bindings.rs @@ -1,8 +1,6 @@ -use cosmic_comp_config::workspace::WorkspaceLayout; use cosmic_settings_config::shortcuts::State as KeyState; -use cosmic_settings_config::shortcuts::{self, Modifiers, Shortcuts}; +use cosmic_settings_config::shortcuts::{self, Modifiers}; use smithay::input::keyboard::ModifiersState; -use xkbcommon::xkb; #[derive(Clone, Debug, Eq, PartialEq)] pub enum Action { @@ -23,88 +21,6 @@ pub enum PrivateAction { ), } -pub fn add_default_bindings(shortcuts: &mut Shortcuts, workspace_layout: WorkspaceLayout) { - let ( - workspace_previous, - workspace_next, - (output_previous, output_previous_dir), - (output_next, output_next_dir), - ) = match workspace_layout { - WorkspaceLayout::Horizontal => ( - [xkb::Keysym::Left, xkb::Keysym::h], - [xkb::Keysym::Right, xkb::Keysym::l], - ( - [xkb::Keysym::Up, xkb::Keysym::k], - shortcuts::action::Direction::Up, - ), - ( - [xkb::Keysym::Down, xkb::Keysym::j], - shortcuts::action::Direction::Down, - ), - ), - WorkspaceLayout::Vertical => ( - [xkb::Keysym::Up, xkb::Keysym::k], - [xkb::Keysym::Down, xkb::Keysym::j], - ( - [xkb::Keysym::Left, xkb::Keysym::h], - shortcuts::action::Direction::Left, - ), - ( - [xkb::Keysym::Right, xkb::Keysym::l], - shortcuts::action::Direction::Right, - ), - ), - }; - - shortcuts.insert_default_binding( - Modifiers::new().logo().ctrl(), - workspace_previous.iter().copied(), - shortcuts::Action::PreviousWorkspace, - ); - - shortcuts.insert_default_binding( - Modifiers::new().logo().ctrl(), - workspace_next.iter().copied(), - shortcuts::Action::NextWorkspace, - ); - - shortcuts.insert_default_binding( - Modifiers::new().logo().ctrl().shift(), - workspace_previous.iter().copied(), - shortcuts::Action::MoveToPreviousWorkspace, - ); - - shortcuts.insert_default_binding( - Modifiers::new().logo().ctrl().shift(), - workspace_next.iter().copied(), - shortcuts::Action::MoveToNextWorkspace, - ); - - shortcuts.insert_default_binding( - Modifiers::new().logo().ctrl(), - output_previous.iter().copied(), - shortcuts::Action::SwitchOutput(output_previous_dir), - ); - - shortcuts.insert_default_binding( - Modifiers::new().logo().ctrl(), - output_next.iter().copied(), - shortcuts::Action::SwitchOutput(output_next_dir), - ); - - shortcuts.insert_default_binding( - Modifiers::new().logo().ctrl().shift(), - output_previous.iter().copied(), - shortcuts::Action::MoveToOutput(output_previous_dir), - ); - - shortcuts.insert_default_binding( - Modifiers::new().logo().ctrl().shift(), - output_next.iter().copied(), - shortcuts::Action::MoveToOutput(output_next_dir), - ); -} - /// Convert `cosmic_settings_config::shortcuts::State` to `smithay::backend::input::KeyState`. pub fn cosmic_keystate_to_smithay(value: KeyState) -> smithay::backend::input::KeyState { match value { diff --git a/src/config/mod.rs b/src/config/mod.rs index 652d7d4d..03bdacda 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -192,7 +192,6 @@ impl Config { }) .expect("Failed to add cosmic-config to the event loop"); let xdg = xdg::BaseDirectories::new().ok(); - let workspace = get_config::(&config, "workspaces"); let cosmic_comp_config = CosmicCompConfig::get_entry(&config).unwrap_or_else(|(errs, c)| { @@ -241,10 +240,7 @@ impl Config { // Source key bindings from com.system76.CosmicSettings.Shortcuts let settings_context = shortcuts::context().expect("Failed to load shortcuts config"); let system_actions = shortcuts::system_actions(&settings_context); - let mut shortcuts = shortcuts::shortcuts(&settings_context); - - // Add any missing default shortcuts recommended by the compositor. - key_bindings::add_default_bindings(&mut shortcuts, workspace.workspace_layout); + let shortcuts = shortcuts::shortcuts(&settings_context); // Listen for updates to the keybindings config. match cosmic_config::calloop::ConfigWatchSource::new(&settings_context) { @@ -254,11 +250,7 @@ impl Config { match key.as_str() { // Reload the keyboard shortcuts config. "custom" | "defaults" => { - let mut shortcuts = shortcuts::shortcuts(&config); - let layout = get_config::(&config, "workspaces") - .workspace_layout; - key_bindings::add_default_bindings(&mut shortcuts, layout); - state.common.config.shortcuts = shortcuts; + state.common.config.shortcuts = shortcuts::shortcuts(&config); } "system_actions" => { diff --git a/src/input/actions.rs b/src/input/actions.rs index a1c0820e..0d326649 100644 --- a/src/input/actions.rs +++ b/src/input/actions.rs @@ -28,6 +28,13 @@ use std::{os::unix::process::CommandExt, thread, time::Duration}; use super::gestures; +fn propagate_by_default(action: &shortcuts::Action) -> bool { + match action { + shortcuts::Action::Focus(_) | shortcuts::Action::Move(_) => true, + _ => false, + } +} + impl State { pub fn handle_action( &mut self, @@ -37,7 +44,6 @@ impl State { time: u32, pattern: shortcuts::Binding, direction: Option, - propagate: bool, ) { // TODO: Detect if started from login manager or tty, and only allow // `Terminate` if it will return to login manager. @@ -52,9 +58,12 @@ impl State { } match action { - Action::Shortcut(action) => self - .handle_shortcut_action(action, seat, serial, time, pattern, direction, propagate), - + Action::Shortcut(action) => { + let propagate = propagate_by_default(&action); + self.handle_shortcut_action( + action, seat, serial, time, pattern, direction, propagate, + ) + } Action::Private(PrivateAction::Escape) => { { let mut shell = self.common.shell.write().unwrap(); @@ -184,16 +193,40 @@ impl State { } Action::NextWorkspace => { + if let Some(direction) = pattern.inferred_direction() { + if ((direction == Direction::Left || direction == Direction::Right) + && self.common.config.cosmic_conf.workspaces.workspace_layout + == WorkspaceLayout::Vertical) + || ((direction == Direction::Up || direction == Direction::Down) + && self.common.config.cosmic_conf.workspaces.workspace_layout + == WorkspaceLayout::Horizontal) + { + return; + } + } + let next = to_next_workspace( &mut *self.common.shell.write().unwrap(), seat, false, &mut self.common.workspace_state.update(), ); - if next.is_err() && propagate { - if let Some(inferred) = pattern.inferred_direction() { + if next.is_err() { + if propagate { + if let Some(inferred) = pattern.inferred_direction() { + self.handle_shortcut_action( + Action::SwitchOutput(inferred), + seat, + serial, + time, + pattern, + direction, + false, + ) + }; + } else { self.handle_shortcut_action( - Action::SwitchOutput(inferred), + Action::Workspace(1), seat, serial, time, @@ -201,21 +234,45 @@ impl State { direction, false, ) - }; + } } } Action::PreviousWorkspace => { + if let Some(direction) = pattern.inferred_direction() { + if ((direction == Direction::Left || direction == Direction::Right) + && self.common.config.cosmic_conf.workspaces.workspace_layout + == WorkspaceLayout::Vertical) + || ((direction == Direction::Up || direction == Direction::Down) + && self.common.config.cosmic_conf.workspaces.workspace_layout + == WorkspaceLayout::Horizontal) + { + return; + } + } + let previous = to_previous_workspace( &mut *self.common.shell.write().unwrap(), seat, false, &mut self.common.workspace_state.update(), ); - if previous.is_err() && propagate { - if let Some(inferred) = pattern.inferred_direction() { + if previous.is_err() { + if propagate { + if let Some(inferred) = pattern.inferred_direction() { + self.handle_shortcut_action( + Action::SwitchOutput(inferred), + seat, + serial, + time, + pattern, + direction, + false, + ) + }; + } else { self.handle_shortcut_action( - Action::SwitchOutput(inferred), + Action::LastWorkspace, seat, serial, time, @@ -223,7 +280,7 @@ impl State { direction, false, ) - }; + } } } @@ -284,24 +341,39 @@ impl State { } x @ Action::MoveToNextWorkspace | x @ Action::SendToNextWorkspace => { + if let Some(direction) = pattern.inferred_direction() { + if ((direction == Direction::Left || direction == Direction::Right) + && self.common.config.cosmic_conf.workspaces.workspace_layout + == WorkspaceLayout::Vertical) + || ((direction == Direction::Up || direction == Direction::Down) + && self.common.config.cosmic_conf.workspaces.workspace_layout + == WorkspaceLayout::Horizontal) + { + return; + } + } let Some(focused_output) = seat.focused_output() else { return; }; + let res = { let mut shell = self.common.shell.write().unwrap(); - let workspace = shell + shell .workspaces .active_num(&focused_output) .1 - .saturating_add(1); - shell.move_current_window( - seat, - &focused_output, - (&focused_output, Some(workspace)), - matches!(x, Action::MoveToNextWorkspace), - direction, - &mut self.common.workspace_state.update(), - ) + .checked_add(1) + .ok_or(InvalidWorkspaceIndex) + .and_then(|workspace| { + shell.move_current_window( + seat, + &focused_output, + (&focused_output, Some(workspace)), + matches!(x, Action::MoveToNextWorkspace), + direction, + &mut self.common.workspace_state.update(), + ) + }) }; match res { @@ -315,6 +387,7 @@ impl State { matches!(x, Action::MoveToNextWorkspace), ); } + Ok(None) => {} Err(_) if propagate => { if let Some(inferred) = pattern.inferred_direction() { self.handle_shortcut_action( @@ -332,30 +405,59 @@ impl State { ) } } - _ => {} + Err(_) => { + // cycle through + self.handle_shortcut_action( + if matches!(x, Action::MoveToNextWorkspace) { + Action::MoveToWorkspace(1) + } else { + Action::SendToWorkspace(1) + }, + seat, + serial, + time, + pattern, + direction, + false, + ) + } } } x @ Action::MoveToPreviousWorkspace | x @ Action::SendToPreviousWorkspace => { + if let Some(direction) = pattern.inferred_direction() { + if ((direction == Direction::Left || direction == Direction::Right) + && self.common.config.cosmic_conf.workspaces.workspace_layout + == WorkspaceLayout::Vertical) + || ((direction == Direction::Up || direction == Direction::Down) + && self.common.config.cosmic_conf.workspaces.workspace_layout + == WorkspaceLayout::Horizontal) + { + return; + } + } let Some(focused_output) = seat.focused_output() else { return; }; + let res = { let mut shell = self.common.shell.write().unwrap(); - let workspace = shell + shell .workspaces .active_num(&focused_output) .1 - .saturating_sub(1); - // TODO: Possibly move to prev output, if idx < 0 - shell.move_current_window( - seat, - &focused_output, - (&focused_output, Some(workspace)), - matches!(x, Action::MoveToPreviousWorkspace), - direction, - &mut self.common.workspace_state.update(), - ) + .checked_sub(1) + .ok_or(InvalidWorkspaceIndex) + .and_then(|workspace| { + shell.move_current_window( + seat, + &focused_output, + (&focused_output, Some(workspace)), + matches!(x, Action::MoveToPreviousWorkspace), + direction, + &mut self.common.workspace_state.update(), + ) + }) }; match res { @@ -368,6 +470,7 @@ impl State { matches!(x, Action::MoveToPreviousWorkspace), ); } + Ok(None) => {} Err(_) if propagate => { if let Some(inferred) = pattern.inferred_direction() { self.handle_shortcut_action( @@ -385,7 +488,22 @@ impl State { ) } } - _ => {} + Err(_) => { + // cycle through + self.handle_shortcut_action( + if matches!(x, Action::MoveToPreviousWorkspace) { + Action::MoveToLastWorkspace + } else { + Action::SendToLastWorkspace + }, + seat, + serial, + time, + pattern, + direction, + false, + ) + } } } @@ -441,155 +559,15 @@ impl State { ptr.frame(self); } } - } else if propagate { - std::mem::drop(shell); - - let action = match ( - direction, - self.common.config.cosmic_conf.workspaces.workspace_layout, - ) { - (Direction::Left, WorkspaceLayout::Horizontal) - | (Direction::Up, WorkspaceLayout::Vertical) => { - Some(Action::PreviousWorkspace) - } - (Direction::Right, WorkspaceLayout::Horizontal) - | (Direction::Down, WorkspaceLayout::Vertical) => { - Some(Action::NextWorkspace) - } - _ => None, - }; - - if let Some(action) = action { - self.handle_shortcut_action( - action, - seat, - serial, - time, - pattern, - Some(direction), - false, - ) - } } } Action::NextOutput => { - let current_output = seat.active_output(); - let mut shell = self.common.shell.write().unwrap(); - - let next_output = shell - .outputs() - .skip_while(|o| *o != ¤t_output) - .skip(1) - .next() - .cloned(); - if let Some(next_output) = next_output { - let idx = shell.workspaces.active_num(&next_output).1; - let res = shell.activate( - &next_output, - idx, - WorkspaceDelta::new_shortcut(), - &mut self.common.workspace_state.update(), - ); - seat.set_active_output(&next_output); - - if let Ok(Some(new_pos)) = res { - let new_target = shell - .workspaces - .active(&next_output) - .unwrap() - .1 - .focus_stack - .get(&seat) - .last() - .cloned() - .map(KeyboardFocusTarget::from); - std::mem::drop(shell); - - let move_cursor = if let Some(under) = new_target { - let update_cursor = self.common.config.cosmic_conf.focus_follows_cursor; - Shell::set_focus(self, Some(&under), seat, None, update_cursor); - !update_cursor - } else { - true - }; - - if let Some(ptr) = seat.get_pointer() { - if move_cursor { - ptr.motion( - self, - None, - &MotionEvent { - location: new_pos.to_f64().as_logical(), - serial, - time, - }, - ); - } - ptr.frame(self); - } - } - } + warn!("Skipping deprecated shortcut NextOutput"); } Action::PreviousOutput => { - let current_output = seat.active_output(); - let mut shell = self.common.shell.write().unwrap(); - - let prev_output = shell - .outputs() - .rev() - .skip_while(|o| *o != ¤t_output) - .skip(1) - .next() - .cloned(); - if let Some(prev_output) = prev_output { - let idx = shell.workspaces.active_num(&prev_output).1; - let res = shell.activate( - &prev_output, - idx, - WorkspaceDelta::new_shortcut(), - &mut self.common.workspace_state.update(), - ); - seat.set_active_output(&prev_output); - - if let Ok(Some(new_pos)) = res { - let new_target = shell - .workspaces - .active(&prev_output) - .unwrap() - .1 - .focus_stack - .get(&seat) - .last() - .cloned() - .map(KeyboardFocusTarget::from); - std::mem::drop(shell); - - let move_cursor = if let Some(under) = new_target { - let update_cursor = self.common.config.cosmic_conf.focus_follows_cursor; - Shell::set_focus(self, Some(&under), seat, None, update_cursor); - !update_cursor - } else { - true - }; - - if let Some(ptr) = seat.get_pointer() { - if move_cursor { - ptr.motion( - self, - None, - &MotionEvent { - location: new_pos.to_f64().as_logical(), - serial, - time, - }, - ); - } - ptr.frame(self); - } - } - } + warn!("Skipping deprecated shortcut PreviousOutput"); } action @ Action::MoveToOutput(_) | action @ Action::SendToOutput(_) => { @@ -631,170 +609,15 @@ impl State { ptr.frame(self); } } - } else if propagate { - std::mem::drop(shell); - match ( - direction, - self.common.config.cosmic_conf.workspaces.workspace_layout, - ) { - (Direction::Left, WorkspaceLayout::Horizontal) - | (Direction::Up, WorkspaceLayout::Vertical) => self - .handle_shortcut_action( - Action::MoveToPreviousWorkspace, - seat, - serial, - time, - pattern, - Some(direction), - false, - ), - (Direction::Right, WorkspaceLayout::Horizontal) - | (Direction::Down, WorkspaceLayout::Vertical) => self - .handle_shortcut_action( - Action::MoveToNextWorkspace, - seat, - serial, - time, - pattern, - Some(direction), - false, - ), - - _ => {} - } } } - x @ Action::MoveToNextOutput | x @ Action::SendToNextOutput => { - let Some(focused_output) = seat.focused_output() else { - return; - }; - let mut shell = self.common.shell.write().unwrap(); - - let next_output = shell - .outputs() - .skip_while(|o| *o != &focused_output) - .skip(1) - .next() - .cloned(); - if let Some(next_output) = next_output { - let res = shell.move_current_window( - seat, - &focused_output, - (&next_output, None), - matches!(x, Action::MoveToNextOutput), - direction, - &mut self.common.workspace_state.update(), - ); - if let Ok(Some((target, new_pos))) = res { - std::mem::drop(shell); - Shell::set_focus( - self, - Some(&target), - seat, - None, - matches!(x, Action::MoveToNextOutput), - ); - if let Some(ptr) = seat.get_pointer() { - ptr.motion( - self, - None, - &MotionEvent { - location: new_pos.to_f64().as_logical(), - serial, - time, - }, - ); - ptr.frame(self); - } - } - } + Action::MoveToNextOutput | Action::SendToNextOutput => { + warn!("Ignoring deprecated action Move/SendToNextOutput"); } - x @ Action::MoveToPreviousOutput | x @ Action::SendToPreviousOutput => { - let Some(focused_output) = seat.focused_output() else { - return; - }; - let mut shell = self.common.shell.write().unwrap(); - - let prev_output = shell - .outputs() - .rev() - .skip_while(|o| *o != &focused_output) - .skip(1) - .next() - .cloned(); - if let Some(prev_output) = prev_output { - let res = shell.move_current_window( - seat, - &focused_output, - (&prev_output, None), - matches!(x, Action::MoveToPreviousOutput), - direction, - &mut self.common.workspace_state.update(), - ); - if let Ok(Some((target, new_pos))) = res { - std::mem::drop(shell); - Shell::set_focus( - self, - Some(&target), - seat, - None, - matches!(x, Action::MoveToPreviousOutput), - ); - if let Some(ptr) = seat.get_pointer() { - ptr.motion( - self, - None, - &MotionEvent { - location: new_pos.to_f64().as_logical(), - serial, - time, - }, - ); - ptr.frame(self); - } - } - } - } - - Action::MigrateWorkspaceToNextOutput => { - let active_output = seat.active_output(); - let (active, next_output) = { - let shell = self.common.shell.read().unwrap(); - let output = shell - .outputs() - .skip_while(|o| *o != &active_output) - .skip(1) - .next() - .cloned(); - - (shell.active_space(&active_output).unwrap().handle, output) - }; - if let Some(next_output) = next_output { - self.common - .migrate_workspace(&active_output, &next_output, &active); - } - } - - Action::MigrateWorkspaceToPreviousOutput => { - let active_output = seat.active_output(); - let (active, prev_output) = { - let shell = self.common.shell.read().unwrap(); - let output = shell - .outputs() - .rev() - .skip_while(|o| *o != &active_output) - .skip(1) - .next() - .cloned(); - - (shell.active_space(&active_output).unwrap().handle, output) - }; - if let Some(prev_output) = prev_output { - self.common - .migrate_workspace(&active_output, &prev_output, &active); - } + Action::MoveToPreviousOutput | Action::SendToPreviousOutput => { + warn!("Ignoring deprecated action Move/SendToPreviousOutput"); } Action::MigrateWorkspaceToOutput(direction) => { @@ -814,6 +637,14 @@ impl State { } } + Action::MigrateWorkspaceToNextOutput => { + warn!("Ignoring deprecated action MigrateWorkspaceToNextOutput"); + } + + Action::MigrateWorkspaceToPreviousOutput => { + warn!("Ignoring deprecated action MigrateWorkspaceToPreviousOutput"); + } + Action::Focus(focus) => { let result = self.common.shell.read().unwrap().next_focus(focus, seat); @@ -828,8 +659,23 @@ impl State { }; if let Some(direction) = dir { + let action = match ( + direction, + self.common.config.cosmic_conf.workspaces.workspace_layout, + ) { + (Direction::Left, WorkspaceLayout::Horizontal) + | (Direction::Up, WorkspaceLayout::Vertical) => { + Action::PreviousWorkspace + } + (Direction::Right, WorkspaceLayout::Horizontal) + | (Direction::Down, WorkspaceLayout::Vertical) => { + Action::NextWorkspace + } + _ => Action::SwitchOutput(direction), + }; + self.handle_shortcut_action( - Action::SwitchOutput(direction), + action, seat, serial, time, @@ -854,15 +700,32 @@ impl State { .unwrap() .move_current_element(direction, seat); match res { - MoveResult::MoveFurther(_move_further) => self.handle_shortcut_action( - Action::MoveToOutput(direction), - seat, - serial, - time, - pattern, - Some(direction), - true, - ), + MoveResult::MoveFurther(_move_further) => { + let action = match ( + direction, + self.common.config.cosmic_conf.workspaces.workspace_layout, + ) { + (Direction::Left, WorkspaceLayout::Horizontal) + | (Direction::Up, WorkspaceLayout::Vertical) => { + Action::MoveToPreviousWorkspace + } + (Direction::Right, WorkspaceLayout::Horizontal) + | (Direction::Down, WorkspaceLayout::Vertical) => { + Action::MoveToNextWorkspace + } + _ => Action::MoveToOutput(direction), + }; + + self.handle_shortcut_action( + action, + seat, + serial, + time, + pattern, + Some(direction), + true, + ) + } MoveResult::ShiftFocus(shift) => { Shell::set_focus(self, Some(&shift), seat, None, true); } @@ -1159,7 +1022,8 @@ fn to_next_workspace( .workspaces .active_num(¤t_output) .1 - .saturating_add(1); + .checked_add(1) + .ok_or(InvalidWorkspaceIndex)?; shell.activate( ¤t_output, @@ -1184,7 +1048,8 @@ fn to_previous_workspace( .workspaces .active_num(¤t_output) .1 - .saturating_sub(1); + .checked_sub(1) + .ok_or(InvalidWorkspaceIndex)?; shell.activate( ¤t_output, diff --git a/src/input/mod.rs b/src/input/mod.rs index bfac811d..9f3dca2b 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -250,7 +250,7 @@ impl State { FilterResult::<()>::Forward }); } - self.handle_action(action, &seat, serial, time, pattern, None, true) + self.handle_action(action, &seat, serial, time, pattern, None) } // If we want to track numlock state so it can be reused on the next boot... @@ -1639,7 +1639,6 @@ impl State { time.overflowing_add(duration as u32).0, key_pattern_clone.clone(), None, - true, ); calloop::timer::TimeoutAction::ToDuration(Duration::from_millis(25)) }, diff --git a/src/shell/mod.rs b/src/shell/mod.rs index c5ba4bc1..98af0027 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -2653,11 +2653,27 @@ impl Shell { ) -> Result)>, InvalidWorkspaceIndex> { let (to_output, to_idx) = to; let to_idx = to_idx.unwrap_or(self.workspaces.active_num(to_output).1); + let from_idx = self.workspaces.active_num(from_output).1; if from_output == to_output && to_idx == self.workspaces.active_num(from_output).1 { return Ok(None); } + if from_output == to_output + && to_idx.checked_sub(1).is_some_and(|idx| idx == from_idx) + && to_idx == self.workspaces.len(to_output) - 1 + && self + .workspaces + .get(from_idx, from_output) + .is_some_and(|w| w.mapped().count() == 1) + && self + .workspaces + .get(to_idx, to_output) + .is_some_and(|w| w.is_empty()) + { + return Err(InvalidWorkspaceIndex); + } + let to = self .workspaces .get(to_idx, to_output)