feat: runtime configurable keybindings

This commit is contained in:
Michael Aaron Murphy 2024-04-03 16:02:27 +02:00 committed by Michael Murphy
parent 62afa4cf61
commit 553c49b42b
25 changed files with 674 additions and 829 deletions

103
Cargo.lock generated
View file

@ -425,6 +425,12 @@ version = "0.21.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
[[package]]
name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "bit-set"
version = "0.5.3"
@ -663,6 +669,7 @@ dependencies = [
"iana-time-zone",
"js-sys",
"num-traits",
"serde",
"wasm-bindgen",
"windows-targets 0.52.5",
]
@ -872,6 +879,7 @@ dependencies = [
"cosmic-comp-config",
"cosmic-config",
"cosmic-protocols",
"cosmic-settings-config",
"edid-rs",
"egui",
"egui_plot",
@ -880,7 +888,7 @@ dependencies = [
"i18n-embed-fl",
"iced_tiny_skia",
"id_tree",
"indexmap",
"indexmap 2.2.6",
"keyframe",
"lazy_static",
"libc",
@ -967,6 +975,20 @@ dependencies = [
"wayland-server",
]
[[package]]
name = "cosmic-settings-config"
version = "0.1.0"
source = "git+https://github.com/pop-os/cosmic-settings-daemon#ad0e0703549f7b135746d0429c6408cc8a7cc037"
dependencies = [
"cosmic-config",
"heck 0.5.0",
"serde",
"serde_with",
"thiserror",
"tracing",
"xkbcommon",
]
[[package]]
name = "cosmic-text"
version = "0.12.0"
@ -1154,7 +1176,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
dependencies = [
"cfg-if",
"hashbrown",
"hashbrown 0.14.5",
"lock_api",
"once_cell",
"parking_lot_core 0.9.10",
@ -1179,6 +1201,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
dependencies = [
"powerfmt",
"serde",
]
[[package]]
@ -2190,7 +2213,7 @@ checksum = "cc11df1ace8e7e564511f53af41f3e42ddc95b56fd07b3f4445d2a6048bc682c"
dependencies = [
"bitflags 2.5.0",
"gpu-descriptor-types",
"hashbrown",
"hashbrown 0.14.5",
]
[[package]]
@ -2228,6 +2251,12 @@ dependencies = [
"crunchy",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hashbrown"
version = "0.14.5"
@ -2259,6 +2288,12 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "hermit-abi"
version = "0.3.9"
@ -2607,6 +2642,17 @@ version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "029d73f573d8e8d63e6d5020011d3255b28c3ba85d6cf870a07184ed23de9284"
[[package]]
name = "indexmap"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown 0.12.3",
"serde",
]
[[package]]
name = "indexmap"
version = "2.2.6"
@ -2614,7 +2660,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
dependencies = [
"equivalent",
"hashbrown",
"hashbrown 0.14.5",
"serde",
]
[[package]]
@ -3061,7 +3108,7 @@ version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc"
dependencies = [
"hashbrown",
"hashbrown 0.14.5",
]
[[package]]
@ -3274,7 +3321,7 @@ dependencies = [
"bitflags 2.5.0",
"codespan-reporting",
"hexf-parse",
"indexmap",
"indexmap 2.2.6",
"log",
"num-traits",
"rustc-hash",
@ -3791,7 +3838,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79"
dependencies = [
"dlv-list",
"hashbrown",
"hashbrown 0.14.5",
]
[[package]]
@ -3821,7 +3868,7 @@ version = "0.17.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec4c6225c69b4ca778c0aea097321a64c421cf4577b331c61b229267edabb6f8"
dependencies = [
"heck",
"heck 0.4.1",
"proc-macro-error",
"proc-macro2",
"quote",
@ -4655,7 +4702,7 @@ version = "1.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
dependencies = [
"indexmap",
"indexmap 2.2.6",
"itoa",
"ryu",
"serde",
@ -4681,6 +4728,36 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_with"
version = "3.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ad483d2ab0149d5a5ebcd9972a3852711e0153d863bf5a5d0391d28883c4a20"
dependencies = [
"base64 0.22.1",
"chrono",
"hex",
"indexmap 1.9.3",
"indexmap 2.2.6",
"serde",
"serde_derive",
"serde_json",
"serde_with_macros",
"time",
]
[[package]]
name = "serde_with_macros"
version = "3.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65569b702f41443e8bc8bbb1c5779bd0450bbe723b56198980e80ec45780bce2"
dependencies = [
"darling",
"proc-macro2",
"quote",
"syn 2.0.66",
]
[[package]]
name = "sha1"
version = "0.10.6"
@ -4797,7 +4874,7 @@ dependencies = [
"gbm",
"gl_generator",
"glow 0.12.3",
"indexmap",
"indexmap 2.2.6",
"input",
"lazy_static",
"libc",
@ -5320,7 +5397,7 @@ version = "0.19.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
dependencies = [
"indexmap",
"indexmap 2.2.6",
"toml_datetime",
"winnow 0.5.40",
]
@ -5331,7 +5408,7 @@ version = "0.22.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c127785850e8c20836d49732ae6abfa47616e60bf9d9f57c43c250361a9db96c"
dependencies = [
"indexmap",
"indexmap 2.2.6",
"serde",
"serde_spanned",
"toml_datetime",
@ -6054,7 +6131,7 @@ dependencies = [
"bitflags 2.5.0",
"cfg_aliases 0.1.1",
"codespan-reporting",
"indexmap",
"indexmap 2.2.6",
"log",
"naga",
"once_cell",

View file

@ -18,6 +18,7 @@ calloop = {version = "0.14.0", features = ["executor"]}
cosmic-comp-config = {path = "cosmic-comp-config"}
cosmic-config = {git = "https://github.com/pop-os/libcosmic/", features = ["calloop", "macro"]}
cosmic-protocols = {git = "https://github.com/pop-os/cosmic-protocols", branch = "main", default-features = false, features = ["server"]}
cosmic-settings-config = { git = "https://github.com/pop-os/cosmic-settings-daemon" }
edid-rs = {version = "0.1"}
egui = {version = "0.23.0", optional = true}
egui_plot = {version = "0.23.0", optional = true}
@ -45,7 +46,7 @@ serde_json = "1"
thiserror = "1.0.26"
time = {version = "0.3.30", features = ["macros", "formatting", "local-offset"]}
tiny-skia = "0.11"
tracing = {version = "0.1.37", features = ["max_level_debug", "release_max_level_info"]}
tracing = { version = "0.1.37", features = ["max_level_debug", "release_max_level_info"] }
tracing-journald = "0.3.0"
tracing-subscriber = {version = "0.3.16", features = ["env-filter", "tracing-log"]}
wayland-backend = "0.3.3"

View file

@ -5,7 +5,6 @@ libdir = $(prefix)/lib
sharedir = $(prefix)/share
BINARY = cosmic-comp
ID = com.pop-os.Compositor
TARGET = debug
DEBUG ?= 0
@ -23,6 +22,8 @@ endif
TARGET_BIN="$(DESTDIR)$(bindir)/$(BINARY)"
KEYBINDINGS_CONF="$(DESTDIR)$(sharedir)/cosmic/com.system76.CosmicSettings.Shortcuts/v1/defaults"
all: extract-vendor
cargo build $(ARGS)
@ -46,6 +47,7 @@ endif
install:
install -Dm0755 "target/$(TARGET)/$(BINARY)" "$(TARGET_BIN)"
install -Dm0644 "data/keybindings.ron" "$(KEYBINDINGS_CONF)"
install-bare-session: install
install -Dm0644 "data/cosmic.desktop" "$(DESTDIR)$(sharedir)/wayland-sessions/cosmic.desktop"
@ -55,7 +57,7 @@ install-bare-session: install
install -Dm0755 "data/cosmic-service" "$(DESTDIR)/$(bindir)/cosmic-service"
uninstall:
rm "$(TARGET_BIN)"
rm "$(TARGET_BIN)" "$(KEYBINDINGS_CONF)"
uninstall-bare-session:
rm "$(DESTDIR)$(sharedir)/wayland-sessions/cosmic.desktop"
rm "$(DESTDIR)$(sharedir)/wayland-sessions/cosmic.desktop"

View file

@ -1,95 +0,0 @@
(
key_bindings: {
(modifiers: [Super, Shift], key: "Escape"): Terminate,
(modifiers: [Super, Ctrl], key: "Escape"): Debug,
(modifiers: [Super], key: "Escape"): Spawn("loginctl lock-session"),
(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,
(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], 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], key: "o"): ToggleOrientation,
(modifiers: [Super], key: "s"): ToggleStacking,
(modifiers: [Super], key: "y"): ToggleTiling,
(modifiers: [Super], key: "g"): ToggleWindowFloating,
(modifiers: [Super], key: "x"): SwapWindow,
(modifiers: [Super], key: "m"): Maximize,
(modifiers: [Super], key: "r"): Resizing(Outwards),
(modifiers: [Super, Shift], key: "r"): Resizing(Inwards),
(modifiers: [Super], key: "b"): Spawn("xdg-open http://"),
(modifiers: [Super], key: "f"): Spawn("xdg-open ~"),
//TODO: ability to select default terminal
(modifiers: [Super], key: "t"): Spawn("cosmic-term"),
(modifiers: [Super], key: "a"): Spawn("cosmic-app-library"),
(modifiers: [Super], key: "w"): Spawn("cosmic-workspaces"),
(modifiers: [Super], key: "slash"): Spawn("cosmic-launcher"),
(modifiers: [Super]): Spawn("cosmic-launcher"),
(modifiers: [Alt], key: "Tab"): Spawn("cosmic-launcher alt-tab"),
(modifiers: [Super], key: "Tab"): Spawn("cosmic-launcher alt-tab"),
(modifiers: [], key: "Print"): Spawn("cosmic-screenshot"),
(modifiers: [], key: "XF86AudioRaiseVolume"): Spawn("amixer sset Master 5%+"),
(modifiers: [], key: "XF86AudioLowerVolume"): Spawn("amixer sset Master 5%-"),
(modifiers: [], key: "XF86AudioMute"): Spawn("amixer sset Master toggle"),
(modifiers: [], key: "XF86AudioMicMute"): Spawn("amixer sset Capture toggle"),
(modifiers: [], key: "XF86MonBrightnessUp"): Spawn("busctl --user call com.system76.CosmicSettingsDaemon /com/system76/CosmicSettingsDaemon com.system76.CosmicSettingsDaemon IncreaseDisplayBrightness"),
(modifiers: [], key: "XF86MonBrightnessDown"): Spawn("busctl --user call com.system76.CosmicSettingsDaemon /com/system76/CosmicSettingsDaemon com.system76.CosmicSettingsDaemon DecreaseDisplayBrightness"),
},
data_control_enabled: false,
)

90
data/keybindings.ron Normal file
View file

@ -0,0 +1,90 @@
{
(modifiers: [Super, Shift], key: "Escape"): Terminate,
(modifiers: [Super, Ctrl], key: "Escape"): Debug,
(modifiers: [Super], key: "Escape"): System(LockScreen),
(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,
(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], 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], key: "o"): ToggleOrientation,
(modifiers: [Super], key: "s"): ToggleStacking,
(modifiers: [Super], key: "y"): ToggleTiling,
(modifiers: [Super], key: "g"): ToggleWindowFloating,
(modifiers: [Super], key: "x"): SwapWindow,
(modifiers: [Super], key: "m"): Maximize,
(modifiers: [Super], key: "r"): Resizing(Outwards),
(modifiers: [Super, Shift], key: "r"): Resizing(Inwards),
(modifiers: [Super], key: "b"): System(WebBrowser),
(modifiers: [Super], key: "f"): System(HomeFolder),
(modifiers: [Super], key: "t"): System(Terminal),
(modifiers: [Super], key: "a"): System(AppLibrary),
(modifiers: [Super], key: "w"): System(WorkspaceOverview),
(modifiers: [Super], key: "slash"): System(Launcher),
(modifiers: [Super]): System(Launcher),
(modifiers: [Alt], key: "Tab"): System(WindowSwitcher),
(modifiers: [Super], key: "Tab"): System(WindowSwitcher),
(modifiers: [], key: "Print"): System(Screenshot),
(modifiers: [], key: "XF86AudioRaiseVolume"): System(VolumeRaise),
(modifiers: [], key: "XF86AudioLowerVolume"): System(VolumeLower),
(modifiers: [], key: "XF86AudioMute"): System(Mute),
(modifiers: [], key: "XF86AudioMicMute"): System(MuteMic),
(modifiers: [], key: "XF86MonBrightnessUp"): System(BrightnessUp),
(modifiers: [], key: "XF86MonBrightnessDown"): System(BrightnessDown),
}

View file

@ -1 +0,0 @@
config.ron etc/cosmic-comp

View file

@ -1,221 +1,29 @@
// SPDX-License-Identifier: GPL-3.0-only
use crate::shell::{focus::FocusDirection, grabs::ResizeEdge, Direction, ResizeDirection};
use cosmic_comp_config::workspace::WorkspaceLayout;
use serde::Deserialize;
use smithay::{
backend::input::KeyState,
input::keyboard::{xkb::keysym_get_name, ModifiersState},
};
use std::collections::HashMap;
use cosmic_settings_config::shortcuts::State as KeyState;
use cosmic_settings_config::shortcuts::{self, Modifiers, Shortcuts};
use smithay::input::keyboard::ModifiersState;
use xkbcommon::xkb;
use super::types::*;
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
pub enum KeyModifier {
Ctrl,
Alt,
Shift,
Super,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
pub struct KeyModifiers {
pub ctrl: bool,
pub alt: bool,
pub shift: bool,
pub logo: bool,
}
impl PartialEq<ModifiersState> for KeyModifiers {
fn eq(&self, other: &ModifiersState) -> bool {
self.ctrl == other.ctrl
&& self.alt == other.alt
&& self.shift == other.shift
&& self.logo == other.logo
}
}
impl Into<KeyModifiers> for ModifiersState {
fn into(self) -> KeyModifiers {
KeyModifiers {
ctrl: self.ctrl,
alt: self.alt,
shift: self.shift,
logo: self.logo,
}
}
}
impl std::ops::AddAssign<KeyModifier> for KeyModifiers {
fn add_assign(&mut self, rhs: KeyModifier) {
match rhs {
KeyModifier::Ctrl => self.ctrl = true,
KeyModifier::Alt => self.alt = true,
KeyModifier::Shift => self.shift = true,
KeyModifier::Super => self.logo = true,
};
}
}
impl std::ops::BitOr for KeyModifier {
type Output = KeyModifiers;
fn bitor(self, rhs: KeyModifier) -> Self::Output {
let mut modifiers = self.into();
modifiers += rhs;
modifiers
}
}
impl Into<KeyModifiers> for KeyModifier {
fn into(self) -> KeyModifiers {
let mut modifiers = KeyModifiers {
ctrl: false,
alt: false,
shift: false,
logo: false,
};
modifiers += self;
modifiers
}
}
/// Describtion of a key combination that might be
/// handled by the compositor.
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Hash)]
#[serde(deny_unknown_fields)]
pub struct KeyPattern {
/// What modifiers are expected to be pressed alongside the key
#[serde(deserialize_with = "deserialize_KeyModifiers")]
pub modifiers: KeyModifiers,
/// The actual key, that was pressed
#[serde(deserialize_with = "deserialize_Keysym", default)]
pub key: Option<Keysym>,
}
impl KeyPattern {
pub fn new(modifiers: impl Into<KeyModifiers>, key: Option<Keysym>) -> KeyPattern {
KeyPattern {
modifiers: modifiers.into(),
key,
}
}
pub fn inferred_direction(&self) -> Option<Direction> {
match self.key? {
Keysym::Left | Keysym::h | Keysym::H => Some(Direction::Left),
Keysym::Down | Keysym::j | Keysym::J => Some(Direction::Down),
Keysym::Up | Keysym::k | Keysym::K => Some(Direction::Up),
Keysym::Right | Keysym::l | Keysym::L => Some(Direction::Right),
_ => None,
}
}
}
impl ToString for KeyPattern {
fn to_string(&self) -> String {
let mut result = String::new();
if self.modifiers.logo {
result += "Super+";
}
if self.modifiers.ctrl {
result += "Ctrl+";
}
if self.modifiers.alt {
result += "Alt+";
}
if self.modifiers.shift {
result += "Shift+";
}
if let Some(key) = self.key {
result += &keysym_get_name(key);
} else {
result.remove(result.len() - 1);
}
result
}
}
#[derive(Debug, Deserialize, Clone, PartialEq, Eq)]
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Action {
Terminate,
Debug,
Close,
#[serde(skip)]
/// Behaviors managed internally by cosmic-comp.
Private(PrivateAction),
/// Behaviors managed via cosmic-settings.
Shortcut(shortcuts::Action),
}
#[derive(Clone, Debug, Eq, PartialEq)]
// Behaviors which are internally defined and emitted.
pub enum PrivateAction {
Escape,
Workspace(u8),
NextWorkspace,
PreviousWorkspace,
LastWorkspace,
MoveToWorkspace(u8),
MoveToNextWorkspace,
MoveToPreviousWorkspace,
MoveToLastWorkspace,
SendToWorkspace(u8),
SendToNextWorkspace,
SendToPreviousWorkspace,
SendToLastWorkspace,
NextOutput,
PreviousOutput,
MoveToNextOutput,
MoveToPreviousOutput,
SendToNextOutput,
SendToPreviousOutput,
SwitchOutput(Direction),
MoveToOutput(Direction),
SendToOutput(Direction),
MigrateWorkspaceToNextOutput,
MigrateWorkspaceToPreviousOutput,
MigrateWorkspaceToOutput(Direction),
Focus(FocusDirection),
Move(Direction),
ToggleOrientation,
Orientation(crate::shell::layout::Orientation),
ToggleStacking,
ToggleTiling,
ToggleWindowFloating,
ToggleSticky,
SwapWindow,
Resizing(ResizeDirection),
#[serde(skip)]
_ResizingInternal(ResizeDirection, ResizeEdge, KeyState),
Minimize,
Maximize,
Spawn(String),
Resizing(
shortcuts::action::ResizeDirection,
shortcuts::action::ResizeEdge,
shortcuts::State,
),
}
fn insert_binding(
key_bindings: &mut HashMap<KeyPattern, Action>,
modifiers: KeyModifiers,
keys: impl Iterator<Item = Keysym>,
action: Action,
) {
if !key_bindings.values().any(|a| a == &action) {
for key in keys {
let pattern = KeyPattern {
modifiers: modifiers.clone(),
key: Some(key),
};
if !key_bindings.contains_key(&pattern) {
key_bindings.insert(pattern, action.clone());
}
}
}
}
pub fn add_default_bindings(
key_bindings: &mut HashMap<KeyPattern, Action>,
workspace_layout: WorkspaceLayout,
) {
pub fn add_default_bindings(shortcuts: &mut Shortcuts, workspace_layout: WorkspaceLayout) {
let (
workspace_previous,
workspace_next,
@ -223,102 +31,110 @@ pub fn add_default_bindings(
(output_next, output_next_dir),
) = match workspace_layout {
WorkspaceLayout::Horizontal => (
[Keysym::Left, Keysym::h],
[Keysym::Right, Keysym::l],
([Keysym::Up, Keysym::k], Direction::Up),
([Keysym::Down, Keysym::j], Direction::Down),
[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 => (
[Keysym::Up, Keysym::k],
[Keysym::Down, Keysym::j],
([Keysym::Left, Keysym::h], Direction::Left),
([Keysym::Right, Keysym::l], Direction::Right),
[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,
),
),
};
insert_binding(
key_bindings,
KeyModifiers {
logo: true,
ctrl: true,
..Default::default()
},
shortcuts.insert_default_binding(
Modifiers::new().logo().ctrl(),
workspace_previous.iter().copied(),
Action::PreviousWorkspace,
);
insert_binding(
key_bindings,
KeyModifiers {
logo: true,
ctrl: true,
..Default::default()
},
workspace_next.iter().copied(),
Action::NextWorkspace,
);
insert_binding(
key_bindings,
KeyModifiers {
logo: true,
ctrl: true,
shift: true,
..Default::default()
},
workspace_previous.iter().copied(),
Action::MoveToPreviousWorkspace,
);
insert_binding(
key_bindings,
KeyModifiers {
logo: true,
ctrl: true,
shift: true,
..Default::default()
},
workspace_next.iter().copied(),
Action::MoveToNextWorkspace,
shortcuts::Action::PreviousWorkspace,
);
insert_binding(
key_bindings,
KeyModifiers {
logo: true,
ctrl: true,
..Default::default()
},
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(),
Action::SwitchOutput(output_previous_dir),
shortcuts::Action::SwitchOutput(output_previous_dir),
);
insert_binding(
key_bindings,
KeyModifiers {
logo: true,
ctrl: true,
..Default::default()
},
shortcuts.insert_default_binding(
Modifiers::new().logo().ctrl(),
output_next.iter().copied(),
Action::SwitchOutput(output_next_dir),
shortcuts::Action::SwitchOutput(output_next_dir),
);
insert_binding(
key_bindings,
KeyModifiers {
logo: true,
ctrl: true,
shift: true,
..Default::default()
},
shortcuts.insert_default_binding(
Modifiers::new().logo().ctrl().shift(),
output_previous.iter().copied(),
Action::MoveToOutput(output_previous_dir),
shortcuts::Action::MoveToOutput(output_previous_dir),
);
insert_binding(
key_bindings,
KeyModifiers {
logo: true,
ctrl: true,
shift: true,
..Default::default()
},
shortcuts.insert_default_binding(
Modifiers::new().logo().ctrl().shift(),
output_next.iter().copied(),
Action::MoveToOutput(output_next_dir),
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 {
KeyState::Pressed => smithay::backend::input::KeyState::Pressed,
KeyState::Released => smithay::backend::input::KeyState::Released,
}
}
/// Convert `smithay::backend::input::KeyState` to `cosmic_settings_config::shortcuts::State`.
pub fn cosmic_keystate_from_smithay(value: smithay::backend::input::KeyState) -> KeyState {
match value {
smithay::backend::input::KeyState::Pressed => KeyState::Pressed,
smithay::backend::input::KeyState::Released => KeyState::Released,
}
}
/// Compare `cosmic_settings_config::shortcuts::Modifiers` to `smithay::input::keyboard::ModifiersState`.
pub fn cosmic_modifiers_eq_smithay(this: &Modifiers, other: &ModifiersState) -> bool {
this.ctrl == other.ctrl
&& this.alt == other.alt
&& this.shift == other.shift
&& this.logo == other.logo
}
/// Convert `smithay::input::keyboard::ModifiersState` to `cosmic_settings_config::shortcuts::Modifiers`
pub fn cosmic_modifiers_from_smithay(value: ModifiersState) -> Modifiers {
Modifiers {
ctrl: value.ctrl,
alt: value.alt,
shift: value.shift,
logo: value.logo,
}
}

View file

@ -8,6 +8,7 @@ use crate::{
},
};
use cosmic_config::{ConfigGet, CosmicConfigEntry};
use cosmic_settings_config::{shortcuts, Shortcuts};
use serde::{Deserialize, Serialize};
use smithay::wayland::xdg_activation::XdgActivationState;
pub use smithay::{
@ -25,66 +26,33 @@ pub use smithay::{
};
use std::{
cell::RefCell,
collections::HashMap,
collections::{BTreeMap, HashMap},
fs::OpenOptions,
path::PathBuf,
sync::{atomic::AtomicBool, Arc, RwLock},
};
use tracing::{debug, error, info, warn};
use tracing::{error, warn};
mod input_config;
mod key_bindings;
pub use key_bindings::{Action, KeyModifier, KeyModifiers, KeyPattern};
pub mod key_bindings;
pub use key_bindings::{Action, PrivateAction};
mod types;
pub use self::types::*;
use cosmic_comp_config::{
input::InputConfig,
workspace::{WorkspaceConfig, WorkspaceLayout},
CosmicCompConfig, TileBehavior, XkbConfig,
input::InputConfig, workspace::WorkspaceConfig, CosmicCompConfig, TileBehavior, XkbConfig,
};
#[derive(Debug)]
pub struct Config {
pub static_conf: StaticConfig,
pub dynamic_conf: DynamicConfig,
pub cosmic_helper: cosmic_config::Config,
pub cosmic_conf: CosmicCompConfig,
}
#[derive(Debug, Deserialize)]
pub struct StaticConfig {
pub key_bindings: HashMap<key_bindings::KeyPattern, key_bindings::Action>,
pub data_control_enabled: bool,
}
impl StaticConfig {
pub fn get_shortcut_for_action(&self, action: &Action) -> Option<String> {
let possible_variants = self
.key_bindings
.iter()
.filter(|(_, a)| *a == action)
.map(|(b, _)| b)
.collect::<Vec<_>>();
possible_variants
.iter()
.find(|b| b.key.is_none()) // prefer short bindings
.or_else(|| {
possible_variants
.iter() // prefer bindings containing arrow keys
.find(|b| {
matches!(
b.key,
Some(Keysym::Down)
| Some(Keysym::Up)
| Some(Keysym::Left)
| Some(Keysym::Right)
)
})
})
.or_else(|| possible_variants.first()) // take the first one
.map(|binding| binding.to_string())
}
/// cosmic-config context for `com.system76.CosmicSettings.Shortcuts`
pub settings_context: cosmic_config::Config,
/// Key bindings from `com.system76.CosmicSettings.Shortcuts`
pub shortcuts: Shortcuts,
/// System actions from `com.system76.CosmicSettings.Shortcuts`
pub system_actions: BTreeMap<shortcuts::action::System, String>,
}
#[derive(Debug)]
@ -185,6 +153,7 @@ impl Config {
.expect("Failed to add cosmic-config to the event loop");
let xdg = xdg::BaseDirectories::new().ok();
let workspace = get_config::<WorkspaceConfig>(&config, "workspaces");
let cosmic_comp_config =
CosmicCompConfig::get_entry(&config).unwrap_or_else(|(errs, c)| {
for err in errs {
@ -192,72 +161,48 @@ impl Config {
}
c
});
Config {
static_conf: Self::load_static(xdg.as_ref(), workspace.workspace_layout),
dynamic_conf: Self::load_dynamic(xdg.as_ref()),
cosmic_conf: cosmic_comp_config,
cosmic_helper: config,
}
}
fn load_static(
xdg: Option<&xdg::BaseDirectories>,
workspace_layout: WorkspaceLayout,
) -> StaticConfig {
let mut locations = if let Some(base) = xdg {
vec![
base.get_config_file("cosmic-comp.ron"),
base.get_config_file("cosmic-comp/config.ron"),
]
} else {
Vec::with_capacity(3)
};
if cfg!(debug_assertions) {
if let Ok(mut cwd) = std::env::current_dir() {
cwd.push("config.ron");
locations.push(cwd);
}
}
locations.push(PathBuf::from("/etc/cosmic-comp/config.ron"));
locations.push(PathBuf::from("/etc/cosmic-comp.ron"));
// Source key bindings from com.system76.CosmicSettings.Shortcuts
let settings_context = shortcuts::context().unwrap();
let system_actions = shortcuts::system_actions(&config);
let mut shortcuts = shortcuts::shortcuts(&settings_context);
for path in locations {
debug!("Trying config location: {}", path.display());
if path.exists() {
info!("Using config at {}", path.display());
let Ok(file) = OpenOptions::new().read(true).open(path) else {
error!("Failed to open config file.");
continue;
};
match ron::de::from_reader::<_, StaticConfig>(file) {
Ok(mut config) => {
key_bindings::add_default_bindings(
&mut config.key_bindings,
workspace_layout,
);
return config;
// Add any missing default shortcuts recommended by the compositor.
key_bindings::add_default_bindings(&mut shortcuts, workspace.workspace_layout);
// Listen for updates to the keybindings config.
let source = cosmic_config::calloop::ConfigWatchSource::new(&settings_context).expect(
"failed to create config watch source for com.system76.CosmicSettings.Shortcuts",
);
_ = loop_handle.insert_source(source, |(config, keys), (), state| {
for key in keys {
match key.as_str() {
// Reload the keyboard shortcuts config.
"custom" | "defaults" => {
let mut shortcuts = shortcuts::shortcuts(&config);
let layout =
get_config::<WorkspaceConfig>(&config, "workspaces").workspace_layout;
key_bindings::add_default_bindings(&mut shortcuts, layout);
state.common.config.shortcuts = shortcuts;
}
Err(err) => {
error!("Malformed config file (skipping): {}", err);
continue;
"system_actions" => {
state.common.config.system_actions = shortcuts::system_actions(&config);
}
_ => (),
}
}
}
info!("No config found, consider installing a config file. Using default mapping.");
let mut config = ron::from_str(include_str!("../../config.ron")).unwrap_or_else(|err| {
debug!("Failed to load internal default config: {}", err);
StaticConfig {
// Small useful keybindings by default
key_bindings: HashMap::new(),
data_control_enabled: false,
}
});
key_bindings::add_default_bindings(&mut config.key_bindings, workspace_layout);
config
Config {
dynamic_conf: Self::load_dynamic(xdg.as_ref()),
cosmic_conf: cosmic_comp_config,
cosmic_helper: config,
settings_context,
shortcuts,
system_actions,
}
}
fn load_dynamic(xdg: Option<&xdg::BaseDirectories>) -> DynamicConfig {
@ -314,6 +259,10 @@ impl Config {
}
}
pub fn shortcut_for_action(&self, action: &shortcuts::Action) -> Option<String> {
self.shortcuts.shortcut_for_action(action)
}
pub fn read_outputs(
&mut self,
output_state: &mut OutputConfigurationState<State>,

View file

@ -1,15 +1,8 @@
// SPDX-License-Identifier: GPL-3.0-only
#![allow(non_snake_case)]
use super::{KeyModifier, KeyModifiers};
use serde::{Deserialize, Serialize};
use smithay::reexports::x11rb::NO_SYMBOL;
pub use smithay::{
input::keyboard::{Keysym, XkbConfig as WlXkbConfig},
utils::Transform,
};
use tracing::warn;
use xkbcommon::xkb;
pub use smithay::{input::keyboard::XkbConfig as WlXkbConfig, utils::Transform};
#[derive(Serialize, Deserialize)]
#[serde(remote = "Transform")]
@ -23,62 +16,3 @@ pub enum TransformDef {
Flipped180,
Flipped270,
}
#[derive(Deserialize)]
#[serde(transparent)]
pub struct KeyModifiersDef(Vec<KeyModifier>);
impl From<KeyModifiersDef> for KeyModifiers {
fn from(src: KeyModifiersDef) -> Self {
src.0.into_iter().fold(
KeyModifiers {
ctrl: false,
alt: false,
shift: false,
logo: false,
},
|mut modis, modi: KeyModifier| {
modis += modi;
modis
},
)
}
}
#[allow(non_snake_case)]
pub fn deserialize_KeyModifiers<'de, D>(deserializer: D) -> Result<KeyModifiers, D::Error>
where
D: serde::Deserializer<'de>,
{
KeyModifiersDef::deserialize(deserializer).map(Into::into)
}
#[allow(non_snake_case)]
pub fn deserialize_Keysym<'de, D>(deserializer: D) -> Result<Option<Keysym>, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::de::{Error, Unexpected};
let name = String::deserialize(deserializer)?;
//let name = format!("KEY_{}", code);
match xkb::keysym_from_name(&name, xkb::KEYSYM_NO_FLAGS) {
x if x.raw() == NO_SYMBOL => {
match xkb::keysym_from_name(&name, xkb::KEYSYM_CASE_INSENSITIVE) {
x if x.raw() == NO_SYMBOL => Err(<D::Error as Error>::invalid_value(
Unexpected::Str(&name),
&"One of the keysym names of xkbcommon.h without the 'KEY_' prefix",
)),
x => {
warn!(
"Key-Binding '{}' only matched case insensitive for {:?}",
name,
xkb::keysym_get_name(x)
);
Ok(Some(x))
}
}
}
x => Ok(Some(x)),
}
}

View file

@ -1,9 +1,8 @@
use cosmic_settings_config::shortcuts::action::Direction;
use smithay::utils::{Logical, Point};
use std::{collections::VecDeque, time::Duration};
use tracing::trace;
use crate::shell::Direction;
const HISTORY_LIMIT: Duration = Duration::from_millis(150);
const DECELERATION_TOUCHPAD: f64 = 0.997;

View file

@ -1,20 +1,23 @@
// SPDX-License-Identifier: GPL-3.0-only
use crate::{
config::{Action, Config, KeyModifiers, KeyPattern},
config::{
key_bindings::{
cosmic_keystate_from_smithay, cosmic_modifiers_eq_smithay,
cosmic_modifiers_from_smithay,
},
Action, Config, PrivateAction,
},
input::gestures::{GestureState, SwipeAction},
shell::{
focus::{
target::{KeyboardFocusTarget, PointerFocusTarget},
FocusDirection,
},
focus::target::{KeyboardFocusTarget, PointerFocusTarget},
grabs::{ReleaseMode, ResizeEdge},
layout::{
floating::ResizeGrabMarker,
tiling::{SwapWindowGrab, TilingLayout},
},
Direction, FocusResult, InvalidWorkspaceIndex, MoveResult, OverviewMode, ResizeDirection,
ResizeMode, SeatExt, Trigger, WorkspaceDelta,
FocusResult, InvalidWorkspaceIndex, MoveResult, OverviewMode, ResizeMode, SeatExt, Trigger,
WorkspaceDelta,
},
utils::prelude::*,
wayland::{
@ -28,6 +31,8 @@ use crate::{
use calloop::{timer::Timer, RegistrationToken};
use cosmic_comp_config::{workspace::WorkspaceLayout, TileBehavior};
use cosmic_config::ConfigSet;
use cosmic_settings_config::shortcuts;
use cosmic_settings_config::shortcuts::action::{Direction, FocusDirection, ResizeDirection};
use smithay::{
backend::input::{
AbsolutePositionEvent, Axis, AxisSource, Device, DeviceCapability, GestureBeginEvent,
@ -84,7 +89,7 @@ pub mod gestures;
#[derive(Default)]
pub struct SupressedKeys(RefCell<Vec<(Keycode, Option<RegistrationToken>)>>);
#[derive(Default, Debug)]
pub struct ModifiersShortcutQueue(RefCell<Option<KeyPattern>>);
pub struct ModifiersShortcutQueue(RefCell<Option<shortcuts::Binding>>);
impl SupressedKeys {
fn add(&self, keysym: &KeysymHandle, token: impl Into<Option<RegistrationToken>>) {
@ -112,12 +117,12 @@ impl SupressedKeys {
}
impl ModifiersShortcutQueue {
pub fn set(&self, binding: KeyPattern) {
pub fn set(&self, binding: shortcuts::Binding) {
let mut set = self.0.borrow_mut();
*set = Some(binding);
}
pub fn take(&self, binding: &KeyPattern) -> bool {
pub fn take(&self, binding: &shortcuts::Binding) -> bool {
let mut set = self.0.borrow_mut();
if set.is_some() && set.as_ref().unwrap() == binding {
*set = None;
@ -308,20 +313,19 @@ impl State {
&& handle.raw_syms().contains(&action_pattern.key.unwrap())
{
shell.set_resize_mode(None, &data.common.config, data.common.event_loop_handle.clone());
} else if action_pattern.modifiers != *modifiers {
} else if !cosmic_modifiers_eq_smithay(&action_pattern.modifiers, modifiers) {
let mut new_pattern = action_pattern.clone();
new_pattern.modifiers = modifiers.clone().into();
new_pattern.modifiers = cosmic_modifiers_from_smithay(modifiers.clone());
let enabled = data
.common
.config
.static_conf
.key_bindings
.shortcuts
.iter()
.find_map(move |(binding, action)| {
if binding == &new_pattern
&& matches!(action, Action::Resizing(_))
&& matches!(action, shortcuts::Action::Resizing(_))
{
let Action::Resizing(direction) = action else { unreachable!() };
let shortcuts::Action::Resizing(direction) = action else { unreachable!() };
Some((new_pattern.clone(), *direction))
} else {
None
@ -347,10 +351,11 @@ impl State {
if direction == ResizeDirection::Inwards {
edge.flip_direction();
}
let action = Action::_ResizingInternal(direction, edge, state);
let key_pattern = KeyPattern {
modifiers: modifiers.clone().into(),
let action = Action::Private(PrivateAction::Resizing(direction, edge.into(), cosmic_keystate_from_smithay(state)));
let key_pattern = shortcuts::Binding {
modifiers: cosmic_modifiers_from_smithay(modifiers.clone()),
key: Some(Keysym::new(handle.raw_code().raw())),
description: None,
};
if state == KeyState::Released {
@ -394,10 +399,11 @@ impl State {
seat.supressed_keys()
.add(&handle, None);
return FilterResult::Intercept(Some((
Action::Escape,
KeyPattern {
modifiers: KeyModifiers::default(),
Action::Private(PrivateAction::Escape),
shortcuts::Binding {
modifiers: shortcuts::Modifiers::default(),
key: Some(Keysym::Escape),
description: None,
}
)));
}
@ -432,15 +438,16 @@ impl State {
let mut can_clear_modifiers_shortcut = true;
if !shortcuts_inhibited {
let modifiers_queue = seat.modifiers_shortcut_queue();
for (binding, action) in
data.common.config.static_conf.key_bindings.iter()
data.common.config.shortcuts.iter()
{
let modifiers_bypass = binding.key.is_none()
&& state == KeyState::Released
&& binding.modifiers != *modifiers
&& !cosmic_modifiers_eq_smithay(&binding.modifiers, modifiers)
&& modifiers_queue.take(binding);
if !modifiers_bypass && binding.key.is_none() && state == KeyState::Pressed && binding.modifiers == *modifiers {
if !modifiers_bypass && binding.key.is_none() && state == KeyState::Pressed && cosmic_modifiers_eq_smithay(&binding.modifiers, modifiers) {
modifiers_queue.set(binding.clone());
can_clear_modifiers_shortcut = false;
}
@ -449,13 +456,13 @@ impl State {
binding.key.is_some()
&& state == KeyState::Pressed
&& handle.raw_syms().contains(&binding.key.unwrap())
&& binding.modifiers == *modifiers
&& cosmic_modifiers_eq_smithay(&binding.modifiers, modifiers)
) || modifiers_bypass
{
modifiers_queue.clear();
seat.supressed_keys().add(&handle, None);
return FilterResult::Intercept(Some((
action.clone(),
Action::Shortcut(action.clone()),
binding.clone(),
)));
}
@ -503,7 +510,9 @@ impl State {
Some(constraint) if constraint.is_active() => {
// Constraint does not apply if not within region
if !constraint.region().map_or(true, |x| {
x.contains((ptr.current_location() - *surface_loc).to_i32_round())
x.contains(
(ptr.current_location() - *surface_loc).to_i32_round(),
)
}) {
return;
}
@ -1567,43 +1576,27 @@ impl State {
seat: &Seat<State>,
serial: Serial,
time: u32,
pattern: KeyPattern,
pattern: shortcuts::Binding,
direction: Option<Direction>,
propagate: bool,
) {
// TODO: Detect if started from login manager or tty, and only allow
// `Terminate` if it will return to login manager.
if self.common.shell.read().unwrap().session_lock.is_some()
&& !matches!(action, Action::Terminate | Action::Debug)
&& !matches!(
action,
Action::Shortcut(shortcuts::Action::Terminate)
| Action::Shortcut(shortcuts::Action::Debug)
)
{
return;
}
match action {
Action::Terminate => {
self.common.should_stop = true;
}
#[cfg(feature = "debug")]
Action::Debug => {
let mut shell = self.common.shell.write().unwrap();
shell.debug_active = !shell.debug_active;
for mapped in shell.workspaces.spaces().flat_map(|w| w.mapped()) {
mapped.set_debug(shell.debug_active);
}
}
#[cfg(not(feature = "debug"))]
Action::Debug => {
info!("Debug overlay not included in this build.")
}
Action::Close => {
let current_output = seat.active_output();
let shell = self.common.shell.read().unwrap();
let workspace = shell.active_space(&current_output);
if let Some(window) = workspace.focus_stack.get(seat).last() {
window.send_close();
}
}
Action::Escape => {
Action::Shortcut(action) => self
.handle_shortcut_action(action, seat, serial, time, pattern, direction, propagate),
Action::Private(PrivateAction::Escape) => {
{
let mut shell = self.common.shell.write().unwrap();
shell.set_overview_mode(None, self.common.event_loop_handle.clone());
@ -1622,6 +1615,65 @@ impl State {
keyboard.unset_grab(self);
}
}
Action::Private(PrivateAction::Resizing(direction, edge, state)) => {
if state == shortcuts::State::Pressed {
self.common
.shell
.write()
.unwrap()
.resize(seat, direction, edge.into());
} else {
self.common
.shell
.write()
.unwrap()
.finish_resize(direction, edge.into());
}
}
}
}
pub fn handle_shortcut_action(
&mut self,
action: shortcuts::Action,
seat: &Seat<State>,
serial: Serial,
time: u32,
pattern: shortcuts::Binding,
direction: Option<Direction>,
propagate: bool,
) {
use shortcuts::Action;
match action {
Action::Terminate => {
self.common.should_stop = true;
}
#[cfg(feature = "debug")]
Action::Debug => {
let mut shell = self.common.shell.write().unwrap();
shell.debug_active = !shell.debug_active;
for mapped in shell.workspaces.spaces().flat_map(|w| w.mapped()) {
mapped.set_debug(shell.debug_active);
}
}
#[cfg(not(feature = "debug"))]
Action::Debug => {
info!("Debug overlay not included in this build.")
}
Action::Close => {
let current_output = seat.active_output();
let shell = self.common.shell.read().unwrap();
let workspace = shell.active_space(&current_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 {
@ -1635,6 +1687,7 @@ impl State {
&mut self.common.workspace_state.update(),
);
}
Action::LastWorkspace => {
let current_output = seat.active_output();
let mut shell = self.common.shell.write().unwrap();
@ -1646,6 +1699,7 @@ impl State {
&mut self.common.workspace_state.update(),
);
}
Action::NextWorkspace => {
let next = to_next_workspace(
&mut *self.common.shell.write().unwrap(),
@ -1655,7 +1709,7 @@ impl State {
);
if next.is_err() && propagate {
if let Some(inferred) = pattern.inferred_direction() {
self.handle_action(
self.handle_shortcut_action(
Action::SwitchOutput(inferred),
seat,
serial,
@ -1667,6 +1721,7 @@ impl State {
};
}
}
Action::PreviousWorkspace => {
let previous = to_previous_workspace(
&mut *self.common.shell.write().unwrap(),
@ -1676,7 +1731,7 @@ impl State {
);
if previous.is_err() && propagate {
if let Some(inferred) = pattern.inferred_direction() {
self.handle_action(
self.handle_shortcut_action(
Action::SwitchOutput(inferred),
seat,
serial,
@ -1688,6 +1743,7 @@ impl State {
};
}
}
x @ Action::MoveToWorkspace(_) | x @ Action::SendToWorkspace(_) => {
let current_output = seat.active_output();
let follow = matches!(x, Action::MoveToWorkspace(_));
@ -1708,6 +1764,7 @@ impl State {
Shell::set_focus(self, Some(&target), seat, None);
}
}
x @ Action::MoveToLastWorkspace | x @ Action::SendToLastWorkspace => {
let current_output = seat.active_output();
let mut shell = self.common.shell.write().unwrap();
@ -1725,6 +1782,7 @@ impl State {
Shell::set_focus(self, Some(&target), seat, None);
}
}
x @ Action::MoveToNextWorkspace | x @ Action::SendToNextWorkspace => {
let current_output = seat.active_output();
let res = {
@ -1750,7 +1808,7 @@ impl State {
}
Err(_) if propagate => {
if let Some(inferred) = pattern.inferred_direction() {
self.handle_action(
self.handle_shortcut_action(
if matches!(x, Action::MoveToNextWorkspace) {
Action::MoveToOutput(inferred)
} else {
@ -1768,6 +1826,7 @@ impl State {
_ => {}
}
}
x @ Action::MoveToPreviousWorkspace | x @ Action::SendToPreviousWorkspace => {
let current_output = seat.active_output();
let res = {
@ -1794,7 +1853,7 @@ impl State {
}
Err(_) if propagate => {
if let Some(inferred) = pattern.inferred_direction() {
self.handle_action(
self.handle_shortcut_action(
if matches!(x, Action::MoveToPreviousWorkspace) {
Action::MoveToOutput(inferred)
} else {
@ -1812,6 +1871,7 @@ impl State {
_ => {}
}
}
Action::SwitchOutput(direction) => {
let current_output = seat.active_output();
let mut shell = self.common.shell.write().unwrap();
@ -1850,35 +1910,36 @@ impl State {
}
} else if propagate {
std::mem::drop(shell);
match (
let action = match (
direction,
self.common.config.cosmic_conf.workspaces.workspace_layout,
) {
(Direction::Left, WorkspaceLayout::Horizontal)
| (Direction::Up, WorkspaceLayout::Vertical) => self.handle_action(
Action::PreviousWorkspace,
seat,
serial,
time,
pattern,
Some(direction),
false,
),
| (Direction::Up, WorkspaceLayout::Vertical) => {
Some(Action::PreviousWorkspace)
}
(Direction::Right, WorkspaceLayout::Horizontal)
| (Direction::Down, WorkspaceLayout::Vertical) => self.handle_action(
Action::NextWorkspace,
| (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();
@ -1921,6 +1982,7 @@ impl State {
}
}
}
Action::PreviousOutput => {
let current_output = seat.active_output();
let mut shell = self.common.shell.write().unwrap();
@ -1964,6 +2026,7 @@ impl State {
}
}
}
action @ Action::MoveToOutput(_) | action @ Action::SendToOutput(_) => {
let is_move_action = matches!(action, Action::MoveToOutput(_));
let direction = match action {
@ -2008,30 +2071,33 @@ impl State {
self.common.config.cosmic_conf.workspaces.workspace_layout,
) {
(Direction::Left, WorkspaceLayout::Horizontal)
| (Direction::Up, WorkspaceLayout::Vertical) => self.handle_action(
Action::MoveToPreviousWorkspace,
seat,
serial,
time,
pattern,
Some(direction),
false,
),
| (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_action(
Action::MoveToNextWorkspace,
seat,
serial,
time,
pattern,
Some(direction),
false,
),
| (Direction::Down, WorkspaceLayout::Vertical) => self
.handle_shortcut_action(
Action::MoveToNextWorkspace,
seat,
serial,
time,
pattern,
Some(direction),
false,
),
_ => {}
}
}
}
x @ Action::MoveToNextOutput | x @ Action::SendToNextOutput => {
let current_output = seat.active_output();
let mut shell = self.common.shell.write().unwrap();
@ -2069,6 +2135,7 @@ impl State {
}
}
}
x @ Action::MoveToPreviousOutput | x @ Action::SendToPreviousOutput => {
let current_output = seat.active_output();
let mut shell = self.common.shell.write().unwrap();
@ -2107,6 +2174,7 @@ impl State {
}
}
}
Action::MigrateWorkspaceToNextOutput => {
let current_output = seat.active_output();
let (active, next_output) = {
@ -2125,6 +2193,7 @@ impl State {
.migrate_workspace(&current_output, &next_output, &active);
}
}
Action::MigrateWorkspaceToPreviousOutput => {
let current_output = seat.active_output();
let (active, prev_output) = {
@ -2144,6 +2213,7 @@ impl State {
.migrate_workspace(&current_output, &prev_output, &active);
}
}
Action::MigrateWorkspaceToOutput(direction) => {
let current_output = seat.active_output();
let (active, next_output) = {
@ -2160,6 +2230,7 @@ impl State {
.migrate_workspace(&current_output, &next_output, &active);
}
}
Action::Focus(focus) => {
let result = self.common.shell.read().unwrap().next_focus(focus, seat);
@ -2174,7 +2245,7 @@ impl State {
};
if let Some(direction) = dir {
self.handle_action(
self.handle_shortcut_action(
Action::SwitchOutput(direction),
seat,
serial,
@ -2191,6 +2262,7 @@ impl State {
}
}
}
Action::Move(direction) => {
let res = self
.common
@ -2199,7 +2271,7 @@ impl State {
.unwrap()
.move_current_element(direction, seat);
match res {
MoveResult::MoveFurther(_move_further) => self.handle_action(
MoveResult::MoveFurther(_move_further) => self.handle_shortcut_action(
Action::MoveToOutput(direction),
seat,
serial,
@ -2226,6 +2298,7 @@ impl State {
}
}
}
Action::SwapWindow => {
let current_output = seat.active_output();
let mut shell = self.common.shell.write().unwrap();
@ -2249,6 +2322,7 @@ impl State {
}
}
}
Action::Minimize => {
let current_output = seat.active_output();
let mut shell = self.common.shell.write().unwrap();
@ -2259,6 +2333,7 @@ impl State {
shell.minimize_request(&window);
}
}
Action::Maximize => {
let current_output = seat.active_output();
let mut shell = self.common.shell.write().unwrap();
@ -2269,32 +2344,20 @@ impl State {
shell.maximize_toggle(&window, seat);
}
}
Action::Resizing(direction) => self.common.shell.write().unwrap().set_resize_mode(
Some((pattern, direction)),
&self.common.config,
self.common.event_loop_handle.clone(),
),
Action::_ResizingInternal(direction, edge, state) => {
if state == KeyState::Pressed {
self.common
.shell
.write()
.unwrap()
.resize(seat, direction, edge);
} else {
self.common
.shell
.write()
.unwrap()
.finish_resize(direction, edge);
}
}
Action::ToggleOrientation => {
let output = seat.active_output();
let mut shell = self.common.shell.write().unwrap();
let workspace = shell.active_space_mut(&output);
workspace.tiling_layer.update_orientation(None, &seat);
}
Action::Orientation(orientation) => {
let output = seat.active_output();
let mut shell = self.common.shell.write().unwrap();
@ -2303,6 +2366,7 @@ impl State {
.tiling_layer
.update_orientation(Some(orientation), &seat);
}
Action::ToggleStacking => {
let res = self
.common
@ -2314,6 +2378,7 @@ impl State {
Shell::set_focus(self, Some(&new_focus), seat, Some(serial));
}
}
Action::ToggleTiling => {
if matches!(
self.common.config.cosmic_conf.autotile_behavior,
@ -2345,12 +2410,14 @@ impl State {
workspace.toggle_tiling(seat, &mut guard);
}
}
Action::ToggleWindowFloating => {
let output = seat.active_output();
let mut shell = self.common.shell.write().unwrap();
let workspace = shell.active_space_mut(&output);
workspace.toggle_floating_window_focused(seat);
}
Action::ToggleSticky => {
self.common
.shell
@ -2358,51 +2425,64 @@ impl State {
.unwrap()
.toggle_sticky_current(seat);
}
Action::Spawn(command) => {
let mut shell = self.common.shell.write().unwrap();
let (token, data) = self.common.xdg_activation_state.create_external_token(None);
let (token, data) = (token.clone(), data.clone());
let output = shell.seats.last_active().active_output();
let workspace = shell.active_space_mut(&output);
workspace.pending_tokens.insert(token.clone());
let handle = workspace.handle;
std::mem::drop(shell);
data.user_data
.insert_if_missing(move || ActivationContext::Workspace(handle));
let wayland_display = self.common.socket.clone();
let display = self
.common
.xwayland_state
.as_ref()
.map(|s| format!(":{}", s.display))
.unwrap_or_default();
let mut cmd = std::process::Command::new("/bin/sh");
cmd.arg("-c")
.arg(command.clone())
.env("WAYLAND_DISPLAY", &wayland_display)
.env("DISPLAY", &display)
.env("XDG_ACTIVATION_TOKEN", &*token)
.env("DESKTOP_STARTUP_ID", &*token)
.env_remove("COSMIC_SESSION_SOCK");
unsafe { cmd.pre_exec(|| Ok(crate::utils::rlimit::restore_nofile_limit())) };
std::thread::spawn(move || match cmd.spawn() {
Ok(mut child) => {
let _res = child.wait();
}
Err(err) => {
tracing::warn!(?err, "Failed to spawn \"{}\"", command);
}
});
// Gets the configured command for a given system action.
Action::System(system) => {
if let Some(command) = self.common.config.system_actions.get(&system) {
self.spawn_command(command.clone());
}
}
Action::Spawn(command) => self.spawn_command(command),
// Do nothing
Action::Disable => (),
}
}
fn spawn_command(&mut self, command: String) {
let mut shell = self.common.shell.write().unwrap();
let (token, data) = self.common.xdg_activation_state.create_external_token(None);
let (token, data) = (token.clone(), data.clone());
let output = shell.seats.last_active().active_output();
let workspace = shell.active_space_mut(&output);
workspace.pending_tokens.insert(token.clone());
let handle = workspace.handle;
std::mem::drop(shell);
data.user_data
.insert_if_missing(move || ActivationContext::Workspace(handle));
let wayland_display = self.common.socket.clone();
let display = self
.common
.xwayland_state
.as_ref()
.map(|s| format!(":{}", s.display))
.unwrap_or_default();
let mut cmd = std::process::Command::new("/bin/sh");
cmd.arg("-c")
.arg(&command)
.env("WAYLAND_DISPLAY", &wayland_display)
.env("DISPLAY", &display)
.env("XDG_ACTIVATION_TOKEN", &*token)
.env("DESKTOP_STARTUP_ID", &*token)
.env_remove("COSMIC_SESSION_SOCK");
unsafe { cmd.pre_exec(|| Ok(crate::utils::rlimit::restore_nofile_limit())) };
std::thread::spawn(move || match cmd.spawn() {
Ok(mut child) => {
let _res = child.wait();
}
Err(err) => {
tracing::warn!(?err, "Failed to spawn \"{}\"", command);
}
});
}
// TODO: Try to get rid of the *mutable* Shell references (needed for hovered_stack in floating_layout)
pub fn surface_under(
global_pos: Point<f64, Global>,
@ -2463,8 +2543,11 @@ impl State {
geo,
));
}
PointerFocusTarget::under_surface(window, relative_pos.as_logical())
.map(|(target, surface_loc)| (target, (output_geo.loc + surface_loc.as_global()).to_f64()))
PointerFocusTarget::under_surface(window, relative_pos.as_logical()).map(
|(target, surface_loc)| {
(target, (output_geo.loc + surface_loc.as_global()).to_f64())
},
)
} else {
{
let layers = layer_map_for_output(output);

View file

@ -72,13 +72,14 @@ use smithay::desktop::WindowSurface;
use tracing::debug;
use super::{
focus::{target::PointerFocusTarget, FocusDirection},
focus::target::PointerFocusTarget,
layout::{
floating::{ResizeState, TiledCorners},
tiling::NodeDesc,
},
Direction, ManagedLayer, SeatExt,
ManagedLayer, SeatExt,
};
use cosmic_settings_config::shortcuts::action::{Direction, FocusDirection};
space_elements! {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]

View file

@ -1,9 +1,9 @@
use std::sync::Mutex;
use crate::{
config::{Action, Config},
config::Config,
fl,
shell::{grabs::ResizeEdge, ResizeDirection},
shell::grabs::ResizeEdge,
utils::iced::{IcedElement, Program},
};
@ -15,6 +15,7 @@ use cosmic::{
widget::{icon::from_name, text},
Apply,
};
use cosmic_settings_config::shortcuts::action::{Action, ResizeDirection};
use smithay::utils::Size;
pub type ResizeIndicator = IcedElement<ResizeIndicatorInternal>;
@ -30,8 +31,7 @@ pub fn resize_indicator(
edges: Mutex::new(ResizeEdge::all()),
direction,
shortcut1: config
.static_conf
.key_bindings
.shortcuts
.iter()
.find_map(|(pattern, action)| {
(*action == Action::Resizing(ResizeDirection::Outwards)).then_some(pattern)
@ -39,8 +39,7 @@ pub fn resize_indicator(
.map(|pattern| format!("{}: ", pattern.to_string()))
.unwrap_or_else(|| crate::fl!("unknown-keybinding")),
shortcut2: config
.static_conf
.key_bindings
.shortcuts
.iter()
.find_map(|(pattern, action)| {
(*action == Action::Resizing(ResizeDirection::Inwards)).then_some(pattern)

View file

@ -2,10 +2,9 @@ use super::{surface::RESIZE_BORDER, window::Focus, CosmicSurface};
use crate::{
backend::render::cursor::{CursorShape, CursorState},
shell::{
focus::{target::PointerFocusTarget, FocusDirection},
focus::target::PointerFocusTarget,
grabs::{ReleaseMode, ResizeEdge},
layout::tiling::NodeDesc,
Direction,
},
state::State,
utils::{
@ -21,7 +20,9 @@ use cosmic::{
iced_widget::scrollable::AbsoluteOffset,
theme, widget as cosmic_widget, Apply, Element as CosmicElement,
};
use cosmic_settings_config::shortcuts;
use once_cell::sync::Lazy;
use shortcuts::action::{Direction, FocusDirection};
use smithay::{
backend::{
input::KeyState,

View file

@ -27,16 +27,6 @@ use super::{layout::floating::FloatingLayout, SeatExt};
pub mod target;
#[derive(Debug, serde::Deserialize, Clone, Copy, PartialEq, Eq)]
pub enum FocusDirection {
Left,
Right,
Up,
Down,
In,
Out,
}
pub struct FocusStack<'a>(pub(super) Option<&'a IndexSet<CosmicMapped>>);
pub struct FocusStackMut<'a>(pub(super) &'a mut IndexSet<CosmicMapped>);

View file

@ -1,7 +1,8 @@
use cosmic_settings_config::shortcuts::Action;
use smithay::{input::pointer::MotionEvent, utils::SERIAL_COUNTER, wayland::seat::WaylandFocus};
use crate::{
config::{Action, StaticConfig},
config::Config,
fl,
shell::{
element::{CosmicMapped, CosmicWindow},
@ -93,7 +94,7 @@ pub fn tab_items(
stack: &CosmicMapped,
tab: &CosmicSurface,
is_tiled: bool,
config: &StaticConfig,
config: &Config,
) -> impl Iterator<Item = Item> {
let unstack_clone_stack = stack.clone();
let unstack_clone_tab = tab.clone();
@ -145,7 +146,7 @@ pub fn tab_items(
Item::new(fl!("window-menu-close"), move |_handle| {
close_clone.close();
})
.shortcut(config.get_shortcut_for_action(&Action::Close)),
.shortcut(config.shortcut_for_action(&Action::Close)),
]
.into_iter()
}
@ -157,7 +158,7 @@ pub fn window_items(
is_sticky: bool,
tiling_enabled: bool,
possible_resizes: ResizeEdge,
config: &StaticConfig,
config: &Config,
) -> impl Iterator<Item = Item> {
let minimize_clone = window.clone();
let maximize_clone = window.clone();
@ -181,7 +182,7 @@ pub fn window_items(
let mapped = stack_clone.clone();
let _ = handle.insert_idle(move |state| toggle_stacking(state, &mapped));
})
.shortcut(config.get_shortcut_for_action(&Action::ToggleStacking)),
.shortcut(config.shortcut_for_action(&Action::ToggleStacking)),
),
is_stacked.then_some(
Item::new(fl!("window-menu-unstack-all"), move |handle| {
@ -190,7 +191,7 @@ pub fn window_items(
toggle_stacking(state, &mapped);
});
})
.shortcut(config.get_shortcut_for_action(&Action::ToggleStacking)),
.shortcut(config.shortcut_for_action(&Action::ToggleStacking)),
),
Some(Item::Separator),
Some(
@ -205,7 +206,7 @@ pub fn window_items(
.minimize_request(&mapped);
});
})
.shortcut(config.get_shortcut_for_action(&Action::Minimize)),
.shortcut(config.shortcut_for_action(&Action::Minimize)),
),
Some(
Item::new(fl!("window-menu-maximize"), move |handle| {
@ -216,7 +217,7 @@ pub fn window_items(
shell.maximize_toggle(&mapped, &seat);
});
})
.shortcut(config.get_shortcut_for_action(&Action::Maximize))
.shortcut(config.shortcut_for_action(&Action::Maximize))
.toggled(window.is_maximized(false)),
),
(tiling_enabled && !is_sticky).then_some(
@ -230,7 +231,7 @@ pub fn window_items(
}
});
})
.shortcut(config.get_shortcut_for_action(&Action::ToggleWindowFloating))
.shortcut(config.shortcut_for_action(&Action::ToggleWindowFloating))
.toggled(!is_tiled),
),
Some(Item::Separator),
@ -410,7 +411,7 @@ pub fn window_items(
let mapped = move_prev_clone.clone();
let _ = handle.insert_idle(move |state| move_prev_workspace(state, &mapped));
})
.shortcut(config.get_shortcut_for_action(&Action::MoveToPreviousWorkspace))
.shortcut(config.shortcut_for_action(&Action::MoveToPreviousWorkspace))
.disabled(is_sticky),
),
Some(
@ -418,7 +419,7 @@ pub fn window_items(
let mapped = move_next_clone.clone();
let _ = handle.insert_idle(move |state| move_next_workspace(state, &mapped));
})
.shortcut(config.get_shortcut_for_action(&Action::MoveToNextWorkspace))
.shortcut(config.shortcut_for_action(&Action::MoveToNextWorkspace))
.disabled(is_sticky),
),
Some(Item::Separator),
@ -445,7 +446,7 @@ pub fn window_items(
Item::new(fl!("window-menu-close"), move |_handle| {
close_clone.send_close();
})
.shortcut(config.get_shortcut_for_action(&Action::Close)),
.shortcut(config.shortcut_for_action(&Action::Close)),
)
},
]

View file

@ -1,3 +1,4 @@
use cosmic_settings_config::shortcuts;
use smithay::{
input::{
pointer::{
@ -106,6 +107,36 @@ impl ResizeEdge {
}
}
impl From<shortcuts::action::ResizeEdge> for ResizeEdge {
fn from(edge: shortcuts::action::ResizeEdge) -> Self {
match edge {
shortcuts::action::ResizeEdge::Bottom => ResizeEdge::BOTTOM,
shortcuts::action::ResizeEdge::BottomLeft => ResizeEdge::BOTTOM_LEFT,
shortcuts::action::ResizeEdge::BottomRight => ResizeEdge::BOTTOM_RIGHT,
shortcuts::action::ResizeEdge::Left => ResizeEdge::LEFT,
shortcuts::action::ResizeEdge::Right => ResizeEdge::RIGHT,
shortcuts::action::ResizeEdge::Top => ResizeEdge::TOP,
shortcuts::action::ResizeEdge::TopLeft => ResizeEdge::TOP_LEFT,
shortcuts::action::ResizeEdge::TopRight => ResizeEdge::TOP_RIGHT,
}
}
}
impl Into<shortcuts::action::ResizeEdge> for ResizeEdge {
fn into(self) -> shortcuts::action::ResizeEdge {
match self {
ResizeEdge::BOTTOM => shortcuts::action::ResizeEdge::Bottom,
ResizeEdge::BOTTOM_LEFT => shortcuts::action::ResizeEdge::BottomLeft,
ResizeEdge::BOTTOM_RIGHT => shortcuts::action::ResizeEdge::BottomRight,
ResizeEdge::LEFT => shortcuts::action::ResizeEdge::Left,
ResizeEdge::RIGHT => shortcuts::action::ResizeEdge::Right,
ResizeEdge::TOP => shortcuts::action::ResizeEdge::Top,
ResizeEdge::TOP_LEFT => shortcuts::action::ResizeEdge::TopLeft,
_ => shortcuts::action::ResizeEdge::TopRight,
}
}
}
impl From<xdg_toplevel::ResizeEdge> for ResizeEdge {
#[inline]
fn from(x: xdg_toplevel::ResizeEdge) -> Self {

View file

@ -863,7 +863,8 @@ impl Drop for MoveGrab {
state,
Some((
target,
position.as_logical().to_f64() - window.geometry().loc.to_f64() + offset,
position.as_logical().to_f64() - window.geometry().loc.to_f64()
+ offset,
)),
&MotionEvent {
location: pointer.current_location(),

View file

@ -6,6 +6,7 @@ use std::{
time::{Duration, Instant},
};
use cosmic_settings_config::shortcuts::action::ResizeDirection;
use keyframe::{ease, functions::EaseInOutCubic};
use smithay::{
backend::renderer::{
@ -36,7 +37,7 @@ use crate::{
FocusStackMut,
},
grabs::{GrabStartData, ReleaseMode, ResizeEdge},
CosmicSurface, Direction, ManagedLayer, MoveResult, ResizeDirection, ResizeMode,
CosmicSurface, Direction, ManagedLayer, MoveResult, ResizeMode,
},
state::State,
utils::{prelude::*, tween::EaseRectangle},

View file

@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-3.0-only
use cosmic_settings_config::shortcuts::action::Orientation;
use regex::RegexSet;
use smithay::{
desktop::WindowSurface,
@ -12,22 +13,6 @@ use super::CosmicSurface;
pub mod floating;
pub mod tiling;
#[derive(Debug, serde::Deserialize, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Orientation {
Horizontal,
Vertical,
}
impl std::ops::Not for Orientation {
type Output = Self;
fn not(self) -> Self::Output {
match self {
Orientation::Horizontal => Orientation::Vertical,
Orientation::Vertical => Orientation::Horizontal,
}
}
}
lazy_static::lazy_static! {
static ref EXCEPTIONS_APPID: RegexSet = RegexSet::new(&[
r"Authy Desktop",

View file

@ -1,3 +1,4 @@
use cosmic_settings_config::shortcuts;
use smithay::{
backend::input::KeyState,
input::{
@ -12,7 +13,7 @@ use smithay::{
use xkbcommon::xkb::Keysym;
use crate::{
config::{Action, KeyPattern},
config::key_bindings::cosmic_modifiers_from_smithay,
shell::{layout::tiling::NodeDesc, OverviewMode, Trigger},
state::State,
};
@ -53,12 +54,11 @@ impl KeyboardGrab<State> for SwapWindowGrab {
let focus_bindings = &data
.common
.config
.static_conf
.key_bindings
.shortcuts
.iter()
.filter(|(_, action)| matches!(action, Action::Focus(_)))
.filter(|(_, action)| matches!(action, shortcuts::Action::Focus(_)))
.map(|(pattern, action)| {
let Action::Focus(direction) = action else {
let shortcuts::Action::Focus(direction) = action else {
unreachable!()
};
(pattern.key, *direction)
@ -72,14 +72,17 @@ impl KeyboardGrab<State> for SwapWindowGrab {
return;
};
data.handle_action(
Action::Focus(direction),
data.handle_shortcut_action(
shortcuts::Action::Focus(direction),
&self.seat,
serial,
time,
KeyPattern {
modifiers: modifiers.map(Into::into).unwrap_or_default(),
shortcuts::Binding {
modifiers: modifiers
.map(cosmic_modifiers_from_smithay)
.unwrap_or_default(),
key: Some(Keysym::new(keycode)),
description: None,
},
None,
true,

View file

@ -18,12 +18,12 @@ use crate::{
},
focus::{
target::{KeyboardFocusTarget, PointerFocusTarget, WindowGroup},
FocusDirection, FocusStackMut,
FocusStackMut,
},
grabs::ResizeEdge,
layout::Orientation,
CosmicSurface, Direction, FocusResult, MoveResult, OutputNotMapped, OverviewMode,
ResizeDirection, ResizeMode, Trigger,
ResizeMode, Trigger,
},
utils::{prelude::*, tween::EaseRectangle},
wayland::{
@ -38,6 +38,7 @@ use crate::{
},
};
use cosmic_settings_config::shortcuts::action::{FocusDirection, ResizeDirection};
use id_tree::{InsertBehavior, MoveBehavior, Node, NodeId, NodeIdError, RemoveBehavior, Tree};
use keyframe::{
ease,

View file

@ -15,6 +15,8 @@ use cosmic_comp_config::{
use cosmic_protocols::workspace::v1::server::zcosmic_workspace_handle_v1::{
State as WState, TilingState,
};
use cosmic_settings_config::shortcuts;
use cosmic_settings_config::shortcuts::action::{Direction, FocusDirection, ResizeDirection};
use keyframe::{ease, functions::EaseInOutCubic};
use smithay::{
backend::{input::TouchSlot, renderer::element::RenderElementStates},
@ -49,7 +51,7 @@ use smithay::{
use crate::{
backend::render::animations::spring::{Spring, SpringParams},
config::{Config, KeyModifiers, KeyPattern},
config::Config,
utils::prelude::*,
wayland::{
handlers::{
@ -78,16 +80,14 @@ mod workspace;
pub use self::element::{CosmicMapped, CosmicMappedRenderElement, CosmicSurface};
pub use self::seats::*;
pub use self::workspace::*;
use self::{
element::{
resize_indicator::{resize_indicator, ResizeIndicator},
swap_indicator::{swap_indicator, SwapIndicator},
CosmicWindow, MaximizedState,
},
focus::{
target::{KeyboardFocusTarget, PointerFocusTarget},
FocusDirection,
},
focus::target::{KeyboardFocusTarget, PointerFocusTarget},
grabs::{
tab_items, window_items, GrabStartData, Item, MenuGrab, MoveGrab, ReleaseMode, ResizeEdge,
ResizeGrab,
@ -106,8 +106,8 @@ const MOVE_GRAB_Y_OFFSET: f64 = 16.;
#[derive(Debug, Clone)]
pub enum Trigger {
KeyboardSwap(KeyPattern, NodeDesc),
KeyboardMove(KeyModifiers),
KeyboardSwap(shortcuts::Binding, NodeDesc),
KeyboardMove(shortcuts::Modifiers),
Pointer(u32),
Touch(TouchSlot),
}
@ -141,16 +141,10 @@ impl OverviewMode {
}
}
#[derive(Debug, Clone, Copy, serde::Deserialize, PartialEq, Eq, Hash)]
pub enum ResizeDirection {
Inwards,
Outwards,
}
#[derive(Debug, Clone)]
pub enum ResizeMode {
None,
Started(KeyPattern, Instant, ResizeDirection),
Started(shortcuts::Binding, Instant, ResizeDirection),
Ended(Instant, ResizeDirection),
}
@ -1596,7 +1590,7 @@ impl Shell {
pub fn set_resize_mode(
&mut self,
enabled: Option<(KeyPattern, ResizeDirection)>,
enabled: Option<(shortcuts::Binding, ResizeDirection)>,
config: &Config,
evlh: LoopHandle<'static, crate::state::State>,
) {
@ -2306,14 +2300,14 @@ impl Shell {
is_sticky,
tiling_enabled,
edge,
&config.static_conf,
config,
)) as Box<dyn Iterator<Item = Item>>
} else {
let (tab, _) = mapped
.windows()
.find(|(s, _)| s.wl_surface().as_deref() == Some(surface))
.unwrap();
Box::new(tab_items(&mapped, &tab, is_tiled, &config.static_conf))
Box::new(tab_items(&mapped, &tab, is_tiled, config))
as Box<dyn Iterator<Item = Item>>
},
global_position,

View file

@ -192,26 +192,6 @@ pub enum ManagedLayer {
Sticky,
}
#[derive(Debug, serde::Deserialize, Clone, Copy, PartialEq, Eq)]
pub enum Direction {
Left,
Right,
Up,
Down,
}
impl std::ops::Not for Direction {
type Output = Self;
fn not(self) -> Self::Output {
match self {
Direction::Left => Direction::Right,
Direction::Right => Direction::Left,
Direction::Up => Direction::Down,
Direction::Down => Direction::Up,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum FocusResult {
None,

View file

@ -463,9 +463,11 @@ impl State {
let idle_inhibit_manager_state = IdleInhibitManagerState::new::<State>(&dh);
let idle_inhibiting_surfaces = HashSet::new();
let data_control_state = config.static_conf.data_control_enabled.then(|| {
DataControlState::new::<Self, _>(dh, Some(&primary_selection_state), |_| true)
});
let data_control_state = std::env::var("COSMIC_DATA_CONTROL_ENABLED")
.is_ok_and(|value| value == "1")
.then(|| {
DataControlState::new::<Self, _>(dh, Some(&primary_selection_state), |_| true)
});
let shell = Arc::new(RwLock::new(Shell::new(&config)));