From 544acecd2e5431dd3e177ab3f068c76c3b6218d5 Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Thu, 10 Nov 2022 18:42:11 +0100 Subject: [PATCH] input: Various new keybindings --- config.ron | 130 +++++---- src/config/mod.rs | 23 +- src/input/mod.rs | 520 ++++++++++++++++++++------------- src/shell/layout/tiling/mod.rs | 17 +- src/shell/mod.rs | 60 ++-- src/shell/workspace.rs | 6 +- 6 files changed, 476 insertions(+), 280 deletions(-) diff --git a/config.ron b/config.ron index 13e3c72e..c1795c9c 100644 --- a/config.ron +++ b/config.ron @@ -1,57 +1,89 @@ ( key_bindings: { - (modifiers: [Logo, Shift], key: "Escape"): Terminate, - (modifiers: [Logo], key: "Escape"): Debug, - (modifiers: [Logo], key: "q"): Close, - (modifiers: [Logo], key: "1"): Workspace(1), - (modifiers: [Logo], key: "2"): Workspace(2), - (modifiers: [Logo], key: "3"): Workspace(3), - (modifiers: [Logo], key: "4"): Workspace(4), - (modifiers: [Logo], key: "5"): Workspace(5), - (modifiers: [Logo], key: "6"): Workspace(6), - (modifiers: [Logo], key: "7"): Workspace(7), - (modifiers: [Logo], key: "8"): Workspace(8), - (modifiers: [Logo], key: "9"): Workspace(9), - (modifiers: [Logo], key: "0"): Workspace(0), - (modifiers: [Logo, Shift], key: "1"): MoveToWorkspace(1), - (modifiers: [Logo, Shift], key: "2"): MoveToWorkspace(2), - (modifiers: [Logo, Shift], key: "3"): MoveToWorkspace(3), - (modifiers: [Logo, Shift], key: "4"): MoveToWorkspace(4), - (modifiers: [Logo, Shift], key: "5"): MoveToWorkspace(5), - (modifiers: [Logo, Shift], key: "6"): MoveToWorkspace(6), - (modifiers: [Logo, Shift], key: "7"): MoveToWorkspace(7), - (modifiers: [Logo, Shift], key: "8"): MoveToWorkspace(8), - (modifiers: [Logo, Shift], key: "9"): MoveToWorkspace(9), - (modifiers: [Logo, Shift], key: "0"): MoveToWorkspace(0), - (modifiers: [Logo], key: "Left"): Focus(Left), - (modifiers: [Logo], key: "Right"): Focus(Right), - (modifiers: [Logo], key: "Up"): Focus(Up), - (modifiers: [Logo], key: "Down"): Focus(Down), - (modifiers: [Logo], key: "h"): Focus(Left), - (modifiers: [Logo], key: "j"): Focus(Down), - (modifiers: [Logo], key: "k"): Focus(Up), - (modifiers: [Logo], key: "l"): Focus(Right), - (modifiers: [Logo, Shift], key: "Left"): Move(Left), - (modifiers: [Logo, Shift], key: "Right"): Move(Right), - (modifiers: [Logo, Shift], key: "Up"): Move(Up), - (modifiers: [Logo, Shift], key: "Down"): Move(Down), - (modifiers: [Logo, Shift], key: "h"): Move(Left), - (modifiers: [Logo, Shift], key: "j"): Move(Down), - (modifiers: [Logo, Shift], key: "k"): Move(Up), - (modifiers: [Logo, Shift], key: "l"): Move(Right), - (modifiers: [Logo], key: "o"): ToggleOrientation, - (modifiers: [Logo], key: "y"): ToggleTiling, - (modifiers: [Logo], key: "g"): ToggleWindowFloating, - (modifiers: [Logo, Shift], key: "f"): Fullscreen, - //(modifiers: [Logo, Shift], key: "s"): Screenshot, + (modifiers: [Super, Shift], key: "Escape"): Terminate, + (modifiers: [Super], key: "Escape"): Debug, + (modifiers: [Super], key: "q"): Close, + + (modifiers: [Super], key: "1"): Workspace(1), + (modifiers: [Super], key: "2"): Workspace(2), + (modifiers: [Super], key: "3"): Workspace(3), + (modifiers: [Super], key: "4"): Workspace(4), + (modifiers: [Super], key: "5"): Workspace(5), + (modifiers: [Super], key: "6"): Workspace(6), + (modifiers: [Super], key: "7"): Workspace(7), + (modifiers: [Super], key: "8"): Workspace(8), + (modifiers: [Super], key: "9"): Workspace(9), + (modifiers: [Super], key: "0"): LastWorkspace, + (modifiers: [Super, Shift], key: "1"): MoveToWorkspace(1), + (modifiers: [Super, Shift], key: "2"): MoveToWorkspace(2), + (modifiers: [Super, Shift], key: "3"): MoveToWorkspace(3), + (modifiers: [Super, Shift], key: "4"): MoveToWorkspace(4), + (modifiers: [Super, Shift], key: "5"): MoveToWorkspace(5), + (modifiers: [Super, Shift], key: "6"): MoveToWorkspace(6), + (modifiers: [Super, Shift], key: "7"): MoveToWorkspace(7), + (modifiers: [Super, Shift], key: "8"): MoveToWorkspace(8), + (modifiers: [Super, Shift], key: "9"): MoveToWorkspace(9), + (modifiers: [Super, Shift], key: "0"): MoveToLastWorkspace, + + // TODO: Depends on workspace orientation + (modifiers: [Super, Ctrl], key: "Right"): NextWorkspace, + (modifiers: [Super, Ctrl], key: "Left"): PreviousWorkspace, + (modifiers: [Super, Ctrl, Shift], key: "Right"): MoveToNextWorkspace, + (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: "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, 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: "o"): ToggleOrientation, + + (modifiers: [Super], key: "y"): ToggleTiling, + (modifiers: [Super], key: "g"): ToggleWindowFloating, + + (modifiers: [Super], key: "m"): Maximize, + //TODO: ability to select default web browser - (modifiers: [Logo], key: "b"): Spawn("firefox"), + (modifiers: [Super], key: "b"): Spawn("firefox"), //TODO: ability to select default file browser - (modifiers: [Logo], key: "f"): Spawn("nautilus"), + (modifiers: [Super], key: "f"): Spawn("nautilus"), //TODO: ability to select default terminal - (modifiers: [Logo], key: "t"): Spawn("gnome-terminal"), - (modifiers: [Logo], key: "a"): Spawn("busctl --user call com.system76.CosmicAppletHost /com/system76/CosmicAppletHost com.system76.CosmicAppletHost Toggle s 'com.system76.CosmicAppLibrary'"), - (modifiers: [Logo], key: "slash"): Spawn("busctl --user call com.system76.CosmicAppletHost /com/system76/CosmicAppletHost com.system76.CosmicAppletHost Toggle s 'com.system76.CosmicLauncher'"), + (modifiers: [Super], key: "t"): Spawn("gnome-terminal"), + + (modifiers: [Super], key: "a"): Spawn("busctl --user call com.system76.CosmicAppletHost /com/system76/CosmicAppletHost com.system76.CosmicAppletHost Toggle s 'com.system76.CosmicAppLibrary'"), + (modifiers: [Super], key: "slash"): Spawn("busctl --user call com.system76.CosmicAppletHost /com/system76/CosmicAppletHost com.system76.CosmicAppletHost Toggle s 'com.system76.CosmicLauncher'"), + (modifiers: [], key: "XF86AudioRaiseVolume"): Spawn("amixer sset Master 5%+"), (modifiers: [], key: "XF86AudioLowerVolume"): Spawn("amixer sset Master 5%-"), (modifiers: [], key: "XF86AudioMute"): Spawn("amixer sset Master toggle"), diff --git a/src/config/mod.rs b/src/config/mod.rs index 340c4977..16dd0f23 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -691,7 +691,7 @@ pub enum KeyModifier { Ctrl, Alt, Shift, - Logo, + Super, CapsLock, NumLock, } @@ -723,7 +723,7 @@ impl std::ops::AddAssign for KeyModifiers { KeyModifier::Ctrl => self.ctrl = true, KeyModifier::Alt => self.alt = true, KeyModifier::Shift => self.shift = true, - KeyModifier::Logo => self.logo = true, + KeyModifier::Super => self.logo = true, KeyModifier::CapsLock => self.caps_lock = true, KeyModifier::NumLock => self.num_lock = true, }; @@ -782,15 +782,30 @@ pub enum Action { Terminate, Debug, Close, + Workspace(u8), + NextWorkspace, + PreviousWorkspace, + LastWorkspace, MoveToWorkspace(u8), + MoveToNextWorkspace, + MoveToPreviousWorkspace, + MoveToLastWorkspace, + + NextOutput, + PreviousOutput, + MoveToNextOutput, + MoveToPreviousOutput, + Focus(FocusDirection), Move(Direction), + ToggleOrientation, Orientation(crate::shell::layout::Orientation), + ToggleTiling, ToggleWindowFloating, - Fullscreen, - //Screenshot, + + Maximize, Spawn(String), } diff --git a/src/input/mod.rs b/src/input/mod.rs index de70aaf5..ee60d2de 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -2,7 +2,14 @@ use crate::{ config::{Action, Config}, - shell::{focus::target::PointerFocusTarget, layout::floating::SeatMoveGrabState, Workspace}, // shell::grabs::SeatMoveGrabState + shell::{ + focus::{target::PointerFocusTarget, FocusDirection}, + layout::{ + floating::SeatMoveGrabState, + tiling::{Direction, FocusResult}, + }, + Workspace, + }, // shell::grabs::SeatMoveGrabState state::Common, utils::prelude::*, wayland::{handlers::screencopy::ScreencopySessions, protocols::screencopy::Session}, @@ -301,206 +308,7 @@ impl State { ) .flatten() { - match action { - Action::Terminate => { - self.common.should_stop = true; - } - #[cfg(feature = "debug")] - Action::Debug => { - self.common.egui.active = !self.common.egui.active; - } - #[cfg(not(feature = "debug"))] - Action::Debug => { - slog_scope::info!("Debug overlay not included in this version") - } - Action::Close => { - let current_output = seat.active_output(); - let workspace = - self.common.shell.active_space_mut(¤t_output); - if let Some(window) = workspace.focus_stack.get(seat).last() { - window.send_close(); - } - } - Action::Workspace(key_num) => { - let current_output = seat.active_output(); - let workspace = match key_num { - 0 => 9, - x => x - 1, - }; - if let Some(motion_event) = self - .common - .shell - .activate(¤t_output, workspace as usize) - { - if let Some(ptr) = seat.get_pointer() { - ptr.motion(self, None, &motion_event); - } - } - } - Action::MoveToWorkspace(key_num) => { - let current_output = seat.active_output(); - let workspace = match key_num { - 0 => 9, - x => x - 1, - }; - Shell::move_current_window( - self, - seat, - ¤t_output, - workspace as usize, - ); - } - Action::Focus(focus) => { - let current_output = seat.active_output(); - let workspace = - self.common.shell.active_space_mut(¤t_output); - let focus_stack = workspace.focus_stack.get(seat); - if let Some(target) = workspace.tiling_layer.next_focus( - focus, - seat, - focus_stack.iter(), - ) { - std::mem::drop(focus_stack); - Common::set_focus(self, Some(&target), seat, None); - } - } - Action::Move(direction) => { - let current_output = seat.active_output(); - let workspace = - self.common.shell.active_space_mut(¤t_output); - if let Some(_move_further) = - workspace.tiling_layer.move_current_window(direction, seat) - { - // TODO moving across workspaces/displays - } - } - Action::Fullscreen => { - let current_output = seat.active_output(); - let workspace = - self.common.shell.active_space_mut(¤t_output); - let focus_stack = workspace.focus_stack.get(seat); - let focused_window = focus_stack.last(); - if let Some(window) = focused_window.map(|f| f.active_window()) - { - workspace.fullscreen_toggle(&window, ¤t_output); - } - } - Action::ToggleOrientation => { - let output = seat.active_output(); - let workspace = self.common.shell.active_space_mut(&output); - let focus_stack = workspace.focus_stack.get(seat); - workspace.tiling_layer.update_orientation( - None, - &seat, - focus_stack.iter(), - ); - } - Action::Orientation(orientation) => { - let output = seat.active_output(); - let workspace = self.common.shell.active_space_mut(&output); - let focus_stack = workspace.focus_stack.get(seat); - workspace.tiling_layer.update_orientation( - Some(orientation), - &seat, - focus_stack.iter(), - ); - } - Action::ToggleTiling => { - let output = seat.active_output(); - let workspace = self.common.shell.active_space_mut(&output); - workspace.toggle_tiling(seat); - } - Action::ToggleWindowFloating => { - let output = seat.active_output(); - let workspace = self.common.shell.active_space_mut(&output); - workspace.toggle_floating_window(seat); - } - Action::Spawn(command) => { - if let Err(err) = std::process::Command::new("/bin/sh") - .arg("-c") - .arg(command) - .env("WAYLAND_DISPLAY", &self.common.socket) - .env_remove("COSMIC_SESSION_SOCK") - .spawn() - { - slog_scope::warn!("Failed to spawn: {}", err); - } - } /* - Action::Screenshot => { - let home = match std::env::var("HOME") { - Ok(home) => home, - Err(err) => { - slog_scope::error!( - "$HOME is not set, can't save screenshots: {}", - err - ); - break; - } - }; - let timestamp = match std::time::SystemTime::UNIX_EPOCH - .elapsed() - { - Ok(duration) => duration.as_secs(), - Err(err) => { - slog_scope::error!("Unable to get timestamp, can't save screenshots: {}", err); - break; - } - }; - for output in self.common.shell.outputs.clone().into_iter() { - match self - .backend - .offscreen_for_output(&output, &mut self.common) - { - Ok((buffer, size)) => { - let mut path = std::path::PathBuf::new(); - path.push(&home); - path.push(format!( - "{}_{}.png", - output.name(), - timestamp - )); - - fn write_png( - path: impl AsRef, - data: Vec, - size: Size, - ) -> anyhow::Result<()> - { - use std::{fs, io}; - - let file = io::BufWriter::new( - fs::File::create(&path)?, - ); - let mut encoder = png::Encoder::new( - file, - size.w as u32, - size.h as u32, - ); - encoder.set_color(png::ColorType::Rgba); - encoder.set_depth(png::BitDepth::Eight); - let mut writer = encoder.write_header()?; - writer.write_image_data(&data)?; - Ok(()) - } - - if let Err(err) = write_png(&path, buffer, size) { - slog_scope::error!( - "Unable to save screenshot at {}: {}", - path.display(), - err - ); - } - } - Err(err) => slog_scope::error!( - "Could not save screenshot for output {}: {}", - output.name(), - err - ), - } - } - } - */ - } + self.handle_action(action, seat) } break; } @@ -815,6 +623,316 @@ impl State { } } + fn handle_action(&mut self, action: Action, seat: &Seat) { + match action { + Action::Terminate => { + self.common.should_stop = true; + } + #[cfg(feature = "debug")] + Action::Debug => { + self.common.egui.active = !self.common.egui.active; + } + #[cfg(not(feature = "debug"))] + Action::Debug => { + slog_scope::info!("Debug overlay not included in this version") + } + Action::Close => { + let current_output = seat.active_output(); + let workspace = self.common.shell.active_space_mut(¤t_output); + if let Some(window) = workspace.focus_stack.get(seat).last() { + window.send_close(); + } + } + Action::Workspace(key_num) => { + let current_output = seat.active_output(); + let workspace = match key_num { + 0 => 9, + x => x - 1, + }; + if let Some(motion_event) = self + .common + .shell + .activate(¤t_output, workspace as usize) + { + if let Some(ptr) = seat.get_pointer() { + ptr.motion(self, None, &motion_event); + } + } + } + Action::NextWorkspace => { + let current_output = seat.active_output(); + let workspace = self + .common + .shell + .workspaces + .active_num(¤t_output) + .saturating_add(1); + // TODO: Possibly move to next output, if idx to large + if let Some(motion_event) = self.common.shell.activate(¤t_output, workspace) { + if let Some(ptr) = seat.get_pointer() { + ptr.motion(self, None, &motion_event); + } + } + } + Action::PreviousWorkspace => { + let current_output = seat.active_output(); + let workspace = self + .common + .shell + .workspaces + .active_num(¤t_output) + .saturating_sub(1); + // TODO: Possibly move to prev output, if idx < 0 + if let Some(motion_event) = self.common.shell.activate(¤t_output, workspace) { + if let Some(ptr) = seat.get_pointer() { + ptr.motion(self, None, &motion_event); + } + } + } + Action::LastWorkspace => { + let current_output = seat.active_output(); + let workspace = self + .common + .shell + .workspaces + .len(¤t_output) + .saturating_sub(1); + if let Some(motion_event) = self.common.shell.activate(¤t_output, workspace) { + if let Some(ptr) = seat.get_pointer() { + ptr.motion(self, None, &motion_event); + } + } + } + Action::MoveToWorkspace(key_num) => { + let current_output = seat.active_output(); + let workspace = match key_num { + 0 => 9, + x => x - 1, + }; + Shell::move_current_window( + self, + seat, + ¤t_output, + (¤t_output, Some(workspace as usize)), + ); + } + Action::MoveToNextWorkspace => { + let current_output = seat.active_output(); + let workspace = self + .common + .shell + .workspaces + .active_num(¤t_output) + .saturating_add(1); + // TODO: Possibly move to next output, if idx too large + Shell::move_current_window( + self, + seat, + ¤t_output, + (¤t_output, Some(workspace as usize)), + ); + } + Action::MoveToPreviousWorkspace => { + let current_output = seat.active_output(); + let workspace = self + .common + .shell + .workspaces + .active_num(¤t_output) + .saturating_sub(1); + // TODO: Possibly move to prev output, if idx < 0 + Shell::move_current_window( + self, + seat, + ¤t_output, + (¤t_output, Some(workspace as usize)), + ); + } + Action::MoveToLastWorkspace => { + let current_output = seat.active_output(); + let workspace = self + .common + .shell + .workspaces + .len(¤t_output) + .saturating_sub(1); + Shell::move_current_window( + self, + seat, + ¤t_output, + (¤t_output, Some(workspace as usize)), + ); + } + Action::NextOutput => { + let current_output = seat.active_output(); + if let Some(next_output) = self + .common + .shell + .outputs + .iter() + .skip_while(|o| *o != ¤t_output) + .skip(1) + .next() + .cloned() + { + let idx = self.common.shell.workspaces.active_num(&next_output); + if let Some(motion_event) = self.common.shell.activate(&next_output, idx) { + if let Some(ptr) = seat.get_pointer() { + ptr.motion(self, None, &motion_event); + } + } + } + } + Action::PreviousOutput => { + let current_output = seat.active_output(); + if let Some(prev_output) = self + .common + .shell + .outputs + .iter() + .rev() + .skip_while(|o| *o != ¤t_output) + .skip(1) + .next() + .cloned() + { + let idx = self.common.shell.workspaces.active_num(&prev_output); + if let Some(motion_event) = self.common.shell.activate(&prev_output, idx) { + if let Some(ptr) = seat.get_pointer() { + ptr.motion(self, None, &motion_event); + } + } + } + } + Action::MoveToNextOutput => { + let current_output = seat.active_output(); + if let Some(next_output) = self + .common + .shell + .outputs + .iter() + .skip_while(|o| *o != ¤t_output) + .skip(1) + .next() + .cloned() + { + Shell::move_current_window(self, seat, ¤t_output, (&next_output, None)); + } + } + Action::MoveToPreviousOutput => { + let current_output = seat.active_output(); + if let Some(prev_output) = self + .common + .shell + .outputs + .iter() + .rev() + .skip_while(|o| *o != ¤t_output) + .skip(1) + .next() + .cloned() + { + Shell::move_current_window(self, seat, ¤t_output, (&prev_output, None)); + } + } + Action::Focus(focus) => { + let current_output = seat.active_output(); + let workspace = self.common.shell.active_space_mut(¤t_output); + let focus_stack = workspace.focus_stack.get(seat); + match workspace + .tiling_layer + .next_focus(focus, seat, focus_stack.iter()) + { + FocusResult::None => { + // TODO: Handle Workspace orientation + match focus { + FocusDirection::Left => { + self.handle_action(Action::PreviousWorkspace, seat) + } + FocusDirection::Right => { + self.handle_action(Action::NextWorkspace, seat) + } + FocusDirection::Up => self.handle_action(Action::PreviousOutput, seat), + FocusDirection::Down => self.handle_action(Action::NextOutput, seat), + _ => {} + } + } + FocusResult::Handled => {} + FocusResult::Some(target) => { + std::mem::drop(focus_stack); + Common::set_focus(self, Some(&target), seat, None); + } + } + } + Action::Move(direction) => { + let current_output = seat.active_output(); + let workspace = self.common.shell.active_space_mut(¤t_output); + if let Some(_move_further) = + workspace.tiling_layer.move_current_window(direction, seat) + { + // TODO: Handle Workspace orientation + // TODO: Being able to move Groups (move_further should be KeyboardFocusTarget instead) + match direction { + Direction::Left => { + self.handle_action(Action::MoveToPreviousWorkspace, seat) + } + Direction::Right => self.handle_action(Action::MoveToNextWorkspace, seat), + Direction::Up => self.handle_action(Action::MoveToPreviousOutput, seat), + Direction::Down => self.handle_action(Action::MoveToNextOutput, seat), + } + } + } + Action::Maximize => { + let current_output = seat.active_output(); + let workspace = self.common.shell.active_space_mut(¤t_output); + let focus_stack = workspace.focus_stack.get(seat); + let focused_window = focus_stack.last(); + if let Some(window) = focused_window.map(|f| f.active_window()) { + workspace.maximize_toggle(&window, ¤t_output); + } + } + Action::ToggleOrientation => { + let output = seat.active_output(); + let workspace = self.common.shell.active_space_mut(&output); + let focus_stack = workspace.focus_stack.get(seat); + workspace + .tiling_layer + .update_orientation(None, &seat, focus_stack.iter()); + } + Action::Orientation(orientation) => { + let output = seat.active_output(); + let workspace = self.common.shell.active_space_mut(&output); + let focus_stack = workspace.focus_stack.get(seat); + workspace.tiling_layer.update_orientation( + Some(orientation), + &seat, + focus_stack.iter(), + ); + } + Action::ToggleTiling => { + let output = seat.active_output(); + let workspace = self.common.shell.active_space_mut(&output); + workspace.toggle_tiling(seat); + } + Action::ToggleWindowFloating => { + let output = seat.active_output(); + let workspace = self.common.shell.active_space_mut(&output); + workspace.toggle_floating_window(seat); + } + Action::Spawn(command) => { + if let Err(err) = std::process::Command::new("/bin/sh") + .arg("-c") + .arg(command) + .env("WAYLAND_DISPLAY", &self.common.socket) + .env_remove("COSMIC_SESSION_SOCK") + .spawn() + { + slog_scope::warn!("Failed to spawn: {}", err); + } + } + } + } + pub fn surface_under( global_pos: Point, relative_pos: Point, diff --git a/src/shell/layout/tiling/mod.rs b/src/shell/layout/tiling/mod.rs index 5cf42adb..97b392ae 100644 --- a/src/shell/layout/tiling/mod.rs +++ b/src/shell/layout/tiling/mod.rs @@ -69,6 +69,13 @@ pub enum Direction { Down, } +#[derive(Debug, Clone, PartialEq)] +pub enum FocusResult { + None, + Handled, + Some(KeyboardFocusTarget), +} + #[derive(Debug, Clone)] pub struct TilingLayout { gaps: (i32, i32), @@ -660,7 +667,7 @@ impl TilingLayout { direction: FocusDirection, seat: &Seat, focus_stack: impl Iterator + 'a, - ) -> Option { + ) -> FocusResult { let output = seat.active_output(); let tree = self.trees.get_mut(&output).unwrap(); @@ -671,7 +678,7 @@ impl TilingLayout { // stacks may handle focus internally if last_window.handle_focus(direction) { - return None; + return FocusResult::Handled; } let mut node_id = last_node_id.clone(); @@ -682,7 +689,7 @@ impl TilingLayout { assert!(group_data.is_group()); if direction == FocusDirection::Out { - return Some( + return FocusResult::Some( WindowGroup { node: group.clone(), output: output.downgrade(), @@ -787,7 +794,7 @@ impl TilingLayout { }); } Data::Mapped { mapped, .. } => { - return Some(mapped.clone().into()); + return FocusResult::Some(mapped.clone().into()); } } } @@ -797,7 +804,7 @@ impl TilingLayout { } } - None + FocusResult::None } pub fn update_orientation<'a>( diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 48018596..7e32c841 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -325,6 +325,16 @@ impl WorkspaceMode { } } + pub fn len(&self, output: &Output) -> usize { + match self { + WorkspaceMode::Global(set) => set.workspaces.len(), + WorkspaceMode::OutputBound(sets, _) => { + let set = sets.get(output).unwrap(); + set.workspaces.len() + } + } + } + pub fn spaces(&self) -> impl Iterator { match self { WorkspaceMode::Global(set) => { @@ -970,16 +980,27 @@ impl Shell { } } - pub fn move_current_window(state: &mut State, seat: &Seat, output: &Output, idx: usize) { - if idx == state.common.shell.workspaces.active_num(output) { + pub fn move_current_window( + state: &mut State, + seat: &Seat, + from_output: &Output, + to: (&Output, Option), + ) { + let (to_output, to_idx) = to; + let to_idx = to_idx.unwrap_or(state.common.shell.workspaces.active_num(to_output)); + + if from_output == to_output + && to_idx == state.common.shell.workspaces.active_num(from_output) + { return; } - let old_workspace = state.common.shell.workspaces.active_mut(output); - let maybe_window = old_workspace.focus_stack.get(seat).last().cloned(); + let from_workspace = state.common.shell.workspaces.active_mut(from_output); + let maybe_window = from_workspace.focus_stack.get(seat).last().cloned(); + if let Some(mapped) = maybe_window { - let was_floating = old_workspace.floating_layer.unmap(&mapped); - let was_tiling = old_workspace.tiling_layer.unmap(&mapped); + let was_floating = from_workspace.floating_layer.unmap(&mapped); + let was_tiling = from_workspace.tiling_layer.unmap(&mapped); assert!(was_floating != was_tiling); for (toplevel, _) in mapped.windows() { @@ -987,22 +1008,25 @@ impl Shell { .common .shell .toplevel_info_state - .toplevel_leave_workspace(&toplevel, &old_workspace.handle); + .toplevel_leave_workspace(&toplevel, &from_workspace.handle); } - let elements = old_workspace.mapped().cloned().collect::>(); - std::mem::drop(old_workspace); + let elements = from_workspace.mapped().cloned().collect::>(); + std::mem::drop(from_workspace); for mapped in elements.into_iter() { state.common.shell.update_reactive_popups(&mapped); } - let new_workspace = state.common.shell.workspaces.get_mut(idx, output).unwrap(); // checked above - let focus_stack = new_workspace.focus_stack.get(&seat); + let to_workspace = state + .common + .shell + .workspaces + .get_mut(to_idx, to_output) + .unwrap(); // checked above + let focus_stack = to_workspace.focus_stack.get(&seat); if was_floating { - new_workspace - .floating_layer - .map(mapped.clone(), &seat, None); + to_workspace.floating_layer.map(mapped.clone(), &seat, None); } else { - new_workspace + to_workspace .tiling_layer .map(mapped.clone(), &seat, focus_stack.iter()); } @@ -1011,10 +1035,10 @@ impl Shell { .common .shell .toplevel_info_state - .toplevel_enter_workspace(&toplevel, &new_workspace.handle); + .toplevel_enter_workspace(&toplevel, &to_workspace.handle); } - for mapped in new_workspace + for mapped in to_workspace .mapped() .cloned() .collect::>() @@ -1023,7 +1047,7 @@ impl Shell { state.common.shell.update_reactive_popups(&mapped); } - state.common.shell.activate(output, idx); + state.common.shell.activate(to_output, to_idx); Common::set_focus(state, Some(&KeyboardFocusTarget::from(mapped)), &seat, None); } } diff --git a/src/shell/workspace.rs b/src/shell/workspace.rs index 8cc19c2c..5eb46487 100644 --- a/src/shell/workspace.rs +++ b/src/shell/workspace.rs @@ -249,11 +249,11 @@ impl Workspace { } } - pub fn fullscreen_toggle(&mut self, window: &Window, output: &Output) { + pub fn maximize_toggle(&mut self, window: &Window, output: &Output) { if self.fullscreen.contains_key(output) { - self.unfullscreen_request(window) + self.unmaximize_request(window) } else { - self.fullscreen_request(window, output) + self.maximize_request(window, output) } }