feat: runtime configurable keybindings
This commit is contained in:
parent
62afa4cf61
commit
553c49b42b
25 changed files with 674 additions and 829 deletions
103
Cargo.lock
generated
103
Cargo.lock
generated
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
8
Makefile
8
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"
|
||||
rm "$(DESTDIR)$(sharedir)/wayland-sessions/cosmic.desktop"
|
||||
|
|
|
|||
95
config.ron
95
config.ron
|
|
@ -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
90
data/keybindings.ron
Normal 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),
|
||||
}
|
||||
1
debian/cosmic-comp.install
vendored
1
debian/cosmic-comp.install
vendored
|
|
@ -1 +0,0 @@
|
|||
config.ron etc/cosmic-comp
|
||||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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)),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
383
src/input/mod.rs
383
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<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(¤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<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(¤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<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);
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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>);
|
||||
|
||||
|
|
|
|||
|
|
@ -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)),
|
||||
)
|
||||
},
|
||||
]
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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},
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue