input: Various new keybindings
This commit is contained in:
parent
6cec3cb7e0
commit
544acecd2e
6 changed files with 476 additions and 280 deletions
130
config.ron
130
config.ron
|
|
@ -1,57 +1,89 @@
|
||||||
(
|
(
|
||||||
key_bindings: {
|
key_bindings: {
|
||||||
(modifiers: [Logo, Shift], key: "Escape"): Terminate,
|
(modifiers: [Super, Shift], key: "Escape"): Terminate,
|
||||||
(modifiers: [Logo], key: "Escape"): Debug,
|
(modifiers: [Super], key: "Escape"): Debug,
|
||||||
(modifiers: [Logo], key: "q"): Close,
|
(modifiers: [Super], key: "q"): Close,
|
||||||
(modifiers: [Logo], key: "1"): Workspace(1),
|
|
||||||
(modifiers: [Logo], key: "2"): Workspace(2),
|
(modifiers: [Super], key: "1"): Workspace(1),
|
||||||
(modifiers: [Logo], key: "3"): Workspace(3),
|
(modifiers: [Super], key: "2"): Workspace(2),
|
||||||
(modifiers: [Logo], key: "4"): Workspace(4),
|
(modifiers: [Super], key: "3"): Workspace(3),
|
||||||
(modifiers: [Logo], key: "5"): Workspace(5),
|
(modifiers: [Super], key: "4"): Workspace(4),
|
||||||
(modifiers: [Logo], key: "6"): Workspace(6),
|
(modifiers: [Super], key: "5"): Workspace(5),
|
||||||
(modifiers: [Logo], key: "7"): Workspace(7),
|
(modifiers: [Super], key: "6"): Workspace(6),
|
||||||
(modifiers: [Logo], key: "8"): Workspace(8),
|
(modifiers: [Super], key: "7"): Workspace(7),
|
||||||
(modifiers: [Logo], key: "9"): Workspace(9),
|
(modifiers: [Super], key: "8"): Workspace(8),
|
||||||
(modifiers: [Logo], key: "0"): Workspace(0),
|
(modifiers: [Super], key: "9"): Workspace(9),
|
||||||
(modifiers: [Logo, Shift], key: "1"): MoveToWorkspace(1),
|
(modifiers: [Super], key: "0"): LastWorkspace,
|
||||||
(modifiers: [Logo, Shift], key: "2"): MoveToWorkspace(2),
|
(modifiers: [Super, Shift], key: "1"): MoveToWorkspace(1),
|
||||||
(modifiers: [Logo, Shift], key: "3"): MoveToWorkspace(3),
|
(modifiers: [Super, Shift], key: "2"): MoveToWorkspace(2),
|
||||||
(modifiers: [Logo, Shift], key: "4"): MoveToWorkspace(4),
|
(modifiers: [Super, Shift], key: "3"): MoveToWorkspace(3),
|
||||||
(modifiers: [Logo, Shift], key: "5"): MoveToWorkspace(5),
|
(modifiers: [Super, Shift], key: "4"): MoveToWorkspace(4),
|
||||||
(modifiers: [Logo, Shift], key: "6"): MoveToWorkspace(6),
|
(modifiers: [Super, Shift], key: "5"): MoveToWorkspace(5),
|
||||||
(modifiers: [Logo, Shift], key: "7"): MoveToWorkspace(7),
|
(modifiers: [Super, Shift], key: "6"): MoveToWorkspace(6),
|
||||||
(modifiers: [Logo, Shift], key: "8"): MoveToWorkspace(8),
|
(modifiers: [Super, Shift], key: "7"): MoveToWorkspace(7),
|
||||||
(modifiers: [Logo, Shift], key: "9"): MoveToWorkspace(9),
|
(modifiers: [Super, Shift], key: "8"): MoveToWorkspace(8),
|
||||||
(modifiers: [Logo, Shift], key: "0"): MoveToWorkspace(0),
|
(modifiers: [Super, Shift], key: "9"): MoveToWorkspace(9),
|
||||||
(modifiers: [Logo], key: "Left"): Focus(Left),
|
(modifiers: [Super, Shift], key: "0"): MoveToLastWorkspace,
|
||||||
(modifiers: [Logo], key: "Right"): Focus(Right),
|
|
||||||
(modifiers: [Logo], key: "Up"): Focus(Up),
|
// TODO: Depends on workspace orientation
|
||||||
(modifiers: [Logo], key: "Down"): Focus(Down),
|
(modifiers: [Super, Ctrl], key: "Right"): NextWorkspace,
|
||||||
(modifiers: [Logo], key: "h"): Focus(Left),
|
(modifiers: [Super, Ctrl], key: "Left"): PreviousWorkspace,
|
||||||
(modifiers: [Logo], key: "j"): Focus(Down),
|
(modifiers: [Super, Ctrl, Shift], key: "Right"): MoveToNextWorkspace,
|
||||||
(modifiers: [Logo], key: "k"): Focus(Up),
|
(modifiers: [Super, Ctrl, Shift], key: "Left"): MoveToPreviousWorkspace,
|
||||||
(modifiers: [Logo], key: "l"): Focus(Right),
|
(modifiers: [Super, Ctrl], key: "l"): NextWorkspace,
|
||||||
(modifiers: [Logo, Shift], key: "Left"): Move(Left),
|
(modifiers: [Super, Ctrl], key: "h"): PreviousWorkspace,
|
||||||
(modifiers: [Logo, Shift], key: "Right"): Move(Right),
|
(modifiers: [Super, Ctrl, Shift], key: "l"): MoveToNextWorkspace,
|
||||||
(modifiers: [Logo, Shift], key: "Up"): Move(Up),
|
(modifiers: [Super, Ctrl, Shift], key: "h"): MoveToPreviousWorkspace,
|
||||||
(modifiers: [Logo, Shift], key: "Down"): Move(Down),
|
|
||||||
(modifiers: [Logo, Shift], key: "h"): Move(Left),
|
(modifiers: [Super, Ctrl], key: "Down"): NextOutput,
|
||||||
(modifiers: [Logo, Shift], key: "j"): Move(Down),
|
(modifiers: [Super, Ctrl], key: "Up"): PreviousOutput,
|
||||||
(modifiers: [Logo, Shift], key: "k"): Move(Up),
|
(modifiers: [Super, Ctrl, Alt], key: "Down"): NextOutput,
|
||||||
(modifiers: [Logo, Shift], key: "l"): Move(Right),
|
(modifiers: [Super, Ctrl, Alt], key: "Up"): PreviousOutput,
|
||||||
(modifiers: [Logo], key: "o"): ToggleOrientation,
|
(modifiers: [Super, Ctrl], key: "j"): NextOutput,
|
||||||
(modifiers: [Logo], key: "y"): ToggleTiling,
|
(modifiers: [Super, Ctrl], key: "k"): PreviousOutput,
|
||||||
(modifiers: [Logo], key: "g"): ToggleWindowFloating,
|
(modifiers: [Super, Ctrl, Alt], key: "j"): NextOutput,
|
||||||
(modifiers: [Logo, Shift], key: "f"): Fullscreen,
|
(modifiers: [Super, Ctrl, Alt], key: "k"): PreviousOutput,
|
||||||
//(modifiers: [Logo, Shift], key: "s"): Screenshot,
|
|
||||||
|
(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
|
//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
|
//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
|
//TODO: ability to select default terminal
|
||||||
(modifiers: [Logo], key: "t"): Spawn("gnome-terminal"),
|
(modifiers: [Super], 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: "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: "XF86AudioRaiseVolume"): Spawn("amixer sset Master 5%+"),
|
||||||
(modifiers: [], key: "XF86AudioLowerVolume"): Spawn("amixer sset Master 5%-"),
|
(modifiers: [], key: "XF86AudioLowerVolume"): Spawn("amixer sset Master 5%-"),
|
||||||
(modifiers: [], key: "XF86AudioMute"): Spawn("amixer sset Master toggle"),
|
(modifiers: [], key: "XF86AudioMute"): Spawn("amixer sset Master toggle"),
|
||||||
|
|
|
||||||
|
|
@ -691,7 +691,7 @@ pub enum KeyModifier {
|
||||||
Ctrl,
|
Ctrl,
|
||||||
Alt,
|
Alt,
|
||||||
Shift,
|
Shift,
|
||||||
Logo,
|
Super,
|
||||||
CapsLock,
|
CapsLock,
|
||||||
NumLock,
|
NumLock,
|
||||||
}
|
}
|
||||||
|
|
@ -723,7 +723,7 @@ impl std::ops::AddAssign<KeyModifier> for KeyModifiers {
|
||||||
KeyModifier::Ctrl => self.ctrl = true,
|
KeyModifier::Ctrl => self.ctrl = true,
|
||||||
KeyModifier::Alt => self.alt = true,
|
KeyModifier::Alt => self.alt = true,
|
||||||
KeyModifier::Shift => self.shift = true,
|
KeyModifier::Shift => self.shift = true,
|
||||||
KeyModifier::Logo => self.logo = true,
|
KeyModifier::Super => self.logo = true,
|
||||||
KeyModifier::CapsLock => self.caps_lock = true,
|
KeyModifier::CapsLock => self.caps_lock = true,
|
||||||
KeyModifier::NumLock => self.num_lock = true,
|
KeyModifier::NumLock => self.num_lock = true,
|
||||||
};
|
};
|
||||||
|
|
@ -782,15 +782,30 @@ pub enum Action {
|
||||||
Terminate,
|
Terminate,
|
||||||
Debug,
|
Debug,
|
||||||
Close,
|
Close,
|
||||||
|
|
||||||
Workspace(u8),
|
Workspace(u8),
|
||||||
|
NextWorkspace,
|
||||||
|
PreviousWorkspace,
|
||||||
|
LastWorkspace,
|
||||||
MoveToWorkspace(u8),
|
MoveToWorkspace(u8),
|
||||||
|
MoveToNextWorkspace,
|
||||||
|
MoveToPreviousWorkspace,
|
||||||
|
MoveToLastWorkspace,
|
||||||
|
|
||||||
|
NextOutput,
|
||||||
|
PreviousOutput,
|
||||||
|
MoveToNextOutput,
|
||||||
|
MoveToPreviousOutput,
|
||||||
|
|
||||||
Focus(FocusDirection),
|
Focus(FocusDirection),
|
||||||
Move(Direction),
|
Move(Direction),
|
||||||
|
|
||||||
ToggleOrientation,
|
ToggleOrientation,
|
||||||
Orientation(crate::shell::layout::Orientation),
|
Orientation(crate::shell::layout::Orientation),
|
||||||
|
|
||||||
ToggleTiling,
|
ToggleTiling,
|
||||||
ToggleWindowFloating,
|
ToggleWindowFloating,
|
||||||
Fullscreen,
|
|
||||||
//Screenshot,
|
Maximize,
|
||||||
Spawn(String),
|
Spawn(String),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
520
src/input/mod.rs
520
src/input/mod.rs
|
|
@ -2,7 +2,14 @@
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{Action, Config},
|
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,
|
state::Common,
|
||||||
utils::prelude::*,
|
utils::prelude::*,
|
||||||
wayland::{handlers::screencopy::ScreencopySessions, protocols::screencopy::Session},
|
wayland::{handlers::screencopy::ScreencopySessions, protocols::screencopy::Session},
|
||||||
|
|
@ -301,206 +308,7 @@ impl State {
|
||||||
)
|
)
|
||||||
.flatten()
|
.flatten()
|
||||||
{
|
{
|
||||||
match action {
|
self.handle_action(action, seat)
|
||||||
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<std::path::Path>,
|
|
||||||
data: Vec<u8>,
|
|
||||||
size: Size<i32, Buffer>,
|
|
||||||
) -> 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
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -815,6 +623,316 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_action(&mut self, action: Action, seat: &Seat<State>) {
|
||||||
|
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(
|
pub fn surface_under(
|
||||||
global_pos: Point<f64, Logical>,
|
global_pos: Point<f64, Logical>,
|
||||||
relative_pos: Point<f64, Logical>,
|
relative_pos: Point<f64, Logical>,
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,13 @@ pub enum Direction {
|
||||||
Down,
|
Down,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum FocusResult {
|
||||||
|
None,
|
||||||
|
Handled,
|
||||||
|
Some(KeyboardFocusTarget),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct TilingLayout {
|
pub struct TilingLayout {
|
||||||
gaps: (i32, i32),
|
gaps: (i32, i32),
|
||||||
|
|
@ -660,7 +667,7 @@ impl TilingLayout {
|
||||||
direction: FocusDirection,
|
direction: FocusDirection,
|
||||||
seat: &Seat<State>,
|
seat: &Seat<State>,
|
||||||
focus_stack: impl Iterator<Item = &'a CosmicMapped> + 'a,
|
focus_stack: impl Iterator<Item = &'a CosmicMapped> + 'a,
|
||||||
) -> Option<KeyboardFocusTarget> {
|
) -> FocusResult {
|
||||||
let output = seat.active_output();
|
let output = seat.active_output();
|
||||||
let tree = self.trees.get_mut(&output).unwrap();
|
let tree = self.trees.get_mut(&output).unwrap();
|
||||||
|
|
||||||
|
|
@ -671,7 +678,7 @@ impl TilingLayout {
|
||||||
|
|
||||||
// stacks may handle focus internally
|
// stacks may handle focus internally
|
||||||
if last_window.handle_focus(direction) {
|
if last_window.handle_focus(direction) {
|
||||||
return None;
|
return FocusResult::Handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut node_id = last_node_id.clone();
|
let mut node_id = last_node_id.clone();
|
||||||
|
|
@ -682,7 +689,7 @@ impl TilingLayout {
|
||||||
assert!(group_data.is_group());
|
assert!(group_data.is_group());
|
||||||
|
|
||||||
if direction == FocusDirection::Out {
|
if direction == FocusDirection::Out {
|
||||||
return Some(
|
return FocusResult::Some(
|
||||||
WindowGroup {
|
WindowGroup {
|
||||||
node: group.clone(),
|
node: group.clone(),
|
||||||
output: output.downgrade(),
|
output: output.downgrade(),
|
||||||
|
|
@ -787,7 +794,7 @@ impl TilingLayout {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Data::Mapped { mapped, .. } => {
|
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>(
|
pub fn update_orientation<'a>(
|
||||||
|
|
|
||||||
|
|
@ -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<Item = &Workspace> {
|
pub fn spaces(&self) -> impl Iterator<Item = &Workspace> {
|
||||||
match self {
|
match self {
|
||||||
WorkspaceMode::Global(set) => {
|
WorkspaceMode::Global(set) => {
|
||||||
|
|
@ -970,16 +980,27 @@ impl Shell {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn move_current_window(state: &mut State, seat: &Seat<State>, output: &Output, idx: usize) {
|
pub fn move_current_window(
|
||||||
if idx == state.common.shell.workspaces.active_num(output) {
|
state: &mut State,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
from_output: &Output,
|
||||||
|
to: (&Output, Option<usize>),
|
||||||
|
) {
|
||||||
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let old_workspace = state.common.shell.workspaces.active_mut(output);
|
let from_workspace = state.common.shell.workspaces.active_mut(from_output);
|
||||||
let maybe_window = old_workspace.focus_stack.get(seat).last().cloned();
|
let maybe_window = from_workspace.focus_stack.get(seat).last().cloned();
|
||||||
|
|
||||||
if let Some(mapped) = maybe_window {
|
if let Some(mapped) = maybe_window {
|
||||||
let was_floating = old_workspace.floating_layer.unmap(&mapped);
|
let was_floating = from_workspace.floating_layer.unmap(&mapped);
|
||||||
let was_tiling = old_workspace.tiling_layer.unmap(&mapped);
|
let was_tiling = from_workspace.tiling_layer.unmap(&mapped);
|
||||||
assert!(was_floating != was_tiling);
|
assert!(was_floating != was_tiling);
|
||||||
|
|
||||||
for (toplevel, _) in mapped.windows() {
|
for (toplevel, _) in mapped.windows() {
|
||||||
|
|
@ -987,22 +1008,25 @@ impl Shell {
|
||||||
.common
|
.common
|
||||||
.shell
|
.shell
|
||||||
.toplevel_info_state
|
.toplevel_info_state
|
||||||
.toplevel_leave_workspace(&toplevel, &old_workspace.handle);
|
.toplevel_leave_workspace(&toplevel, &from_workspace.handle);
|
||||||
}
|
}
|
||||||
let elements = old_workspace.mapped().cloned().collect::<Vec<_>>();
|
let elements = from_workspace.mapped().cloned().collect::<Vec<_>>();
|
||||||
std::mem::drop(old_workspace);
|
std::mem::drop(from_workspace);
|
||||||
for mapped in elements.into_iter() {
|
for mapped in elements.into_iter() {
|
||||||
state.common.shell.update_reactive_popups(&mapped);
|
state.common.shell.update_reactive_popups(&mapped);
|
||||||
}
|
}
|
||||||
|
|
||||||
let new_workspace = state.common.shell.workspaces.get_mut(idx, output).unwrap(); // checked above
|
let to_workspace = state
|
||||||
let focus_stack = new_workspace.focus_stack.get(&seat);
|
.common
|
||||||
|
.shell
|
||||||
|
.workspaces
|
||||||
|
.get_mut(to_idx, to_output)
|
||||||
|
.unwrap(); // checked above
|
||||||
|
let focus_stack = to_workspace.focus_stack.get(&seat);
|
||||||
if was_floating {
|
if was_floating {
|
||||||
new_workspace
|
to_workspace.floating_layer.map(mapped.clone(), &seat, None);
|
||||||
.floating_layer
|
|
||||||
.map(mapped.clone(), &seat, None);
|
|
||||||
} else {
|
} else {
|
||||||
new_workspace
|
to_workspace
|
||||||
.tiling_layer
|
.tiling_layer
|
||||||
.map(mapped.clone(), &seat, focus_stack.iter());
|
.map(mapped.clone(), &seat, focus_stack.iter());
|
||||||
}
|
}
|
||||||
|
|
@ -1011,10 +1035,10 @@ impl Shell {
|
||||||
.common
|
.common
|
||||||
.shell
|
.shell
|
||||||
.toplevel_info_state
|
.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()
|
.mapped()
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
|
|
@ -1023,7 +1047,7 @@ impl Shell {
|
||||||
state.common.shell.update_reactive_popups(&mapped);
|
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);
|
Common::set_focus(state, Some(&KeyboardFocusTarget::from(mapped)), &seat, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
if self.fullscreen.contains_key(output) {
|
||||||
self.unfullscreen_request(window)
|
self.unmaximize_request(window)
|
||||||
} else {
|
} else {
|
||||||
self.fullscreen_request(window, output)
|
self.maximize_request(window, output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue