From 553c49b42b5941002b3dd1e7b3fddaf58760dcd1 Mon Sep 17 00:00:00 2001 From: Michael Aaron Murphy Date: Wed, 3 Apr 2024 16:02:27 +0200 Subject: [PATCH] feat: runtime configurable keybindings --- Cargo.lock | 103 ++++++- Cargo.toml | 3 +- Makefile | 8 +- config.ron | 95 ------ data/keybindings.ron | 90 ++++++ debian/cosmic-comp.install | 1 - src/config/key_bindings.rs | 404 +++++++------------------- src/config/mod.rs | 153 ++++------ src/config/types.rs | 68 +---- src/input/gestures/mod.rs | 3 +- src/input/mod.rs | 383 ++++++++++++++---------- src/shell/element/mod.rs | 5 +- src/shell/element/resize_indicator.rs | 11 +- src/shell/element/stack.rs | 5 +- src/shell/focus/mod.rs | 10 - src/shell/grabs/menu/default.rs | 25 +- src/shell/grabs/mod.rs | 31 ++ src/shell/grabs/moving.rs | 3 +- src/shell/layout/floating/mod.rs | 3 +- src/shell/layout/mod.rs | 17 +- src/shell/layout/tiling/grabs/swap.rs | 21 +- src/shell/layout/tiling/mod.rs | 5 +- src/shell/mod.rs | 28 +- src/shell/workspace.rs | 20 -- src/state.rs | 8 +- 25 files changed, 674 insertions(+), 829 deletions(-) delete mode 100644 config.ron create mode 100644 data/keybindings.ron delete mode 100644 debian/cosmic-comp.install diff --git a/Cargo.lock b/Cargo.lock index c02996c1..64f6f73c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", diff --git a/Cargo.toml b/Cargo.toml index 511dd092..b45bec33 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/Makefile b/Makefile index 76d3b4d4..e23ac438 100644 --- a/Makefile +++ b/Makefile @@ -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" \ No newline at end of file + rm "$(DESTDIR)$(sharedir)/wayland-sessions/cosmic.desktop" diff --git a/config.ron b/config.ron deleted file mode 100644 index 8ebbc611..00000000 --- a/config.ron +++ /dev/null @@ -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, -) diff --git a/data/keybindings.ron b/data/keybindings.ron new file mode 100644 index 00000000..d3c0bc12 --- /dev/null +++ b/data/keybindings.ron @@ -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), +} diff --git a/debian/cosmic-comp.install b/debian/cosmic-comp.install deleted file mode 100644 index 2c5aab35..00000000 --- a/debian/cosmic-comp.install +++ /dev/null @@ -1 +0,0 @@ -config.ron etc/cosmic-comp diff --git a/src/config/key_bindings.rs b/src/config/key_bindings.rs index 72410131..31e858f0 100644 --- a/src/config/key_bindings.rs +++ b/src/config/key_bindings.rs @@ -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 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 for ModifiersState { - fn into(self) -> KeyModifiers { - KeyModifiers { - ctrl: self.ctrl, - alt: self.alt, - shift: self.shift, - logo: self.logo, - } - } -} - -impl std::ops::AddAssign 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 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, -} - -impl KeyPattern { - pub fn new(modifiers: impl Into, key: Option) -> KeyPattern { - KeyPattern { - modifiers: modifiers.into(), - key, - } - } - - pub fn inferred_direction(&self) -> Option { - 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, - modifiers: KeyModifiers, - keys: impl Iterator, - 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, - 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, + } +} diff --git a/src/config/mod.rs b/src/config/mod.rs index b456fd05..3de274ff 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -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, - pub data_control_enabled: bool, -} - -impl StaticConfig { - pub fn get_shortcut_for_action(&self, action: &Action) -> Option { - let possible_variants = self - .key_bindings - .iter() - .filter(|(_, a)| *a == action) - .map(|(b, _)| b) - .collect::>(); - - 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, } #[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::(&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::(&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 { + self.shortcuts.shortcut_for_action(action) + } + pub fn read_outputs( &mut self, output_state: &mut OutputConfigurationState, diff --git a/src/config/types.rs b/src/config/types.rs index f400912c..a27deb58 100644 --- a/src/config/types.rs +++ b/src/config/types.rs @@ -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); - -impl From 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 -where - D: serde::Deserializer<'de>, -{ - KeyModifiersDef::deserialize(deserializer).map(Into::into) -} - -#[allow(non_snake_case)] -pub fn deserialize_Keysym<'de, D>(deserializer: D) -> Result, 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(::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)), - } -} diff --git a/src/input/gestures/mod.rs b/src/input/gestures/mod.rs index 2998615a..996d19cf 100644 --- a/src/input/gestures/mod.rs +++ b/src/input/gestures/mod.rs @@ -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; diff --git a/src/input/mod.rs b/src/input/mod.rs index 3136fcc2..a8ca1a7f 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -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)>>); #[derive(Default, Debug)] -pub struct ModifiersShortcutQueue(RefCell>); +pub struct ModifiersShortcutQueue(RefCell>); impl SupressedKeys { fn add(&self, keysym: &KeysymHandle, token: impl Into>) { @@ -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, serial: Serial, time: u32, - pattern: KeyPattern, + pattern: shortcuts::Binding, direction: Option, propagate: bool, ) { // TODO: Detect if started from login manager or tty, and only allow // `Terminate` if it will return to login manager. 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(¤t_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, + serial: Serial, + time: u32, + pattern: shortcuts::Binding, + direction: Option, + 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(¤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 { @@ -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(¤t_output, &next_output, &active); } } + Action::MigrateWorkspaceToPreviousOutput => { let current_output = seat.active_output(); let (active, prev_output) = { @@ -2144,6 +2213,7 @@ impl State { .migrate_workspace(¤t_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(¤t_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, @@ -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); diff --git a/src/shell/element/mod.rs b/src/shell/element/mod.rs index 1d29dbdf..231f633a 100644 --- a/src/shell/element/mod.rs +++ b/src/shell/element/mod.rs @@ -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)] diff --git a/src/shell/element/resize_indicator.rs b/src/shell/element/resize_indicator.rs index 370da865..e8748e1f 100644 --- a/src/shell/element/resize_indicator.rs +++ b/src/shell/element/resize_indicator.rs @@ -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; @@ -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) diff --git a/src/shell/element/stack.rs b/src/shell/element/stack.rs index a9945afb..107179a3 100644 --- a/src/shell/element/stack.rs +++ b/src/shell/element/stack.rs @@ -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, diff --git a/src/shell/focus/mod.rs b/src/shell/focus/mod.rs index 0376e216..3c40c9eb 100644 --- a/src/shell/focus/mod.rs +++ b/src/shell/focus/mod.rs @@ -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>); pub struct FocusStackMut<'a>(pub(super) &'a mut IndexSet); diff --git a/src/shell/grabs/menu/default.rs b/src/shell/grabs/menu/default.rs index 09b6a1cf..68e7b64f 100644 --- a/src/shell/grabs/menu/default.rs +++ b/src/shell/grabs/menu/default.rs @@ -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 { 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 { 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)), ) }, ] diff --git a/src/shell/grabs/mod.rs b/src/shell/grabs/mod.rs index 7a4b3b9c..def21cfe 100644 --- a/src/shell/grabs/mod.rs +++ b/src/shell/grabs/mod.rs @@ -1,3 +1,4 @@ +use cosmic_settings_config::shortcuts; use smithay::{ input::{ pointer::{ @@ -106,6 +107,36 @@ impl ResizeEdge { } } +impl From 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 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 for ResizeEdge { #[inline] fn from(x: xdg_toplevel::ResizeEdge) -> Self { diff --git a/src/shell/grabs/moving.rs b/src/shell/grabs/moving.rs index 597c4b2f..0cbe400f 100644 --- a/src/shell/grabs/moving.rs +++ b/src/shell/grabs/moving.rs @@ -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(), diff --git a/src/shell/layout/floating/mod.rs b/src/shell/layout/floating/mod.rs index e30e9291..f7cad190 100644 --- a/src/shell/layout/floating/mod.rs +++ b/src/shell/layout/floating/mod.rs @@ -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}, diff --git a/src/shell/layout/mod.rs b/src/shell/layout/mod.rs index 8adfbdac..2e1a2b58 100644 --- a/src/shell/layout/mod.rs +++ b/src/shell/layout/mod.rs @@ -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", diff --git a/src/shell/layout/tiling/grabs/swap.rs b/src/shell/layout/tiling/grabs/swap.rs index 73b0dbc8..9805a07b 100644 --- a/src/shell/layout/tiling/grabs/swap.rs +++ b/src/shell/layout/tiling/grabs/swap.rs @@ -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 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 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, diff --git a/src/shell/layout/tiling/mod.rs b/src/shell/layout/tiling/mod.rs index df7f0630..6e77b3f1 100644 --- a/src/shell/layout/tiling/mod.rs +++ b/src/shell/layout/tiling/mod.rs @@ -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, diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 54749663..6e65ed89 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -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> } 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> }, global_position, diff --git a/src/shell/workspace.rs b/src/shell/workspace.rs index f59680ee..bff8c956 100644 --- a/src/shell/workspace.rs +++ b/src/shell/workspace.rs @@ -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, diff --git a/src/state.rs b/src/state.rs index dbbf4969..d16065fc 100644 --- a/src/state.rs +++ b/src/state.rs @@ -463,9 +463,11 @@ impl State { let idle_inhibit_manager_state = IdleInhibitManagerState::new::(&dh); let idle_inhibiting_surfaces = HashSet::new(); - let data_control_state = config.static_conf.data_control_enabled.then(|| { - DataControlState::new::(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::(dh, Some(&primary_selection_state), |_| true) + }); let shell = Arc::new(RwLock::new(Shell::new(&config)));