autocommit 2022-02-14 21:13:42 CET
This commit is contained in:
parent
9b8e1ac29f
commit
da6b29f138
44 changed files with 5903 additions and 364 deletions
111
Cargo.lock
generated
111
Cargo.lock
generated
|
|
@ -39,9 +39,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.52"
|
||||
version = "1.0.53"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84450d0b4a8bd1ba4144ce8ce718fbc5d071358b1e5384bace6536b3d1f2d5b3"
|
||||
checksum = "94a45b455c14666b85fc40a019e8ab9eb75e3a124e05494f5397122bc9eb06e0"
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
|
|
@ -56,9 +56,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
|
|
@ -75,6 +75,24 @@ dependencies = [
|
|||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "2.0.0-beta.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3b09eea9771bcc3c1d3f21325c51066859dbb9addfad6325273630d9ea1707d"
|
||||
dependencies = [
|
||||
"bincode_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bincode_derive"
|
||||
version = "2.0.0-beta.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebde72585aa64e130b4c1d3612742253e7c486f25cb299b4373e505130519279"
|
||||
dependencies = [
|
||||
"virtue",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
|
|
@ -129,6 +147,14 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "default-config"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"i4config",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.9.0"
|
||||
|
|
@ -153,9 +179,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.19"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28560757fe2bb34e79f907794bb6b22ae8b0e5c669b638a1132f2592b19035b4"
|
||||
checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
|
|
@ -168,9 +194,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.19"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba3dda0b6588335f360afc675d0564c17a77a2bda81ca178a4b6081bd86c7f0b"
|
||||
checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
|
|
@ -178,15 +204,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.19"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7"
|
||||
checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.19"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29d6d2ff5bb10fb95c85b8ce46538a2e5f5e7fdc755623a7d4529ab8a4ed9d2a"
|
||||
checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
|
|
@ -195,15 +221,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.19"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1f9d34af5a1aac6fb380f735fe510746c38067c5bf16c7fd250280503c971b2"
|
||||
checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.19"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6dbd947adfffb0efc70599b3ddcf7b5597bb5fa9e245eb99f62b3a5f7bb8bd3c"
|
||||
checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -212,21 +238,21 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.19"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3055baccb68d74ff6480350f8d6eb8fcfa3aa11bdc1a1ae3afdd0514617d508"
|
||||
checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.19"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72"
|
||||
checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.19"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164"
|
||||
checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
|
|
@ -242,9 +268,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.3"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
|
||||
checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
|
|
@ -279,12 +305,15 @@ dependencies = [
|
|||
"ahash",
|
||||
"anyhow",
|
||||
"backtrace",
|
||||
"bincode",
|
||||
"bitflags",
|
||||
"bstr",
|
||||
"byteorder",
|
||||
"chrono",
|
||||
"default-config",
|
||||
"env_logger",
|
||||
"futures",
|
||||
"i4config",
|
||||
"isnt",
|
||||
"libloading",
|
||||
"log",
|
||||
|
|
@ -301,6 +330,14 @@ dependencies = [
|
|||
"xcb-dl-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "i4config"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "isnt"
|
||||
version = "0.1.0"
|
||||
|
|
@ -315,15 +352,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.112"
|
||||
version = "0.2.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125"
|
||||
checksum = "e74d72e0f9b65b5b4ca49a346af3976df0f9c61d550727f349ecd559f251a26c"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.7.2"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afe203d669ec979b7128619bae5a63b7b42e9203c1b29146079ee05e2f604b52"
|
||||
checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"winapi",
|
||||
|
|
@ -401,9 +438,9 @@ checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
|
|||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.7"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443"
|
||||
checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
|
|
@ -428,9 +465,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.14"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d"
|
||||
checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
|
@ -554,9 +591,9 @@ checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.84"
|
||||
version = "1.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ecb2e6da8ee5eb9a61068762a32fa9619cc591ceb055b3687f4cd4051ec2e06b"
|
||||
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -641,6 +678,12 @@ version = "0.9.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "virtue"
|
||||
version = "0.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0e85ed1066abcc0ea331cce3ce83cccf30ae9900529ca46f353b22ca79b56b8"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.0+wasi-snapshot-preview1"
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
build = "build/build.rs"
|
||||
|
||||
[workspace]
|
||||
members = ["i4config", "default-config"]
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
|
||||
|
|
@ -33,6 +36,9 @@ smallvec = { version = "1.8.0", features = ["const_generics", "const_new", "unio
|
|||
backtrace = "0.3.64"
|
||||
byteorder = "1.4.3"
|
||||
chrono = "0.4.19"
|
||||
bincode = "2.0.0-beta.2"
|
||||
i4config = { path = "i4config" }
|
||||
default-config = { path = "default-config" }
|
||||
|
||||
[build-dependencies]
|
||||
repc = "0.1.1"
|
||||
|
|
|
|||
11
default-config/Cargo.toml
Normal file
11
default-config/Cargo.toml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "default-config"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["lib", "cdylib"]
|
||||
|
||||
[dependencies]
|
||||
i4config = { path = "../i4config" }
|
||||
log = "0.4.14"
|
||||
313
default-config/src/keymap.xkb
Normal file
313
default-config/src/keymap.xkb
Normal file
|
|
@ -0,0 +1,313 @@
|
|||
xkb_keymap {
|
||||
|
||||
xkb_keycodes {
|
||||
|
||||
<1> = 9; # ESC
|
||||
<2> = 10; # 1
|
||||
<3> = 11; # 2
|
||||
<4> = 12; # 3
|
||||
<5> = 13; # 4
|
||||
<6> = 14; # 5
|
||||
<7> = 15; # 6
|
||||
<8> = 16; # 7
|
||||
<9> = 17; # 8
|
||||
<10> = 18; # 9
|
||||
<11> = 19; # 0
|
||||
<12> = 20; # MINUS
|
||||
<13> = 21; # EQUAL
|
||||
<14> = 22; # BACKSPACE
|
||||
<15> = 23; # TAB
|
||||
<16> = 24; # Q
|
||||
<17> = 25; # W
|
||||
<18> = 26; # E
|
||||
<19> = 27; # R
|
||||
<20> = 28; # T
|
||||
<21> = 29; # Y
|
||||
<22> = 30; # U
|
||||
<23> = 31; # I
|
||||
<24> = 32; # O
|
||||
<25> = 33; # P
|
||||
<26> = 34; # LEFTBRACE
|
||||
<27> = 35; # RIGHTBRACE
|
||||
<28> = 36; # ENTER
|
||||
<29> = 37; # LEFTCTRL
|
||||
<30> = 38; # A
|
||||
<31> = 39; # S
|
||||
<32> = 40; # D
|
||||
<33> = 41; # F
|
||||
<34> = 42; # G
|
||||
<35> = 43; # H
|
||||
<36> = 44; # J
|
||||
<37> = 45; # K
|
||||
<38> = 46; # L
|
||||
<39> = 47; # SEMICOLON
|
||||
<40> = 48; # APOSTROPHE
|
||||
<41> = 49; # GRAVE
|
||||
<42> = 50; # LEFTSHIFT
|
||||
<43> = 51; # BACKSLASH
|
||||
<44> = 52; # Z
|
||||
<45> = 53; # X
|
||||
<46> = 54; # C
|
||||
<47> = 55; # V
|
||||
<48> = 56; # B
|
||||
<49> = 57; # N
|
||||
<50> = 58; # M
|
||||
<51> = 59; # COMMA
|
||||
<52> = 60; # DOT
|
||||
<53> = 61; # SLASH
|
||||
<54> = 62; # RIGHTSHIFT
|
||||
<55> = 63; # KPASTERISK
|
||||
<56> = 64; # LEFTALT
|
||||
<57> = 65; # SPACE
|
||||
<58> = 66; # CAPSLOCK
|
||||
<59> = 67; # F1
|
||||
<60> = 68; # F2
|
||||
<61> = 69; # F3
|
||||
<62> = 70; # F4
|
||||
<63> = 71; # F5
|
||||
<64> = 72; # F6
|
||||
<65> = 73; # F7
|
||||
<66> = 74; # F8
|
||||
<67> = 75; # F9
|
||||
<68> = 76; # F10
|
||||
<69> = 77; # NUMLOCK
|
||||
<70> = 78; # SCROLLLOCK
|
||||
<71> = 79; # KP7
|
||||
<72> = 80; # KP8
|
||||
<73> = 81; # KP9
|
||||
<74> = 82; # KPMINUS
|
||||
<75> = 83; # KP4
|
||||
<76> = 84; # KP5
|
||||
<77> = 85; # KP6
|
||||
<78> = 86; # KPPLUS
|
||||
<79> = 87; # KP1
|
||||
<80> = 88; # KP2
|
||||
<81> = 89; # KP3
|
||||
<82> = 90; # KP0
|
||||
<83> = 91; # KPDOT
|
||||
<87> = 95; # F11
|
||||
<88> = 96; # F12
|
||||
<89> = 97; # RO
|
||||
<92> = 100; # HENKAN
|
||||
<93> = 101; # KATAKANAHIRAGANA
|
||||
<94> = 102; # MUHENKAN
|
||||
<96> = 104; # KPENTER
|
||||
<97> = 105; # RIGHTCTRL
|
||||
<98> = 106; # KPSLASH
|
||||
<100> = 108; # RIGHTALT
|
||||
<102> = 110; # HOME
|
||||
<103> = 111; # UP
|
||||
<104> = 112; # PAGEUP
|
||||
<105> = 113; # LEFT
|
||||
<106> = 114; # RIGHT
|
||||
<107> = 115; # END
|
||||
<108> = 116; # DOWN
|
||||
<109> = 117; # PAGEDOWN
|
||||
<110> = 118; # INSERT
|
||||
<111> = 119; # DELETE
|
||||
<117> = 125; # KPEQUAL
|
||||
<119> = 127; # PAUSE
|
||||
<124> = 132; # YEN
|
||||
<125> = 133; # LEFTMETA
|
||||
<126> = 134; # RIGHTMETA
|
||||
<139> = 147; # MENU
|
||||
<183> = 191; # F13
|
||||
<184> = 192; # F14
|
||||
<185> = 193; # F15
|
||||
<186> = 194; # F16
|
||||
<187> = 195; # F17
|
||||
<188> = 196; # F18
|
||||
<189> = 197; # F19
|
||||
<190> = 198; # F20
|
||||
<191> = 199; # F21
|
||||
<210> = 218; # PRINT
|
||||
|
||||
# We must include at least one indicator here. Otherwise Xwayland segfaults.
|
||||
indicator 1 = "DUMMY";
|
||||
};
|
||||
|
||||
xkb_types {
|
||||
|
||||
# We must include at least one virtual modifier.
|
||||
# Otherwise Xwayland rejects our keymap.
|
||||
virtual_modifiers Dummy;
|
||||
|
||||
type "ONE_LEVEL" {
|
||||
modifiers = none;
|
||||
};
|
||||
type "TWO_LEVEL" {
|
||||
modifiers = Shift;
|
||||
map[Shift] = Level2;
|
||||
};
|
||||
type "ALPHABETIC" {
|
||||
modifiers = Shift+Lock;
|
||||
map[Shift] = Level2;
|
||||
map[Lock] = Level2;
|
||||
};
|
||||
type "KEYPAD" {
|
||||
modifiers = Shift+Mod2;
|
||||
map[Mod2] = Level2;
|
||||
};
|
||||
};
|
||||
|
||||
xkb_compatibility {
|
||||
|
||||
interpret.repeat = False;
|
||||
interpret.locking = False;
|
||||
interpret Shift_L {
|
||||
action = SetMods(modifiers=Shift);
|
||||
};
|
||||
interpret Shift_R {
|
||||
action = SetMods(modifiers=Shift);
|
||||
};
|
||||
interpret Caps_Lock {
|
||||
action = LockMods(modifiers=Lock);
|
||||
};
|
||||
interpret Control_L {
|
||||
action = SetMods(modifiers=Control);
|
||||
};
|
||||
interpret Control_R {
|
||||
action = SetMods(modifiers=Control);
|
||||
};
|
||||
interpret Alt_L {
|
||||
action = SetMods(modifiers=Mod1);
|
||||
};
|
||||
interpret Alt_R {
|
||||
action = SetMods(modifiers=Mod1);
|
||||
};
|
||||
interpret Num_Lock {
|
||||
action = LockMods(modifiers=Mod2);
|
||||
};
|
||||
};
|
||||
|
||||
xkb_symbols {
|
||||
|
||||
key <1> { [ Escape ] };
|
||||
key <59> { [ F1 ] };
|
||||
key <60> { [ F2 ] };
|
||||
key <61> { [ F3 ] };
|
||||
key <62> { [ F4 ] };
|
||||
key <63> { [ F5 ] };
|
||||
key <64> { [ F6 ] };
|
||||
key <65> { [ F7 ] };
|
||||
key <66> { [ F8 ] };
|
||||
key <67> { [ F9 ] };
|
||||
key <68> { [ F10 ] };
|
||||
key <87> { [ F11 ] };
|
||||
key <88> { [ F12 ] };
|
||||
key <183> { [ F13 ] };
|
||||
key <184> { [ F14 ] };
|
||||
key <185> { [ F15 ] };
|
||||
key <186> { [ F16 ] };
|
||||
key <187> { [ F17 ] };
|
||||
key <188> { [ F18 ] };
|
||||
key <189> { [ F19 ] };
|
||||
key <190> { [ F20 ] };
|
||||
key <191> { [ F21 ] };
|
||||
key <210> { [ Print ] };
|
||||
key <70> { [ Scroll_Lock ] };
|
||||
key <119> { [ Pause ] };
|
||||
|
||||
key <69> { [ Num_Lock ] };
|
||||
key <96> { [ KP_Enter ] };
|
||||
key <98> { [ KP_Divide ] };
|
||||
key <74> { [ KP_Subtract ] };
|
||||
key <55> { [ KP_Multiply ] };
|
||||
key <78> { [ KP_Add ] };
|
||||
key <117> { [ KP_Equal ] };
|
||||
key <83> { [ KP_Delete, KP_Decimal ] };
|
||||
key <71> { [ KP_Home, KP_7 ] };
|
||||
key <72> { [ KP_Up, KP_8 ] };
|
||||
key <73> { [ KP_Prior, KP_9 ] };
|
||||
key <75> { [ KP_Left, KP_4 ] };
|
||||
key <76> { [ KP_Begin, KP_5 ] };
|
||||
key <77> { [ KP_Right, KP_6 ] };
|
||||
key <79> { [ KP_End, KP_1 ] };
|
||||
key <80> { [ KP_Down, KP_2 ] };
|
||||
key <81> { [ KP_Next, KP_3 ] };
|
||||
key <82> { [ KP_Insert, KP_0 ] };
|
||||
|
||||
key <103> { [ Up ] };
|
||||
key <105> { [ Left ] };
|
||||
key <106> { [ Right ] };
|
||||
key <108> { [ Down ] };
|
||||
|
||||
key <102> { [ Home ] };
|
||||
key <104> { [ Prior ] };
|
||||
key <107> { [ End ] };
|
||||
key <109> { [ Next ] };
|
||||
key <110> { [ Insert ] };
|
||||
key <111> { [ Delete ] };
|
||||
|
||||
key <14> { [ BackSpace ] };
|
||||
key <15> { [ Tab, ISO_Left_Tab ] };
|
||||
key <58> { [ Caps_Lock ] };
|
||||
key <28> { [ Return ] };
|
||||
key <42> { [ Shift_L ] };
|
||||
key <54> { [ Shift_R ] };
|
||||
key <29> { [ Control_L ] };
|
||||
key <125> { [ Super_L ] };
|
||||
key <56> { [ Alt_L ] };
|
||||
key <57> { [ space ] };
|
||||
key <100> { [ Alt_R ] };
|
||||
key <126> { [ Super_R ] };
|
||||
key <139> { [ Menu ] };
|
||||
key <97> { [ Control_R ] };
|
||||
|
||||
key <41> { [ grave, asciitilde ] };
|
||||
key <12> { [ minus, underscore ] };
|
||||
key <13> { [ equal, plus ] };
|
||||
key <26> { [ bracketleft, braceleft ] };
|
||||
key <27> { [ bracketright, braceright ] };
|
||||
key <43> { [ backslash, bar ] };
|
||||
key <39> { [ semicolon, colon ] };
|
||||
key <40> { [ apostrophe, quotedbl ] };
|
||||
key <51> { [ comma, less ] };
|
||||
key <52> { [ period, greater ] };
|
||||
key <53> { [ slash, question ] };
|
||||
key <89> { [ dollar, asciitilde ] };
|
||||
key <93> { [ ampersand, percent ] };
|
||||
key <94> { [ equal, asterisk ] };
|
||||
key <124> { [ at, asciicircum ] };
|
||||
key <92> { [ numbersign, grave ] };
|
||||
|
||||
key <16> { [ q, Q ] };
|
||||
key <17> { [ w, W ] };
|
||||
key <18> { [ e, E ] };
|
||||
key <19> { [ r, R ] };
|
||||
key <20> { [ t, T ] };
|
||||
key <21> { [ y, Y ] };
|
||||
key <22> { [ u, U ] };
|
||||
key <23> { [ i, I ] };
|
||||
key <24> { [ o, O ] };
|
||||
key <25> { [ p, P ] };
|
||||
key <30> { [ a, A ] };
|
||||
key <31> { [ s, S ] };
|
||||
key <32> { [ d, D ] };
|
||||
key <33> { [ f, F ] };
|
||||
key <34> { [ g, G ] };
|
||||
key <35> { [ h, H ] };
|
||||
key <36> { [ j, J ] };
|
||||
key <37> { [ k, K ] };
|
||||
key <38> { [ l, L ] };
|
||||
key <44> { [ z, Z ] };
|
||||
key <45> { [ x, X ] };
|
||||
key <46> { [ c, C ] };
|
||||
key <47> { [ v, V ] };
|
||||
key <48> { [ b, B ] };
|
||||
key <49> { [ n, N ] };
|
||||
key <50> { [ m, M ] };
|
||||
|
||||
key <2> { [ 1, exclam ] };
|
||||
key <3> { [ 2, at ] };
|
||||
key <4> { [ 3, numbersign ] };
|
||||
key <5> { [ 4, dollar ] };
|
||||
key <6> { [ 5, percent ] };
|
||||
key <7> { [ 6, asciicircum ] };
|
||||
key <8> { [ 7, ampersand ] };
|
||||
key <9> { [ 8, asterisk ] };
|
||||
key <10> { [ 9, parenleft ] };
|
||||
key <11> { [ 0, parenright ] };
|
||||
};
|
||||
|
||||
};
|
||||
43
default-config/src/lib.rs
Normal file
43
default-config/src/lib.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
use i4config::keyboard::mods::{ALT, CTRL, Modifiers, SHIFT};
|
||||
use i4config::keyboard::syms::{SYM_Super_L, SYM_h, SYM_j, SYM_k, SYM_l, SYM_plus, SYM_minus, SYM_r};
|
||||
use i4config::Direction::{Down, Left, Right, Up};
|
||||
use i4config::{config, shell, Seat, create_seat, input_devices, on_new_input_device};
|
||||
|
||||
const MOD: Modifiers = ALT;
|
||||
|
||||
fn configure_seat(s: Seat) {
|
||||
log::info!("Configuring seat {:?}", s);
|
||||
|
||||
let change_rate = move |delta| {
|
||||
let (rate, delay) = s.repeat_rate();
|
||||
let new_rate = rate - delta;
|
||||
let new_delay = delay + 10 * delta;
|
||||
s.set_repeat_rate(new_rate, new_delay);
|
||||
};
|
||||
|
||||
s.bind(CTRL | SYM_l, move || change_rate(-1));
|
||||
s.bind(CTRL | SYM_r, move || change_rate(1));
|
||||
|
||||
s.bind(CTRL | SYM_h, move || s.focus(Left));
|
||||
s.bind(CTRL | SYM_j, move || s.focus(Down));
|
||||
s.bind(CTRL | SYM_k, move || s.focus(Up));
|
||||
s.bind(CTRL | SYM_l, move || s.focus(Right));
|
||||
|
||||
s.bind(MOD | SHIFT | SYM_h, move || s.move_(Left));
|
||||
s.bind(MOD | SHIFT | SYM_j, move || s.move_(Down));
|
||||
s.bind(MOD | SHIFT | SYM_k, move || s.move_(Up));
|
||||
s.bind(MOD | SHIFT | SYM_l, move || s.move_(Right));
|
||||
|
||||
s.bind(SYM_Super_L, || shell("alacritty"));
|
||||
}
|
||||
|
||||
pub fn configure() {
|
||||
let seat = create_seat("default");
|
||||
configure_seat(seat);
|
||||
for device in input_devices() {
|
||||
device.set_seat(seat);
|
||||
}
|
||||
on_new_input_device(move |device| device.set_seat(seat));
|
||||
}
|
||||
|
||||
config!(configure);
|
||||
8
i4config/Cargo.toml
Normal file
8
i4config/Cargo.toml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "i4config"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
bincode = "2.0.0-beta.2"
|
||||
log = "0.4.14"
|
||||
39
i4config/src/_private.rs
Normal file
39
i4config/src/_private.rs
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
pub mod client;
|
||||
pub mod ipc;
|
||||
mod logging;
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub const VERSION: u32 = 1;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct ConfigEntry {
|
||||
pub version: u32,
|
||||
pub init: unsafe extern "C" fn(
|
||||
srv_data: *const u8,
|
||||
srv_unref: unsafe extern "C" fn(data: *const u8),
|
||||
srv_handler: unsafe extern "C" fn(data: *const u8, msg: *const u8, size: usize),
|
||||
msg: *const u8,
|
||||
size: usize,
|
||||
) -> *const u8,
|
||||
pub unref: unsafe extern "C" fn(data: *const u8),
|
||||
pub handle_msg: unsafe extern "C" fn(data: *const u8, msg: *const u8, size: usize),
|
||||
}
|
||||
|
||||
pub struct ConfigEntryGen<T> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: Config> ConfigEntryGen<T> {}
|
||||
|
||||
pub fn bincode_ops() -> impl bincode::config::Config {
|
||||
bincode::config::standard()
|
||||
.with_fixed_int_encoding()
|
||||
.with_little_endian()
|
||||
.with_no_limit()
|
||||
.skip_fixed_array_length()
|
||||
}
|
||||
|
||||
pub trait Config {
|
||||
extern "C" fn configure();
|
||||
}
|
||||
323
i4config/src/_private/client.rs
Normal file
323
i4config/src/_private/client.rs
Normal file
|
|
@ -0,0 +1,323 @@
|
|||
use crate::_private::ipc::{InitMessage, Request, Response};
|
||||
use crate::_private::{bincode_ops, logging, Config, ConfigEntry, ConfigEntryGen, VERSION};
|
||||
use crate::{Direction, InputDevice, LogLevel, ModifiedKeySym, Seat};
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::collections::HashMap;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
use std::{ptr, slice};
|
||||
use crate::keyboard::keymap::Keymap;
|
||||
|
||||
pub(crate) struct Client {
|
||||
configure: extern "C" fn(),
|
||||
srv_data: *const u8,
|
||||
srv_unref: unsafe extern "C" fn(data: *const u8),
|
||||
srv_handler: unsafe extern "C" fn(data: *const u8, msg: *const u8, size: usize),
|
||||
key_handlers: RefCell<HashMap<(Seat, ModifiedKeySym), Rc<dyn Fn()>>>,
|
||||
response: RefCell<Vec<Response>>,
|
||||
on_new_seat: RefCell<Option<Rc<dyn Fn(Seat)>>>,
|
||||
on_new_input_device: RefCell<Option<Rc<dyn Fn(InputDevice)>>>,
|
||||
bufs: RefCell<Vec<Vec<u8>>>,
|
||||
}
|
||||
|
||||
impl Drop for Client {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
(self.srv_unref)(self.srv_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
pub(crate) static CLIENT: std::cell::Cell<*const Client> = const { std::cell::Cell::new(ptr::null()) };
|
||||
}
|
||||
|
||||
unsafe fn with_client<T, F: FnOnce(&Client) -> T>(data: *const u8, f: F) -> T {
|
||||
struct Reset<'a> {
|
||||
cell: &'a Cell<*const Client>,
|
||||
val: *const Client,
|
||||
}
|
||||
impl Drop for Reset<'_> {
|
||||
fn drop(&mut self) {
|
||||
self.cell.set(self.val);
|
||||
}
|
||||
}
|
||||
CLIENT.with(|cell| unsafe {
|
||||
let client = data as *const Client;
|
||||
Rc::increment_strong_count(client);
|
||||
let client = Rc::from_raw(client);
|
||||
let old = cell.replace(client.deref());
|
||||
let _reset = Reset { cell, val: old };
|
||||
f(&client)
|
||||
})
|
||||
}
|
||||
|
||||
impl<T: Config> ConfigEntryGen<T> {
|
||||
pub const ENTRY: ConfigEntry = ConfigEntry {
|
||||
version: VERSION,
|
||||
init: Self::init,
|
||||
unref,
|
||||
handle_msg,
|
||||
};
|
||||
|
||||
pub unsafe extern "C" fn init(
|
||||
srv_data: *const u8,
|
||||
srv_unref: unsafe extern "C" fn(data: *const u8),
|
||||
srv_handler: unsafe extern "C" fn(data: *const u8, msg: *const u8, size: usize),
|
||||
init_data: *const u8,
|
||||
size: usize,
|
||||
) -> *const u8 {
|
||||
logging::init();
|
||||
init(
|
||||
srv_data,
|
||||
srv_unref,
|
||||
srv_handler,
|
||||
init_data,
|
||||
size,
|
||||
T::configure,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn init(
|
||||
srv_data: *const u8,
|
||||
srv_unref: unsafe extern "C" fn(data: *const u8),
|
||||
srv_handler: unsafe extern "C" fn(data: *const u8, msg: *const u8, size: usize),
|
||||
init: *const u8,
|
||||
size: usize,
|
||||
f: extern "C" fn(),
|
||||
) -> *const u8 {
|
||||
let client = Rc::new(Client {
|
||||
configure: f,
|
||||
srv_data,
|
||||
srv_unref,
|
||||
srv_handler,
|
||||
key_handlers: Default::default(),
|
||||
response: Default::default(),
|
||||
on_new_seat: Default::default(),
|
||||
on_new_input_device: Default::default(),
|
||||
bufs: Default::default(),
|
||||
});
|
||||
let init = slice::from_raw_parts(init, size);
|
||||
client.handle_init_msg(init);
|
||||
Rc::into_raw(client) as *const u8
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn unref(data: *const u8) {
|
||||
let client = data as *const Client;
|
||||
drop(Rc::from_raw(client));
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn handle_msg(data: *const u8, msg: *const u8, size: usize) {
|
||||
with_client(data, |client| {
|
||||
let msg = slice::from_raw_parts(msg, size);
|
||||
client.handle_msg(msg);
|
||||
});
|
||||
}
|
||||
|
||||
impl Client {
|
||||
fn send(&self, msg: &Request) {
|
||||
let mut buf = self.bufs.borrow_mut().pop().unwrap_or_default();
|
||||
buf.clear();
|
||||
bincode::encode_into_std_write(msg, &mut buf, bincode_ops()).unwrap();
|
||||
unsafe {
|
||||
(self.srv_handler)(self.srv_data, buf.as_ptr(), buf.len());
|
||||
}
|
||||
self.bufs.borrow_mut().push(buf);
|
||||
}
|
||||
|
||||
pub fn shell(&self, shell: &str) {
|
||||
self.send(&Request::Shell { script: shell });
|
||||
}
|
||||
|
||||
pub fn focus(&self, seat: Seat, direction: Direction) {
|
||||
self.send(&Request::Focus { seat, direction });
|
||||
}
|
||||
|
||||
pub fn move_(&self, seat: Seat, direction: Direction) {
|
||||
self.send(&Request::Move { seat, direction });
|
||||
}
|
||||
|
||||
pub fn unbind<T: Into<ModifiedKeySym>>(&self, seat: Seat, mod_sym: T) {
|
||||
let mod_sym = mod_sym.into();
|
||||
let deregister = self
|
||||
.key_handlers
|
||||
.borrow_mut()
|
||||
.remove(&(seat, mod_sym))
|
||||
.is_some();
|
||||
if deregister {
|
||||
self.send(&Request::RemoveShortcut {
|
||||
seat,
|
||||
mods: mod_sym.mods,
|
||||
sym: mod_sym.sym,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn with_response<F: FnOnce()>(&self, f: F) -> Response {
|
||||
f();
|
||||
self.response.borrow_mut().pop().unwrap_or(Response::None)
|
||||
}
|
||||
|
||||
pub fn seats(&self) -> Vec<Seat> {
|
||||
let response = self.with_response(|| self.send(&Request::GetSeats));
|
||||
match response {
|
||||
Response::GetSeats { seats } => seats,
|
||||
_ => {
|
||||
log::error!("Server did not send a response to a get_seats request");
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_seat(&self, name: &str) -> Seat {
|
||||
let response = self.with_response(|| self.send(&Request::CreateSeat { name }));
|
||||
match response {
|
||||
Response::CreateSeat { seat } => seat,
|
||||
_ => {
|
||||
log::error!("Server did not send a response to a create_seat request");
|
||||
Seat(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_input_devices(&self) -> Vec<InputDevice> {
|
||||
let res = self.with_response(|| self.send(&Request::GetInputDevices));
|
||||
match res {
|
||||
Response::GetInputDevices { devices } => devices,
|
||||
_ => {
|
||||
log::error!("Server did not send a response to a get_input_devices request");
|
||||
vec!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn on_new_seat<F: Fn(Seat) + 'static>(&self, f: F) {
|
||||
*self.on_new_seat.borrow_mut() = Some(Rc::new(f));
|
||||
}
|
||||
|
||||
pub fn on_new_input_device<F: Fn(InputDevice) + 'static>(&self, f: F) {
|
||||
*self.on_new_input_device.borrow_mut() = Some(Rc::new(f));
|
||||
}
|
||||
|
||||
pub fn set_seat(&self, device: InputDevice, seat: Seat) {
|
||||
self.send(&Request::SetSeat { device, seat })
|
||||
}
|
||||
|
||||
pub fn seat_set_keymap(&self, seat: Seat, keymap: Keymap) {
|
||||
self.send(&Request::SeatSetKeymap { seat, keymap })
|
||||
}
|
||||
|
||||
pub fn seat_set_repeat_rate(&self, seat: Seat, rate: i32, delay: i32) {
|
||||
self.send(&Request::SeatSetRepeatRate { seat, rate, delay })
|
||||
}
|
||||
|
||||
pub fn seat_get_repeat_rate(&self, seat: Seat) -> (i32, i32) {
|
||||
let res = self.with_response(|| self.send(&Request::SeatGetRepeatRate { seat }));
|
||||
match res {
|
||||
Response::GetRepeatRate { rate, delay } => (rate, delay),
|
||||
_ => {
|
||||
log::error!("Server did not send a response to a get_repeat_rate request");
|
||||
(25, 250)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_keymap(&self, keymap: &str) -> Keymap {
|
||||
let res = self.with_response(|| self.send(&Request::ParseKeymap { keymap }));
|
||||
match res {
|
||||
Response::ParseKeymap { keymap } => keymap,
|
||||
_ => {
|
||||
log::error!("Server did not send a response to a parse_keymap request");
|
||||
Keymap(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bind<T: Into<ModifiedKeySym>, F: Fn() + 'static>(&self, seat: Seat, mod_sym: T, f: F) {
|
||||
let mod_sym = mod_sym.into();
|
||||
let register = {
|
||||
let mut kh = self.key_handlers.borrow_mut();
|
||||
let f = Rc::new(f);
|
||||
match kh.entry((seat, mod_sym)) {
|
||||
Entry::Occupied(mut o) => {
|
||||
*o.get_mut() = f;
|
||||
false
|
||||
}
|
||||
Entry::Vacant(v) => {
|
||||
v.insert(f);
|
||||
true
|
||||
}
|
||||
}
|
||||
};
|
||||
if register {
|
||||
self.send(&Request::AddShortcut {
|
||||
seat,
|
||||
mods: mod_sym.mods,
|
||||
sym: mod_sym.sym,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn log(&self, level: LogLevel, msg: &str, file: Option<&str>, line: Option<u32>) {
|
||||
self.send(&Request::Log {
|
||||
level,
|
||||
msg,
|
||||
file,
|
||||
line,
|
||||
})
|
||||
}
|
||||
|
||||
fn handle_msg(&self, msg: &[u8]) {
|
||||
let res = bincode::decode_from_slice::<Request, _>(msg, bincode_ops());
|
||||
let (msg, _) = match res {
|
||||
Ok(msg) => msg,
|
||||
Err(e) => {
|
||||
let msg = format!("could not deserialize message: {}", e);
|
||||
self.log(LogLevel::Error, &msg, None, None);
|
||||
return;
|
||||
}
|
||||
};
|
||||
match msg {
|
||||
Request::Configure => {
|
||||
(self.configure)();
|
||||
}
|
||||
Request::Response { response } => {
|
||||
self.response.borrow_mut().push(response);
|
||||
}
|
||||
Request::InvokeShortcut { seat, mods, sym } => {
|
||||
let ms = ModifiedKeySym { mods, sym };
|
||||
let handler = self.key_handlers.borrow_mut().get(&(seat, ms)).cloned();
|
||||
if let Some(handler) = handler {
|
||||
handler();
|
||||
}
|
||||
}
|
||||
Request::NewInputDevice { device } => {
|
||||
let handler = self.on_new_input_device.borrow_mut().clone();
|
||||
if let Some(handler) = handler {
|
||||
handler(device);
|
||||
}
|
||||
}
|
||||
m => {
|
||||
let err = format!("unexpected message: {:?}", m);
|
||||
self.log(LogLevel::Error, &err, None, None);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_init_msg(&self, msg: &[u8]) {
|
||||
let (init, _) = match bincode::decode_from_slice::<InitMessage, _>(msg, bincode_ops()) {
|
||||
Ok(m) => m,
|
||||
Err(e) => {
|
||||
let msg = format!("could not deserialize message: {}", e);
|
||||
self.log(LogLevel::Error, &msg, None, None);
|
||||
return;
|
||||
}
|
||||
};
|
||||
match init {
|
||||
InitMessage::V1(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
96
i4config/src/_private/ipc.rs
Normal file
96
i4config/src/_private/ipc.rs
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
use crate::keyboard::mods::Modifiers;
|
||||
use crate::keyboard::syms::KeySym;
|
||||
use crate::{Direction, InputDevice, LogLevel, Seat};
|
||||
use bincode::{BorrowDecode, Decode, Encode};
|
||||
use crate::keyboard::keymap::Keymap;
|
||||
|
||||
#[derive(Encode, BorrowDecode, Debug)]
|
||||
pub enum Request<'a> {
|
||||
Configure,
|
||||
Log {
|
||||
level: LogLevel,
|
||||
msg: &'a str,
|
||||
file: Option<&'a str>,
|
||||
line: Option<u32>,
|
||||
},
|
||||
Response {
|
||||
response: Response,
|
||||
},
|
||||
CreateSeat {
|
||||
name: &'a str,
|
||||
},
|
||||
SetSeat {
|
||||
device: InputDevice,
|
||||
seat: Seat,
|
||||
},
|
||||
ParseKeymap {
|
||||
keymap: &'a str,
|
||||
},
|
||||
SeatSetKeymap {
|
||||
seat: Seat,
|
||||
keymap: Keymap,
|
||||
},
|
||||
SeatGetRepeatRate {
|
||||
seat: Seat,
|
||||
},
|
||||
SeatSetRepeatRate {
|
||||
seat: Seat,
|
||||
rate: i32,
|
||||
delay: i32,
|
||||
},
|
||||
RemoveSeat {
|
||||
seat: Seat,
|
||||
},
|
||||
GetSeats,
|
||||
GetInputDevices,
|
||||
NewInputDevice {
|
||||
device: InputDevice,
|
||||
},
|
||||
DelInputDevice {
|
||||
device: InputDevice,
|
||||
},
|
||||
AddShortcut {
|
||||
seat: Seat,
|
||||
mods: Modifiers,
|
||||
sym: KeySym,
|
||||
},
|
||||
RemoveShortcut {
|
||||
seat: Seat,
|
||||
mods: Modifiers,
|
||||
sym: KeySym,
|
||||
},
|
||||
InvokeShortcut {
|
||||
seat: Seat,
|
||||
mods: Modifiers,
|
||||
sym: KeySym,
|
||||
},
|
||||
Shell {
|
||||
script: &'a str,
|
||||
},
|
||||
Focus {
|
||||
seat: Seat,
|
||||
direction: Direction,
|
||||
},
|
||||
Move {
|
||||
seat: Seat,
|
||||
direction: Direction,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Debug)]
|
||||
pub enum Response {
|
||||
None,
|
||||
GetSeats { seats: Vec<Seat> },
|
||||
GetRepeatRate { rate: i32, delay: i32 },
|
||||
ParseKeymap { keymap: Keymap, },
|
||||
CreateSeat { seat: Seat },
|
||||
GetInputDevices { devices: Vec<InputDevice> },
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Debug)]
|
||||
pub enum InitMessage {
|
||||
V1(V1InitMessage),
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Debug)]
|
||||
pub struct V1InitMessage {}
|
||||
39
i4config/src/_private/logging.rs
Normal file
39
i4config/src/_private/logging.rs
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
use crate::LogLevel;
|
||||
use log::{Level, LevelFilter, Log, Metadata, Record};
|
||||
|
||||
pub fn init() {
|
||||
log::set_logger(&Logger).unwrap();
|
||||
log::set_max_level(LevelFilter::Trace);
|
||||
}
|
||||
|
||||
struct Logger;
|
||||
|
||||
impl Log for Logger {
|
||||
fn enabled(&self, _metadata: &Metadata) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn log(&self, record: &Record) {
|
||||
let client = get!();
|
||||
let level = match record.level() {
|
||||
Level::Error => LogLevel::Error,
|
||||
Level::Warn => LogLevel::Warn,
|
||||
Level::Info => LogLevel::Info,
|
||||
Level::Debug => LogLevel::Debug,
|
||||
Level::Trace => LogLevel::Trace,
|
||||
};
|
||||
let formatted;
|
||||
let msg = match record.args().as_str() {
|
||||
Some(s) => s,
|
||||
_ => {
|
||||
formatted = record.args().to_string();
|
||||
&formatted
|
||||
}
|
||||
};
|
||||
client.log(level, msg, record.file(), record.line());
|
||||
}
|
||||
|
||||
fn flush(&self) {
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
18
i4config/src/keyboard/keymap.rs
Normal file
18
i4config/src/keyboard/keymap.rs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
use bincode::{Decode, Encode};
|
||||
|
||||
#[derive(Encode, Decode, Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub struct Keymap(pub u64);
|
||||
|
||||
impl Keymap {
|
||||
pub const INVALID: Self = Self(0);
|
||||
|
||||
pub fn is_invalid(self) -> bool {
|
||||
self == Self::INVALID
|
||||
}
|
||||
|
||||
pub fn parse(self, keymap: &str) -> Self {
|
||||
let mut res = Self::INVALID;
|
||||
(|| res = get!().parse_keymap(keymap))();
|
||||
res
|
||||
}
|
||||
}
|
||||
40
i4config/src/keyboard/mod.rs
Normal file
40
i4config/src/keyboard/mod.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
use crate::keyboard::mods::Modifiers;
|
||||
use crate::keyboard::syms::KeySym;
|
||||
use bincode::{Decode, Encode};
|
||||
use std::ops::{BitOr, BitOrAssign};
|
||||
|
||||
pub mod mods;
|
||||
pub mod syms;
|
||||
pub mod keymap;
|
||||
|
||||
#[derive(Encode, Decode, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct ModifiedKeySym {
|
||||
pub mods: Modifiers,
|
||||
pub sym: KeySym,
|
||||
}
|
||||
|
||||
impl From<KeySym> for ModifiedKeySym {
|
||||
fn from(sym: KeySym) -> Self {
|
||||
Self {
|
||||
mods: Modifiers(0),
|
||||
sym,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BitOr<Modifiers> for ModifiedKeySym {
|
||||
type Output = ModifiedKeySym;
|
||||
|
||||
fn bitor(self, rhs: Modifiers) -> Self::Output {
|
||||
ModifiedKeySym {
|
||||
mods: self.mods | rhs,
|
||||
sym: self.sym,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BitOrAssign<Modifiers> for ModifiedKeySym {
|
||||
fn bitor_assign(&mut self, rhs: Modifiers) {
|
||||
self.mods |= rhs;
|
||||
}
|
||||
}
|
||||
60
i4config/src/keyboard/mods.rs
Normal file
60
i4config/src/keyboard/mods.rs
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
use crate::keyboard::syms::KeySym;
|
||||
use crate::ModifiedKeySym;
|
||||
use bincode::{Decode, Encode};
|
||||
use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign};
|
||||
|
||||
#[derive(Encode, Decode, Copy, Clone, Eq, PartialEq, Default, Hash, Debug)]
|
||||
pub struct Modifiers(pub u32);
|
||||
|
||||
pub const SHIFT: Modifiers = Modifiers(1 << 0);
|
||||
pub const LOCK: Modifiers = Modifiers(1 << 1);
|
||||
pub const CTRL: Modifiers = Modifiers(1 << 2);
|
||||
pub const MOD1: Modifiers = Modifiers(1 << 3);
|
||||
pub const MOD2: Modifiers = Modifiers(1 << 4);
|
||||
pub const MOD3: Modifiers = Modifiers(1 << 5);
|
||||
pub const MOD4: Modifiers = Modifiers(1 << 6);
|
||||
pub const MOD5: Modifiers = Modifiers(1 << 7);
|
||||
|
||||
pub const CAPS: Modifiers = LOCK;
|
||||
pub const ALT: Modifiers = MOD1;
|
||||
pub const NUM: Modifiers = MOD2;
|
||||
pub const LOGO: Modifiers = MOD4;
|
||||
|
||||
impl BitOr for Modifiers {
|
||||
type Output = Self;
|
||||
|
||||
fn bitor(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 | rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl BitOr<KeySym> for Modifiers {
|
||||
type Output = ModifiedKeySym;
|
||||
|
||||
fn bitor(self, rhs: KeySym) -> Self::Output {
|
||||
ModifiedKeySym {
|
||||
mods: self,
|
||||
sym: rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BitAnd for Modifiers {
|
||||
type Output = Self;
|
||||
|
||||
fn bitand(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 & rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl BitOrAssign for Modifiers {
|
||||
fn bitor_assign(&mut self, rhs: Self) {
|
||||
self.0 |= rhs.0
|
||||
}
|
||||
}
|
||||
|
||||
impl BitAndAssign for Modifiers {
|
||||
fn bitand_assign(&mut self, rhs: Self) {
|
||||
self.0 &= rhs.0
|
||||
}
|
||||
}
|
||||
2556
i4config/src/keyboard/syms.rs
Normal file
2556
i4config/src/keyboard/syms.rs
Normal file
File diff suppressed because it is too large
Load diff
131
i4config/src/lib.rs
Normal file
131
i4config/src/lib.rs
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
#![feature(thread_local_const_init)]
|
||||
|
||||
use crate::keyboard::ModifiedKeySym;
|
||||
use bincode::{Decode, Encode};
|
||||
use crate::keyboard::keymap::Keymap;
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
#[doc(hidden)]
|
||||
pub mod _private;
|
||||
pub mod keyboard;
|
||||
|
||||
#[derive(Encode, Decode, Copy, Clone, Debug)]
|
||||
pub enum LogLevel {
|
||||
Error,
|
||||
Warn,
|
||||
Info,
|
||||
Debug,
|
||||
Trace,
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Copy, Clone, Debug)]
|
||||
pub enum Direction {
|
||||
Left,
|
||||
Down,
|
||||
Up,
|
||||
Right,
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
pub struct Seat(pub u64);
|
||||
|
||||
impl Seat {
|
||||
pub const INVALID: Self = Self(0);
|
||||
|
||||
pub fn is_invalid(self) -> bool {
|
||||
self == Self::INVALID
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
pub struct Keyboard(pub u64);
|
||||
|
||||
#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
pub struct Mouse(pub u64);
|
||||
|
||||
#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
pub enum InputDevice {
|
||||
Keyboard(Keyboard),
|
||||
Mouse(Mouse),
|
||||
}
|
||||
|
||||
impl InputDevice {
|
||||
pub fn set_seat(self, seat: Seat) {
|
||||
get!().set_seat(self, seat)
|
||||
}
|
||||
}
|
||||
|
||||
impl Seat {
|
||||
#[doc(hidden)]
|
||||
pub fn raw(self) -> u64 {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn from_raw(raw: u64) -> Self {
|
||||
Self(raw)
|
||||
}
|
||||
|
||||
pub fn bind<T: Into<ModifiedKeySym>, F: Fn() + 'static>(self, mod_sym: T, f: F) {
|
||||
get!().bind(self, mod_sym, f)
|
||||
}
|
||||
|
||||
pub fn unbind<T: Into<ModifiedKeySym>>(self, mod_sym: T) {
|
||||
get!().unbind(self, mod_sym)
|
||||
}
|
||||
|
||||
pub fn focus(self, direction: Direction) {
|
||||
get!().focus(self, direction)
|
||||
}
|
||||
|
||||
pub fn move_(self, direction: Direction) {
|
||||
get!().move_(self, direction)
|
||||
}
|
||||
|
||||
pub fn set_keymap(self, keymap: Keymap) {
|
||||
get!().seat_set_keymap(self, keymap)
|
||||
}
|
||||
|
||||
pub fn set_repeat_rate(self, rate: i32, delay: i32) {
|
||||
get!().seat_set_repeat_rate(self, rate, delay)
|
||||
}
|
||||
|
||||
pub fn repeat_rate(self) -> (i32, i32) {
|
||||
let mut res = (25, 250);
|
||||
(|| res = get!().seat_get_repeat_rate(self))();
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_seats() -> Vec<Seat> {
|
||||
let mut res = vec![];
|
||||
(|| res = get!().seats())();
|
||||
res
|
||||
}
|
||||
|
||||
pub fn input_devices() -> Vec<InputDevice> {
|
||||
let mut res = vec![];
|
||||
(|| res = get!().get_input_devices())();
|
||||
res
|
||||
}
|
||||
|
||||
pub fn remove_all_seats() {}
|
||||
|
||||
pub fn create_seat(name: &str) -> Seat {
|
||||
let mut res = Seat(0);
|
||||
(|| res = get!().create_seat(name))();
|
||||
res
|
||||
}
|
||||
|
||||
pub fn on_new_seat<F: Fn(Seat) + 'static>(f: F) {
|
||||
get!().on_new_seat(f)
|
||||
}
|
||||
|
||||
pub fn on_new_input_device<F: Fn(InputDevice) + 'static>(f: F) {
|
||||
get!().on_new_input_device(f)
|
||||
}
|
||||
|
||||
pub fn shell(shell: &str) {
|
||||
get!().shell(shell)
|
||||
}
|
||||
68
i4config/src/macros.rs
Normal file
68
i4config/src/macros.rs
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
#[macro_export]
|
||||
macro_rules! config {
|
||||
($f:path) => {
|
||||
#[no_mangle]
|
||||
#[used]
|
||||
pub static mut I4_CONFIG_ENTRY: $crate::_private::ConfigEntry = {
|
||||
struct X;
|
||||
impl $crate::_private::Config for X {
|
||||
extern "C" fn configure() {
|
||||
$f();
|
||||
}
|
||||
}
|
||||
$crate::_private::ConfigEntryGen::<X>::ENTRY
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! get {
|
||||
() => {{
|
||||
#[allow(unused_unsafe)]
|
||||
let client = unsafe {
|
||||
let client = crate::_private::client::CLIENT.with(|client| client.get());
|
||||
if client.is_null() {
|
||||
return;
|
||||
}
|
||||
&*client
|
||||
};
|
||||
client
|
||||
}};
|
||||
}
|
||||
|
||||
// #[macro_export]
|
||||
// macro_rules! log {
|
||||
// ($lvl:expr, $($arg:tt)+) => ({
|
||||
// $crate::log(
|
||||
// $lvl,
|
||||
// &format!($($args)*),
|
||||
// );
|
||||
// })
|
||||
// }
|
||||
//
|
||||
// #[macro_export]
|
||||
// macro_rules! trace {
|
||||
// ($($arg:tt)+) => {
|
||||
// $crate::log!($crate::LogLevel::Trace, $($arg)+)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// #[macro_export]
|
||||
// macro_rules! debug {
|
||||
// ($($arg:tt)+) => {
|
||||
// $crate::log!($crate::LogLevel::Debug, $($arg)+)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// #[macro_export]
|
||||
// macro_rules! info {
|
||||
// ($($arg:tt)+) => {
|
||||
// $crate::log!($crate::LogLevel::Info, $($arg)+)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// #[macro_export]
|
||||
// macro_rules! info {
|
||||
// ($($arg:tt)+) => {
|
||||
// $crate::log!($crate::LogLevel::Info, $($arg)+)
|
||||
// }
|
||||
// }
|
||||
|
|
@ -3,7 +3,8 @@ use std::fmt::Debug;
|
|||
use std::rc::Rc;
|
||||
|
||||
linear_ids!(OutputIds, OutputId);
|
||||
linear_ids!(SeatIds, SeatId);
|
||||
linear_ids!(KeyboardIds, KeyboardId);
|
||||
linear_ids!(MouseIds, MouseId);
|
||||
|
||||
pub trait Output {
|
||||
fn id(&self) -> OutputId;
|
||||
|
|
@ -13,16 +14,24 @@ pub trait Output {
|
|||
fn on_change(&self, cb: Rc<dyn Fn()>);
|
||||
}
|
||||
|
||||
pub trait Seat {
|
||||
fn id(&self) -> SeatId;
|
||||
pub trait Keyboard {
|
||||
fn id(&self) -> KeyboardId;
|
||||
fn removed(&self) -> bool;
|
||||
fn event(&self) -> Option<SeatEvent>;
|
||||
fn event(&self) -> Option<KeyboardEvent>;
|
||||
fn on_change(&self, cb: Rc<dyn Fn()>);
|
||||
}
|
||||
|
||||
pub trait Mouse {
|
||||
fn id(&self) -> MouseId;
|
||||
fn removed(&self) -> bool;
|
||||
fn event(&self) -> Option<MouseEvent>;
|
||||
fn on_change(&self, cb: Rc<dyn Fn()>);
|
||||
}
|
||||
|
||||
pub enum BackendEvent {
|
||||
NewOutput(Rc<dyn Output>),
|
||||
NewSeat(Rc<dyn Seat>),
|
||||
NewKeyboard(Rc<dyn Keyboard>),
|
||||
NewMouse(Rc<dyn Mouse>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
|
|
@ -38,11 +47,15 @@ pub enum ScrollAxis {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SeatEvent {
|
||||
pub enum KeyboardEvent {
|
||||
Key(u32, KeyState),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum MouseEvent {
|
||||
OutputPosition(OutputId, Fixed, Fixed),
|
||||
#[allow(dead_code)]
|
||||
Motion(Fixed, Fixed),
|
||||
Button(u32, KeyState),
|
||||
Scroll(i32, ScrollAxis),
|
||||
Key(u32, KeyState),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
use crate::backend::{
|
||||
BackendEvent, KeyState, Output, OutputId, ScrollAxis, Seat, SeatEvent, SeatId,
|
||||
};
|
||||
use crate::backend::{BackendEvent, Keyboard, KeyboardEvent, KeyboardId, KeyState, Mouse, MouseEvent, MouseId, Output, OutputId, ScrollAxis};
|
||||
use crate::drm::drm::{Drm, DrmError};
|
||||
use crate::drm::gbm::{GbmDevice, GbmError, GBM_BO_USE_RENDERING};
|
||||
use crate::drm::{ModifiedFormat, INVALID_MODIFIER};
|
||||
|
|
@ -519,14 +517,15 @@ impl XorgBackend {
|
|||
}
|
||||
|
||||
fn handle_input_device(self: &Rc<Self>, info: &ffi::xcb_input_xi_device_info_t) {
|
||||
if info.type_ != ffi::XCB_INPUT_DEVICE_TYPE_MASTER_KEYBOARD as _ {
|
||||
if info.type_ != ffi::XCB_INPUT_DEVICE_TYPE_MASTER_KEYBOARD as u16 {
|
||||
return;
|
||||
}
|
||||
let con = &self.con;
|
||||
self.mouse_seats.remove(&info.attachment);
|
||||
if let Some(kb) = self.seats.remove(&info.deviceid) {
|
||||
kb.removed.set(true);
|
||||
kb.changed();
|
||||
kb.kb_changed();
|
||||
kb.mouse_changed();
|
||||
}
|
||||
unsafe {
|
||||
let mut err = ptr::null_mut();
|
||||
|
|
@ -550,13 +549,16 @@ impl XorgBackend {
|
|||
);
|
||||
}
|
||||
let seat = Rc::new(XorgSeat {
|
||||
id: self.state.seat_ids.next(),
|
||||
kb_id: self.state.kb_ids.next(),
|
||||
mouse_id: self.state.mouse_ids.next(),
|
||||
backend: self.clone(),
|
||||
_kb: info.deviceid,
|
||||
mouse: info.attachment,
|
||||
removed: Cell::new(false),
|
||||
cb: CloneCell::new(None),
|
||||
events: RefCell::new(Default::default()),
|
||||
kb_cb: Default::default(),
|
||||
mouse_cb: Default::default(),
|
||||
kb_events: RefCell::new(Default::default()),
|
||||
mouse_events: RefCell::new(Default::default()),
|
||||
button_map: Default::default(),
|
||||
});
|
||||
seat.update_button_map();
|
||||
|
|
@ -564,7 +566,10 @@ impl XorgBackend {
|
|||
self.mouse_seats.set(info.attachment, seat.clone());
|
||||
self.state
|
||||
.backend_events
|
||||
.push(BackendEvent::NewSeat(seat.clone()));
|
||||
.push(BackendEvent::NewMouse(seat.clone()));
|
||||
self.state
|
||||
.backend_events
|
||||
.push(BackendEvent::NewKeyboard(seat.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -756,7 +761,7 @@ impl XorgBackend {
|
|||
7 => (ScrollAxis::Horizontal, 15),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
seat.event(SeatEvent::Scroll(val, axis));
|
||||
seat.mouse_event(MouseEvent::Scroll(val, axis));
|
||||
}
|
||||
} else {
|
||||
const BTN_LEFT: u32 = 0x110;
|
||||
|
|
@ -770,7 +775,7 @@ impl XorgBackend {
|
|||
3 => BTN_RIGHT,
|
||||
n => BTN_SIDE + n - 8,
|
||||
};
|
||||
seat.event(SeatEvent::Button(button, state));
|
||||
seat.mouse_event(MouseEvent::Button(button, state));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
|
@ -790,7 +795,7 @@ impl XorgBackend {
|
|||
let event =
|
||||
unsafe { (event as *const _ as *const ffi::xcb_input_key_press_event_t).deref() };
|
||||
if let Some(seat) = self.seats.get(&event.deviceid) {
|
||||
seat.event(SeatEvent::Key(event.detail - 8, state));
|
||||
seat.kb_event(KeyboardEvent::Key(event.detail - 8, state));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -816,7 +821,8 @@ impl XorgBackend {
|
|||
self.mouse_seats.remove(&info.attachment);
|
||||
if let Some(seat) = self.seats.remove(&info.deviceid) {
|
||||
seat.removed.set(true);
|
||||
seat.changed();
|
||||
seat.kb_changed();
|
||||
seat.mouse_changed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -832,7 +838,7 @@ impl XorgBackend {
|
|||
self.outputs.get(&event.event),
|
||||
self.mouse_seats.get(&event.deviceid),
|
||||
) {
|
||||
seat.event(SeatEvent::OutputPosition(
|
||||
seat.mouse_event(MouseEvent::OutputPosition(
|
||||
win.id,
|
||||
Fixed::from_1616(event.event_x),
|
||||
Fixed::from_1616(event.event_y),
|
||||
|
|
@ -853,7 +859,7 @@ impl XorgBackend {
|
|||
(Some(a), Some(b)) => (a, b),
|
||||
_ => return Ok(()),
|
||||
};
|
||||
seat.event(SeatEvent::OutputPosition(
|
||||
seat.mouse_event(MouseEvent::OutputPosition(
|
||||
win.id,
|
||||
Fixed::from_1616(event.event_x),
|
||||
Fixed::from_1616(event.event_y),
|
||||
|
|
@ -986,26 +992,40 @@ impl Output for XorgOutput {
|
|||
}
|
||||
|
||||
struct XorgSeat {
|
||||
id: SeatId,
|
||||
kb_id: KeyboardId,
|
||||
mouse_id: MouseId,
|
||||
backend: Rc<XorgBackend>,
|
||||
_kb: ffi::xcb_input_device_id_t,
|
||||
mouse: ffi::xcb_input_device_id_t,
|
||||
removed: Cell<bool>,
|
||||
cb: CloneCell<Option<Rc<dyn Fn()>>>,
|
||||
events: RefCell<VecDeque<SeatEvent>>,
|
||||
kb_cb: CloneCell<Option<Rc<dyn Fn()>>>,
|
||||
mouse_cb: CloneCell<Option<Rc<dyn Fn()>>>,
|
||||
kb_events: RefCell<VecDeque<KeyboardEvent>>,
|
||||
mouse_events: RefCell<VecDeque<MouseEvent>>,
|
||||
button_map: CopyHashMap<u32, u32>,
|
||||
}
|
||||
|
||||
impl XorgSeat {
|
||||
fn changed(&self) {
|
||||
if let Some(cb) = self.cb.get() {
|
||||
fn kb_changed(&self) {
|
||||
if let Some(cb) = self.kb_cb.get() {
|
||||
cb();
|
||||
}
|
||||
}
|
||||
|
||||
fn event(&self, event: SeatEvent) {
|
||||
self.events.borrow_mut().push_back(event);
|
||||
self.changed();
|
||||
fn mouse_changed(&self) {
|
||||
if let Some(cb) = self.mouse_cb.get() {
|
||||
cb();
|
||||
}
|
||||
}
|
||||
|
||||
fn mouse_event(&self, event: MouseEvent) {
|
||||
self.mouse_events.borrow_mut().push_back(event);
|
||||
self.mouse_changed();
|
||||
}
|
||||
|
||||
fn kb_event(&self, event: KeyboardEvent) {
|
||||
self.kb_events.borrow_mut().push_back(event);
|
||||
self.kb_changed();
|
||||
}
|
||||
|
||||
fn update_button_map(&self) {
|
||||
|
|
@ -1041,20 +1061,38 @@ impl XorgSeat {
|
|||
}
|
||||
}
|
||||
|
||||
impl Seat for XorgSeat {
|
||||
fn id(&self) -> SeatId {
|
||||
self.id
|
||||
impl Keyboard for XorgSeat {
|
||||
fn id(&self) -> KeyboardId {
|
||||
self.kb_id
|
||||
}
|
||||
|
||||
fn removed(&self) -> bool {
|
||||
self.removed.get()
|
||||
}
|
||||
|
||||
fn event(&self) -> Option<SeatEvent> {
|
||||
self.events.borrow_mut().pop_front()
|
||||
fn event(&self) -> Option<KeyboardEvent> {
|
||||
self.kb_events.borrow_mut().pop_front()
|
||||
}
|
||||
|
||||
fn on_change(&self, cb: Rc<dyn Fn()>) {
|
||||
self.cb.set(Some(cb));
|
||||
self.kb_cb.set(Some(cb));
|
||||
}
|
||||
}
|
||||
|
||||
impl Mouse for XorgSeat {
|
||||
fn id(&self) -> MouseId {
|
||||
self.mouse_id
|
||||
}
|
||||
|
||||
fn removed(&self) -> bool {
|
||||
self.removed.get()
|
||||
}
|
||||
|
||||
fn event(&self) -> Option<MouseEvent> {
|
||||
self.mouse_events.borrow_mut().pop_front()
|
||||
}
|
||||
|
||||
fn on_change(&self, cb: Rc<dyn Fn()>) {
|
||||
self.mouse_cb.set(Some(cb));
|
||||
}
|
||||
}
|
||||
154
src/config.rs
Normal file
154
src/config.rs
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
mod handler;
|
||||
|
||||
use crate::backend::{KeyboardId, MouseId};
|
||||
use crate::utils::ptr_ext::PtrExt;
|
||||
use crate::{NumCell, State};
|
||||
use i4config::_private::ipc::{InitMessage, Request, V1InitMessage};
|
||||
use i4config::_private::{bincode_ops, ConfigEntry, VERSION};
|
||||
use i4config::keyboard::ModifiedKeySym;
|
||||
use libloading::Library;
|
||||
use std::cell::Cell;
|
||||
use std::ptr;
|
||||
use std::rc::Rc;
|
||||
use thiserror::Error;
|
||||
use i4config::{InputDevice, Keyboard, Mouse, Seat};
|
||||
use crate::config::handler::ConfigProxyHandler;
|
||||
use crate::ifs::wl_seat::{SeatId};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ConfigError {
|
||||
#[error("Could not load the config library")]
|
||||
CouldNotLoadLibrary(#[source] libloading::Error),
|
||||
#[error("Config library does not contain the entry symbol")]
|
||||
LibraryDoesNotContainEntry(#[source] libloading::Error),
|
||||
}
|
||||
|
||||
pub struct ConfigProxy {
|
||||
handler: Rc<ConfigProxyHandler>,
|
||||
}
|
||||
|
||||
impl ConfigProxy {
|
||||
pub fn invoke_shortcut(&self, seat: SeatId, modsym: &ModifiedKeySym) {
|
||||
self.handler.send(&Request::InvokeShortcut {
|
||||
seat: Seat(seat.raw() as _),
|
||||
mods: modsym.mods,
|
||||
sym: modsym.sym,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn new_keyboard(&self, kb: KeyboardId) {
|
||||
self.handler.send(&Request::NewInputDevice {
|
||||
device: InputDevice::Keyboard(Keyboard(kb.raw() as _)),
|
||||
});
|
||||
}
|
||||
|
||||
pub fn new_mouse(&self, mouse: MouseId) {
|
||||
self.handler.send(&Request::NewInputDevice {
|
||||
device: InputDevice::Mouse(Mouse(mouse.raw() as _)),
|
||||
});
|
||||
}
|
||||
|
||||
pub fn del_keyboard(&self, kb: KeyboardId) {
|
||||
self.handler.send(&Request::DelInputDevice {
|
||||
device: InputDevice::Keyboard(Keyboard(kb.raw() as _)),
|
||||
});
|
||||
}
|
||||
|
||||
pub fn del_mouse(&self, mouse: MouseId) {
|
||||
self.handler.send(&Request::DelInputDevice {
|
||||
device: InputDevice::Mouse(Mouse(mouse.raw() as _)),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ConfigProxy {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
self.handler.dropped.set(true);
|
||||
(self.handler.unref)(self.handler.client_data.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn default_client_init(
|
||||
srv_data: *const u8,
|
||||
srv_unref: unsafe extern "C" fn(data: *const u8),
|
||||
srv_handler: unsafe extern "C" fn(data: *const u8, msg: *const u8, size: usize),
|
||||
msg: *const u8,
|
||||
size: usize,
|
||||
) -> *const u8 {
|
||||
extern "C" fn configure() {
|
||||
default_config::configure();
|
||||
}
|
||||
i4config::_private::client::init(srv_data, srv_unref, srv_handler, msg, size, configure)
|
||||
}
|
||||
|
||||
impl ConfigProxy {
|
||||
fn new(lib: Option<Library>, entry: &ConfigEntry, state: &Rc<State>) -> Self {
|
||||
let version = entry.version.min(VERSION);
|
||||
let data = Rc::new(ConfigProxyHandler {
|
||||
client_data: Cell::new(ptr::null()),
|
||||
dropped: Cell::new(false),
|
||||
_lib: lib,
|
||||
_version: version,
|
||||
unref: entry.unref,
|
||||
handle_msg: entry.handle_msg,
|
||||
state: state.clone(),
|
||||
next_id: NumCell::new(1),
|
||||
keymaps: Default::default(),
|
||||
bufs: Default::default(),
|
||||
});
|
||||
let init_msg =
|
||||
bincode::encode_to_vec(&InitMessage::V1(V1InitMessage {}), bincode_ops()).unwrap();
|
||||
unsafe {
|
||||
let client_data = (entry.init)(
|
||||
Rc::into_raw(data.clone()) as _,
|
||||
unref,
|
||||
handle_msg,
|
||||
init_msg.as_ptr(),
|
||||
init_msg.len(),
|
||||
);
|
||||
data.client_data.set(client_data);
|
||||
}
|
||||
data.send(&Request::Configure);
|
||||
Self { handler: data }
|
||||
}
|
||||
|
||||
pub fn default(state: &Rc<State>) -> Self {
|
||||
let entry = ConfigEntry {
|
||||
version: VERSION,
|
||||
init: default_client_init,
|
||||
unref: i4config::_private::client::unref,
|
||||
handle_msg: i4config::_private::client::handle_msg,
|
||||
};
|
||||
Self::new(None, &entry, state)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub unsafe fn from_file(path: &str, state: &Rc<State>) -> Result<Self, ConfigError> {
|
||||
let lib = match Library::new(path) {
|
||||
Ok(l) => l,
|
||||
Err(e) => return Err(ConfigError::CouldNotLoadLibrary(e)),
|
||||
};
|
||||
let entry = lib.get::<&'static ConfigEntry>(b"I4_CONFIG_ENTRY\0");
|
||||
let entry = match entry {
|
||||
Ok(e) => *e,
|
||||
Err(e) => return Err(ConfigError::LibraryDoesNotContainEntry(e)),
|
||||
};
|
||||
Ok(Self::new(Some(lib), entry, state))
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn unref(data: *const u8) {
|
||||
let server = data as *const ConfigProxyHandler;
|
||||
drop(Rc::from_raw(server));
|
||||
}
|
||||
|
||||
unsafe extern "C" fn handle_msg(data: *const u8, msg: *const u8, size: usize) {
|
||||
let server = (data as *const ConfigProxyHandler).deref();
|
||||
if server.dropped.get() {
|
||||
return;
|
||||
}
|
||||
let msg = std::slice::from_raw_parts(msg, size);
|
||||
server.handle_request(msg);
|
||||
}
|
||||
370
src/config/handler.rs
Normal file
370
src/config/handler.rs
Normal file
|
|
@ -0,0 +1,370 @@
|
|||
use std::cell::{Cell};
|
||||
use std::rc::Rc;
|
||||
use bincode::error::DecodeError;
|
||||
use libloading::Library;
|
||||
use log::Level;
|
||||
use thiserror::Error;
|
||||
use i4config::_private::bincode_ops;
|
||||
use i4config::_private::ipc::{Request, Response};
|
||||
use i4config::keyboard::keymap::Keymap;
|
||||
use i4config::{Direction, InputDevice, Keyboard, LogLevel, Mouse, Seat};
|
||||
use i4config::keyboard::mods::Modifiers;
|
||||
use i4config::keyboard::syms::KeySym;
|
||||
use crate::{ErrorFmt, NumCell, State};
|
||||
use crate::backend::{KeyboardId, MouseId};
|
||||
use crate::ifs::wl_seat::WlSeatGlobal;
|
||||
use crate::state::DeviceHandlerData;
|
||||
use crate::utils::copyhashmap::CopyHashMap;
|
||||
use crate::utils::debug_fn::debug_fn;
|
||||
use crate::utils::stack::Stack;
|
||||
use crate::xkbcommon::XkbKeymap;
|
||||
|
||||
pub(super) struct ConfigProxyHandler {
|
||||
pub client_data: Cell<*const u8>,
|
||||
pub dropped: Cell<bool>,
|
||||
pub _lib: Option<Library>,
|
||||
pub _version: u32,
|
||||
pub unref: unsafe extern "C" fn(data: *const u8),
|
||||
pub handle_msg: unsafe extern "C" fn(data: *const u8, msg: *const u8, size: usize),
|
||||
pub state: Rc<State>,
|
||||
pub next_id: NumCell<u64>,
|
||||
pub keymaps: CopyHashMap<Keymap, Rc<XkbKeymap>>,
|
||||
pub bufs: Stack<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl ConfigProxyHandler {
|
||||
pub fn send(&self, msg: &Request) {
|
||||
let mut buf = self.bufs.pop().unwrap_or_default();
|
||||
buf.clear();
|
||||
bincode::encode_into_std_write(msg, &mut buf, bincode_ops()).unwrap();
|
||||
unsafe {
|
||||
(self.handle_msg)(self.client_data.get(), buf.as_ptr(), buf.len());
|
||||
}
|
||||
self.bufs.push(buf);
|
||||
}
|
||||
|
||||
fn id(&self) -> u64 {
|
||||
self.next_id.fetch_add(1)
|
||||
}
|
||||
|
||||
fn handle_log_request(&self, level: LogLevel, msg: &str, file: Option<&str>, line: Option<u32>) -> Result<(), LogError> {
|
||||
let level = match level {
|
||||
LogLevel::Error => Level::Error,
|
||||
LogLevel::Warn => Level::Warn,
|
||||
LogLevel::Info => Level::Info,
|
||||
LogLevel::Debug => Level::Debug,
|
||||
LogLevel::Trace => Level::Trace,
|
||||
};
|
||||
let debug = debug_fn(|fmt| {
|
||||
if let Some(file) = file {
|
||||
write!(fmt, "{}", file)?;
|
||||
if let Some(line) = line {
|
||||
write!(fmt, ":{}", line)?;
|
||||
}
|
||||
write!(fmt, ": ")?;
|
||||
}
|
||||
write!(fmt, "{}", msg)?;
|
||||
Ok(())
|
||||
});
|
||||
log::log!(level, "{:?}", debug);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_create_seat(&self, name: &str) -> Result<(), CreateSeatError> {
|
||||
let global_name = self.state.globals.name();
|
||||
let seat = WlSeatGlobal::new(global_name, name, &self.state);
|
||||
self.state.globals.add_global(&self.state, &seat);
|
||||
self.send(&Request::Response {
|
||||
response: Response::CreateSeat {
|
||||
seat: Seat(seat.id().raw() as _),
|
||||
}
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_parse_keymap(&self, keymap: &str) -> Result<(), ParseKeymapError> {
|
||||
let (keymap, res) = match self.state.xkb_ctx.keymap_from_str(keymap) {
|
||||
Ok(keymap) => {
|
||||
let id = Keymap(self.id());
|
||||
self.keymaps.set(id, keymap);
|
||||
(id, Ok(()))
|
||||
}
|
||||
_ => {
|
||||
(Keymap::INVALID, Err(ParseKeymapError::ParsingFailed))
|
||||
}
|
||||
};
|
||||
self.send(&Request::Response { response: Response::ParseKeymap { keymap } });
|
||||
res
|
||||
}
|
||||
|
||||
fn handle_set_keymap(&self, seat: Seat, keymap: Keymap) -> Result<(), SeatSetKeymapError> {
|
||||
let seat = self.get_seat(seat)?;
|
||||
let keymap = if keymap.is_invalid() {
|
||||
self.state.default_keymap.clone()
|
||||
} else {
|
||||
self.get_keymap(keymap)?
|
||||
};
|
||||
seat.set_keymap(&keymap);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_focus(&self, seat: Seat, direction: Direction) -> Result<(), FocusError> {
|
||||
let seat = self.get_seat(seat)?;
|
||||
seat.move_focus(direction);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_get_repeat_rate(&self, seat: Seat) -> Result<(), SeatGetRepeatRateError> {
|
||||
let seat = self.get_seat(seat)?;
|
||||
let (rate, delay) = seat.get_rate();
|
||||
self.send(&Request::Response {
|
||||
response: Response::GetRepeatRate {
|
||||
rate,
|
||||
delay,
|
||||
},
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_set_repeat_rate(&self, seat: Seat, rate: i32, delay: i32) -> Result<(), SeatSetRepeatRateError> {
|
||||
let seat = self.get_seat(seat)?;
|
||||
if rate < 0 {
|
||||
return Err(SeatSetRepeatRateError::NegativeRate);
|
||||
}
|
||||
if delay < 0 {
|
||||
return Err(SeatSetRepeatRateError::NegativeDelay);
|
||||
}
|
||||
seat.set_rate(rate, delay);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_device_handler_data(&self, device: InputDevice) -> Result<Rc<DeviceHandlerData>, CphError> {
|
||||
let data = match device {
|
||||
InputDevice::Keyboard(kb) => {
|
||||
self.state.kb_handlers.borrow_mut().get(&KeyboardId::from_raw(kb.0 as _)).map(|d| d.data.clone())
|
||||
},
|
||||
InputDevice::Mouse(mouse) => {
|
||||
self.state.mouse_handlers.borrow_mut().get(&MouseId::from_raw(mouse.0 as _)).map(|d| d.data.clone())
|
||||
}
|
||||
};
|
||||
match data {
|
||||
Some(d) => Ok(d),
|
||||
_ => Err(CphError::DeviceDoesNotExist(device)),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_seat(&self, seat: Seat) -> Result<Rc<WlSeatGlobal>, CphError> {
|
||||
let seats = self.state.globals.seats.lock();
|
||||
for seat_global in seats.values() {
|
||||
if seat_global.id().raw() == seat.0 as _ {
|
||||
return Ok(seat_global.clone());
|
||||
}
|
||||
}
|
||||
Err(CphError::SeatDoesNotExist(seat))
|
||||
}
|
||||
|
||||
fn get_keymap(&self, keymap: Keymap) -> Result<Rc<XkbKeymap>, CphError> {
|
||||
match self.keymaps.get(&keymap) {
|
||||
Some(k) => Ok(k),
|
||||
None => Err(CphError::KeymapDoesNotExist(keymap)),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_set_seat(&self, device: InputDevice, seat: Seat) -> Result<(), SetSeatError> {
|
||||
let seat = if seat.is_invalid() {
|
||||
None
|
||||
} else {
|
||||
Some(self.get_seat(seat)?)
|
||||
};
|
||||
let dev = self.get_device_handler_data(device)?;
|
||||
dev.seat.set(seat);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_add_shortcut(&self, seat: Seat, mods: Modifiers, sym: KeySym) -> Result<(), AddShortcutError> {
|
||||
let seat = self.get_seat(seat)?;
|
||||
seat.add_shortcut(mods, sym);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_get_input_devices(&self) -> Result<(), GetInputDevicesError> {
|
||||
let mut res = vec!();
|
||||
{
|
||||
let devs = self.state.kb_handlers.borrow_mut();
|
||||
for dev in devs.values() {
|
||||
res.push(InputDevice::Keyboard(Keyboard(dev.id.raw() as _)));
|
||||
}
|
||||
}
|
||||
{
|
||||
let devs = self.state.mouse_handlers.borrow_mut();
|
||||
for dev in devs.values() {
|
||||
res.push(InputDevice::Mouse(Mouse(dev.id.raw() as _)));
|
||||
}
|
||||
}
|
||||
self.send(&Request::Response {
|
||||
response: Response::GetInputDevices { devices: res },
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_get_seats(&self) -> Result<(), GetSeatsError> {
|
||||
let seats = {
|
||||
let seats = self.state.globals.seats.lock();
|
||||
seats
|
||||
.values()
|
||||
.map(|seat| Seat::from_raw(seat.id().raw() as _))
|
||||
.collect()
|
||||
};
|
||||
self.send(&Request::Response {
|
||||
response: Response::GetSeats { seats },
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn handle_request(&self, msg: &[u8]) {
|
||||
if let Err(e) = self.handle_request_(msg) {
|
||||
log::error!("Could not handle client request: {}", ErrorFmt(e));
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_request_(&self, msg: &[u8]) -> Result<(), CphError> {
|
||||
let (request, _) = match bincode::decode_from_slice::<Request, _>(msg, bincode_ops()) {
|
||||
Ok(msg) => msg,
|
||||
Err(e) => return Err(CphError::ParsingFailed(e)),
|
||||
};
|
||||
match request {
|
||||
Request::Log {
|
||||
level,
|
||||
msg,
|
||||
file,
|
||||
line,
|
||||
} => self.handle_log_request(level, msg, file, line)?,
|
||||
Request::CreateSeat { name } => self.handle_create_seat(name)?,
|
||||
Request::ParseKeymap { keymap } => self.handle_parse_keymap(keymap)?,
|
||||
Request::SeatSetKeymap { seat, keymap } => self.handle_set_keymap(seat, keymap)?,
|
||||
Request::SeatGetRepeatRate { seat } => self.handle_get_repeat_rate(seat)?,
|
||||
Request::SeatSetRepeatRate { seat, rate, delay } => self.handle_set_repeat_rate(seat, rate, delay)?,
|
||||
Request::SetSeat { device, seat } => self.handle_set_seat(device, seat)?,
|
||||
Request::AddShortcut {
|
||||
seat,
|
||||
mods,
|
||||
sym,
|
||||
} => self.handle_add_shortcut(seat, mods, sym)?,
|
||||
Request::RemoveShortcut { .. } => {}
|
||||
Request::Focus { seat, direction } => self.handle_focus(seat, direction)?,
|
||||
Request::Move { seat, direction } => {}
|
||||
Request::GetInputDevices => self.handle_get_input_devices()?,
|
||||
Request::GetSeats => self.handle_get_seats()?,
|
||||
m => return Err(CphError::UnexpectedMessage(format!("{:?}", m))),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
enum CphError {
|
||||
#[error("Could not process a `log` request")]
|
||||
LogError(#[from] LogError),
|
||||
#[error("Could not process a `create_seat` request")]
|
||||
CreateSeatError(#[from] CreateSeatError),
|
||||
#[error("Could not process a `parse_keymap` request")]
|
||||
ParseKeymapError(#[from] ParseKeymapError),
|
||||
#[error("Could not process a `set_seat` request")]
|
||||
SetSeatError(#[from] SetSeatError),
|
||||
#[error("Could not process a `add_shortcut` request")]
|
||||
AddShortcutError(#[from] AddShortcutError),
|
||||
#[error("Could not process a `get_input_devices` request")]
|
||||
GetInputDevicesError(#[from] GetInputDevicesError),
|
||||
#[error("Could not process a `get_seats` request")]
|
||||
GetSeatsError(#[from] GetSeatsError),
|
||||
#[error("Could not process a `set_keymap` request")]
|
||||
SeatSetKeymapError(#[from] SeatSetKeymapError),
|
||||
#[error("Could not process a `get_repeat_rate` request")]
|
||||
SeatGetRepeatRateError(#[from] SeatGetRepeatRateError),
|
||||
#[error("Could not process a `set_repeat_rate` request")]
|
||||
SeatSetRepeatRateError(#[from] SeatSetRepeatRateError),
|
||||
#[error("Could not process a `focus` request")]
|
||||
FocusError(#[from] FocusError),
|
||||
#[error("Device {0:?} does not exist")]
|
||||
DeviceDoesNotExist(InputDevice),
|
||||
#[error("Device {0:?} does not exist")]
|
||||
KeymapDoesNotExist(Keymap),
|
||||
#[error("Seat {0:?} does not exist")]
|
||||
SeatDoesNotExist(Seat),
|
||||
#[error("Seat {0:?} does not exist")]
|
||||
UnexpectedMessage(String),
|
||||
#[error("Could not parse the message")]
|
||||
ParsingFailed(#[source] DecodeError),
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
enum LogError {
|
||||
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
enum CreateSeatError {
|
||||
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
enum ParseKeymapError {
|
||||
#[error("Parsing failed")]
|
||||
ParsingFailed,
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
enum SetSeatError {
|
||||
#[error(transparent)]
|
||||
CphError(#[from] Box<CphError>),
|
||||
}
|
||||
efrom!(SetSeatError, CphError);
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
enum AddShortcutError {
|
||||
#[error(transparent)]
|
||||
CphError(#[from] Box<CphError>),
|
||||
}
|
||||
efrom!(AddShortcutError, CphError);
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
enum GetInputDevicesError {
|
||||
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
enum GetSeatsError {
|
||||
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
enum SeatSetKeymapError {
|
||||
#[error(transparent)]
|
||||
CphError(#[from] Box<CphError>),
|
||||
}
|
||||
efrom!(SeatSetKeymapError, CphError);
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
enum SeatSetRepeatRateError {
|
||||
#[error(transparent)]
|
||||
CphError(#[from] Box<CphError>),
|
||||
#[error("Rate is negative")]
|
||||
NegativeRate,
|
||||
#[error("Delay is negative")]
|
||||
NegativeDelay,
|
||||
}
|
||||
efrom!(SeatSetRepeatRateError, CphError);
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
enum SeatGetRepeatRateError {
|
||||
#[error(transparent)]
|
||||
CphError(#[from] Box<CphError>),
|
||||
}
|
||||
efrom!(SeatGetRepeatRateError, CphError);
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
enum FocusError {
|
||||
#[error(transparent)]
|
||||
CphError(#[from] Box<CphError>),
|
||||
}
|
||||
efrom!(FocusError, CphError);
|
||||
|
|
@ -4,7 +4,6 @@ pub mod wl_keyboard;
|
|||
pub mod wl_pointer;
|
||||
pub mod wl_touch;
|
||||
|
||||
use crate::backend::{Seat, SeatId};
|
||||
use crate::client::{Client, ClientError, ClientId};
|
||||
use crate::cursor::{Cursor, KnownCursor};
|
||||
use crate::fixed::Fixed;
|
||||
|
|
@ -29,24 +28,25 @@ use crate::utils::buffd::MsgParser;
|
|||
use crate::utils::buffd::MsgParserError;
|
||||
use crate::utils::clonecell::CloneCell;
|
||||
use crate::utils::copyhashmap::CopyHashMap;
|
||||
use crate::utils::linkedlist::LinkedList;
|
||||
use crate::utils::linkedlist::{LinkedList, LinkedNode};
|
||||
use crate::wire::wl_seat::*;
|
||||
use crate::wire::{
|
||||
WlDataDeviceId, WlKeyboardId, WlPointerId, WlSeatId, ZwpPrimarySelectionDeviceV1Id,
|
||||
};
|
||||
use crate::xkbcommon::{XkbContext, XkbState};
|
||||
use crate::{NumCell, State};
|
||||
use crate::xkbcommon::{XkbKeymap, XkbState};
|
||||
use crate::{ErrorFmt, NumCell, State};
|
||||
use ahash::{AHashMap, AHashSet};
|
||||
use bstr::ByteSlice;
|
||||
pub use event_handling::NodeSeatState;
|
||||
use i4config::keyboard::mods::Modifiers;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::io::Write;
|
||||
use std::mem;
|
||||
use std::ops::DerefMut;
|
||||
use std::rc::Rc;
|
||||
use thiserror::Error;
|
||||
use uapi::{c, OwnedFd};
|
||||
use uapi::{c, Errno, OwnedFd};
|
||||
use i4config::Direction;
|
||||
use crate::async_engine::SpawnedFuture;
|
||||
|
||||
const POINTER: u32 = 1;
|
||||
const KEYBOARD: u32 = 2;
|
||||
|
|
@ -79,11 +79,13 @@ impl Drop for DroppedDnd {
|
|||
}
|
||||
}
|
||||
|
||||
linear_ids!(SeatIds, SeatId);
|
||||
|
||||
pub struct WlSeatGlobal {
|
||||
id: SeatId,
|
||||
name: GlobalName,
|
||||
state: Rc<State>,
|
||||
seat: Rc<dyn Seat>,
|
||||
seat_name: Rc<String>,
|
||||
seat_name: String,
|
||||
move_: Cell<bool>,
|
||||
move_start_pos: Cell<(Fixed, Fixed)>,
|
||||
extents_start_pos: Cell<(i32, i32)>,
|
||||
|
|
@ -101,9 +103,9 @@ pub struct WlSeatGlobal {
|
|||
AHashMap<ZwpPrimarySelectionDeviceV1Id, Rc<ZwpPrimarySelectionDeviceV1>>,
|
||||
>,
|
||||
>,
|
||||
repeat_rate: Cell<(i32, i32)>,
|
||||
kb_map: CloneCell<Rc<XkbKeymap>>,
|
||||
kb_state: RefCell<XkbState>,
|
||||
layout: Rc<OwnedFd>,
|
||||
layout_size: u32,
|
||||
cursor: CloneCell<Option<Rc<dyn Cursor>>>,
|
||||
serial: NumCell<u32>,
|
||||
tree_changed: Rc<AsyncEvent>,
|
||||
|
|
@ -111,37 +113,22 @@ pub struct WlSeatGlobal {
|
|||
primary_selection: CloneCell<Option<Rc<ZwpPrimarySelectionSourceV1>>>,
|
||||
pointer_owner: PointerOwnerHolder,
|
||||
dropped_dnd: RefCell<Option<DroppedDnd>>,
|
||||
shortcuts: CopyHashMap<(u32, u32), Modifiers>,
|
||||
queue_link: Cell<Option<LinkedNode<Rc<Self>>>>,
|
||||
tree_changed_handler: Cell<Option<SpawnedFuture<()>>>,
|
||||
}
|
||||
|
||||
impl WlSeatGlobal {
|
||||
pub fn new(
|
||||
name: GlobalName,
|
||||
seat_name: &str,
|
||||
state: &Rc<State>,
|
||||
seat: &Rc<dyn Seat>,
|
||||
tree_changed: &Rc<AsyncEvent>,
|
||||
) -> Self {
|
||||
let (kb_state, layout, layout_size) = {
|
||||
let ctx = XkbContext::new().unwrap();
|
||||
let keymap = ctx.default_keymap().unwrap();
|
||||
let state = keymap.state().unwrap();
|
||||
let string = keymap.as_str().unwrap();
|
||||
let mut memfd =
|
||||
uapi::memfd_create("keymap", c::MFD_CLOEXEC | c::MFD_ALLOW_SEALING).unwrap();
|
||||
memfd.write_all(string.as_bytes()).unwrap();
|
||||
memfd.write_all(&[0]).unwrap();
|
||||
uapi::lseek(memfd.raw(), 0, c::SEEK_SET).unwrap();
|
||||
uapi::fcntl_add_seals(
|
||||
memfd.raw(),
|
||||
c::F_SEAL_SEAL | c::F_SEAL_GROW | c::F_SEAL_SHRINK | c::F_SEAL_WRITE,
|
||||
)
|
||||
.unwrap();
|
||||
(state, Rc::new(memfd), (string.len() + 1) as _)
|
||||
};
|
||||
Self {
|
||||
) -> Rc<Self> {
|
||||
let slf = Rc::new(Self {
|
||||
id: state.seat_ids.next(),
|
||||
name,
|
||||
state: state.clone(),
|
||||
seat: seat.clone(),
|
||||
seat_name: Rc::new(format!("seat-{}", seat.id())),
|
||||
seat_name: seat_name.to_string(),
|
||||
move_: Cell::new(false),
|
||||
move_start_pos: Cell::new((Fixed(0), Fixed(0))),
|
||||
extents_start_pos: Cell::new((0, 0)),
|
||||
|
|
@ -154,19 +141,79 @@ impl WlSeatGlobal {
|
|||
bindings: Default::default(),
|
||||
data_devices: RefCell::new(Default::default()),
|
||||
primary_selection_devices: RefCell::new(Default::default()),
|
||||
kb_state: RefCell::new(kb_state),
|
||||
layout,
|
||||
layout_size,
|
||||
repeat_rate: Cell::new((25, 250)),
|
||||
kb_map: CloneCell::new(state.default_keymap.clone()),
|
||||
kb_state: RefCell::new(state.default_keymap.state().unwrap()),
|
||||
cursor: Default::default(),
|
||||
serial: Default::default(),
|
||||
tree_changed: tree_changed.clone(),
|
||||
tree_changed: Default::default(),
|
||||
selection: Default::default(),
|
||||
primary_selection: Default::default(),
|
||||
pointer_owner: Default::default(),
|
||||
dropped_dnd: RefCell::new(None),
|
||||
shortcuts: Default::default(),
|
||||
queue_link: Cell::new(None),
|
||||
tree_changed_handler: Cell::new(None),
|
||||
});
|
||||
let seat = slf.clone();
|
||||
state.eng.spawn(async move {
|
||||
loop {
|
||||
seat.tree_changed.triggered().await;
|
||||
seat.state.tree_changed_sent.set(false);
|
||||
seat.tree_changed();
|
||||
}
|
||||
});
|
||||
slf
|
||||
}
|
||||
|
||||
pub fn mark_last_active(self: &Rc<Self>) {
|
||||
self.queue_link.set(Some(self.state.seat_queue.add_last(self.clone())));
|
||||
}
|
||||
|
||||
pub fn set_keymap(&self, keymap: &Rc<XkbKeymap>) {
|
||||
self.kb_map.set(keymap.clone());
|
||||
let bindings = self.bindings.borrow_mut();
|
||||
for (id, client) in bindings.iter() {
|
||||
for seat in client.values() {
|
||||
let kbs = seat.keyboards.lock();
|
||||
for kb in kbs.values() {
|
||||
let fd = match seat.keymap_fd(&keymap) {
|
||||
Ok(fd) => fd,
|
||||
Err(e) => {
|
||||
log::error!("Could not creat a file descriptor to transfer the keymap to client {}: {}", id, ErrorFmt(e));
|
||||
continue;
|
||||
}
|
||||
};
|
||||
kb.send_keymap(wl_keyboard::XKB_V1, fd, keymap.map_len as _);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_rate(&self) -> (i32, i32) {
|
||||
self.repeat_rate.get()
|
||||
}
|
||||
|
||||
pub fn set_rate(&self, rate: i32, delay: i32) {
|
||||
self.repeat_rate.set((rate, delay));
|
||||
let bindings = self.bindings.borrow_mut();
|
||||
for client in bindings.values() {
|
||||
for seat in client.values() {
|
||||
if seat.version >= REPEAT_INFO_SINCE {
|
||||
let kbs = seat.keyboards.lock();
|
||||
for kb in kbs.values() {
|
||||
kb.send_repeat_info(rate, delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn move_focus(self: &Rc<Self>, direction: Direction) {
|
||||
let kb_node = self.keyboard_node.get();
|
||||
kb_node.move_focus(self, direction);
|
||||
}
|
||||
|
||||
fn set_selection_<T: ipc::Vtable>(
|
||||
self: &Rc<Self>,
|
||||
field: &CloneCell<Option<Rc<T::Source>>>,
|
||||
|
|
@ -275,7 +322,7 @@ impl WlSeatGlobal {
|
|||
}
|
||||
|
||||
pub fn id(&self) -> SeatId {
|
||||
self.seat.id()
|
||||
self.id
|
||||
}
|
||||
|
||||
fn bind_(
|
||||
|
|
@ -321,6 +368,8 @@ impl Global for WlSeatGlobal {
|
|||
|
||||
fn break_loops(&self) {
|
||||
self.bindings.borrow_mut().clear();
|
||||
self.queue_link.take();
|
||||
self.tree_changed_handler.take();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -336,6 +385,8 @@ pub struct WlSeat {
|
|||
tracker: Tracker<Self>,
|
||||
}
|
||||
|
||||
const READ_ONLY_KEYMAP_SINCE: u32 = 7;
|
||||
|
||||
impl WlSeat {
|
||||
fn send_capabilities(self: &Rc<Self>) {
|
||||
self.client.event(Capabilities {
|
||||
|
|
@ -404,13 +455,41 @@ impl WlSeat {
|
|||
track!(self.client, p);
|
||||
self.client.add_client_obj(&p)?;
|
||||
self.keyboards.set(req.id, p.clone());
|
||||
p.send_keymap(wl_keyboard::XKB_V1, p.keymap_fd()?, self.global.layout_size);
|
||||
let keymap = self.global.kb_map.get();
|
||||
p.send_keymap(wl_keyboard::XKB_V1, self.keymap_fd(&keymap)?, keymap.map_len as _);
|
||||
if self.version >= REPEAT_INFO_SINCE {
|
||||
p.send_repeat_info(25, 250);
|
||||
let (rate, delay) = self.global.repeat_rate.get();
|
||||
p.send_repeat_info(rate, delay);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn keymap_fd(&self, keymap: &XkbKeymap) -> Result<Rc<OwnedFd>, WlKeyboardError> {
|
||||
if self.version >= READ_ONLY_KEYMAP_SINCE {
|
||||
return Ok(keymap.map.clone());
|
||||
}
|
||||
let fd = match uapi::memfd_create("shared-keymap", c::MFD_CLOEXEC) {
|
||||
Ok(fd) => fd,
|
||||
Err(e) => return Err(WlKeyboardError::KeymapMemfd(e.into())),
|
||||
};
|
||||
let target = keymap.map_len as c::off_t;
|
||||
let mut pos = 0;
|
||||
while pos < target {
|
||||
let rem = target - pos;
|
||||
let res = uapi::sendfile(
|
||||
fd.raw(),
|
||||
keymap.map.raw(),
|
||||
Some(&mut pos),
|
||||
rem as usize,
|
||||
);
|
||||
match res {
|
||||
Ok(_) | Err(Errno(c::EINTR)) => {}
|
||||
Err(e) => return Err(WlKeyboardError::KeymapCopy(e.into())),
|
||||
}
|
||||
}
|
||||
Ok(Rc::new(fd))
|
||||
}
|
||||
|
||||
fn get_touch(self: &Rc<Self>, parser: MsgParser<'_, '_>) -> Result<(), GetTouchError> {
|
||||
let req: GetTouch = self.client.parse(&**self, parser)?;
|
||||
let p = Rc::new(WlTouch::new(req.id, self));
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::backend::{KeyState, OutputId, ScrollAxis, SeatEvent, SeatId};
|
||||
use crate::backend::{KeyboardEvent, KeyState, MouseEvent, OutputId, ScrollAxis};
|
||||
use crate::client::{Client, ClientId};
|
||||
use crate::fixed::Fixed;
|
||||
use crate::ifs::ipc;
|
||||
|
|
@ -6,7 +6,7 @@ use crate::ifs::ipc::wl_data_device::WlDataDevice;
|
|||
use crate::ifs::ipc::zwp_primary_selection_device_v1::ZwpPrimarySelectionDeviceV1;
|
||||
use crate::ifs::wl_seat::wl_keyboard::WlKeyboard;
|
||||
use crate::ifs::wl_seat::wl_pointer::{WlPointer, POINTER_FRAME_SINCE_VERSION};
|
||||
use crate::ifs::wl_seat::{wl_keyboard, wl_pointer, Dnd, WlSeat, WlSeatGlobal};
|
||||
use crate::ifs::wl_seat::{wl_keyboard, wl_pointer, Dnd, WlSeat, WlSeatGlobal, SeatId};
|
||||
use crate::ifs::wl_surface::xdg_surface::xdg_popup::XdgPopup;
|
||||
use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevel;
|
||||
use crate::ifs::wl_surface::xdg_surface::XdgSurface;
|
||||
|
|
@ -17,6 +17,10 @@ use crate::utils::clonecell::CloneCell;
|
|||
use crate::utils::smallmap::SmallMap;
|
||||
use crate::wire::WlDataOfferId;
|
||||
use crate::xkbcommon::{ModifierState, XKB_KEY_DOWN, XKB_KEY_UP};
|
||||
use i4config::keyboard::mods::Modifiers;
|
||||
use i4config::keyboard::syms::KeySym;
|
||||
use i4config::keyboard::ModifiedKeySym;
|
||||
use smallvec::SmallVec;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
|
@ -30,37 +34,37 @@ pub struct NodeSeatState {
|
|||
|
||||
impl NodeSeatState {
|
||||
pub(super) fn enter(&self, seat: &Rc<WlSeatGlobal>) {
|
||||
self.pointer_foci.insert(seat.seat.id(), seat.clone());
|
||||
self.pointer_foci.insert(seat.id, seat.clone());
|
||||
}
|
||||
|
||||
pub(super) fn leave(&self, seat: &WlSeatGlobal) {
|
||||
self.pointer_foci.remove(&seat.seat.id());
|
||||
self.pointer_foci.remove(&seat.id);
|
||||
}
|
||||
|
||||
pub(super) fn focus(&self, seat: &Rc<WlSeatGlobal>) -> bool {
|
||||
self.kb_foci.insert(seat.seat.id(), seat.clone());
|
||||
self.kb_foci.insert(seat.id, seat.clone());
|
||||
self.kb_foci.len() == 1
|
||||
}
|
||||
|
||||
pub(super) fn unfocus(&self, seat: &WlSeatGlobal) -> bool {
|
||||
self.kb_foci.remove(&seat.seat.id());
|
||||
self.kb_foci.remove(&seat.id);
|
||||
self.kb_foci.len() == 0
|
||||
}
|
||||
|
||||
pub(super) fn add_pointer_grab(&self, seat: &Rc<WlSeatGlobal>) {
|
||||
self.grabs.insert(seat.id(), seat.clone());
|
||||
self.grabs.insert(seat.id, seat.clone());
|
||||
}
|
||||
|
||||
pub(super) fn remove_pointer_grab(&self, seat: &WlSeatGlobal) {
|
||||
self.grabs.remove(&seat.id());
|
||||
self.grabs.remove(&seat.id);
|
||||
}
|
||||
|
||||
pub(super) fn add_dnd_target(&self, seat: &Rc<WlSeatGlobal>) {
|
||||
self.dnd_targets.insert(seat.id(), seat.clone());
|
||||
self.dnd_targets.insert(seat.id, seat.clone());
|
||||
}
|
||||
|
||||
pub(super) fn remove_dnd_target(&self, seat: &WlSeatGlobal) {
|
||||
self.dnd_targets.remove(&seat.id());
|
||||
self.dnd_targets.remove(&seat.id);
|
||||
}
|
||||
|
||||
// pub fn remove_pointer_grabs(&self) {
|
||||
|
|
@ -100,13 +104,18 @@ impl NodeSeatState {
|
|||
}
|
||||
|
||||
impl WlSeatGlobal {
|
||||
pub fn event(self: &Rc<Self>, event: SeatEvent) {
|
||||
pub fn kb_event(self: &Rc<Self>, event: KeyboardEvent) {
|
||||
match event {
|
||||
SeatEvent::OutputPosition(o, x, y) => self.output_position_event(o, x, y),
|
||||
SeatEvent::Motion(dx, dy) => self.motion_event(dx, dy),
|
||||
SeatEvent::Button(b, s) => self.pointer_owner.button(self, b, s),
|
||||
SeatEvent::Scroll(d, a) => self.pointer_owner.scroll(self, d, a),
|
||||
SeatEvent::Key(k, s) => self.key_event(k, s),
|
||||
KeyboardEvent::Key(k, s) => self.key_event(k, s),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mouse_event(self: &Rc<Self>, event: MouseEvent) {
|
||||
match event {
|
||||
MouseEvent::OutputPosition(o, x, y) => self.output_position_event(o, x, y),
|
||||
MouseEvent::Motion(dx, dy) => self.motion_event(dx, dy),
|
||||
MouseEvent::Button(b, s) => self.pointer_owner.button(self, b, s),
|
||||
MouseEvent::Scroll(d, a) => self.pointer_owner.scroll(self, d, a),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -143,9 +152,35 @@ impl WlSeatGlobal {
|
|||
}
|
||||
}
|
||||
};
|
||||
let mods = self.kb_state.borrow_mut().update(key, xkb_dir);
|
||||
let mut shortcuts = SmallVec::<[_; 1]>::new();
|
||||
let new_mods;
|
||||
{
|
||||
let mut kb_state = self.kb_state.borrow_mut();
|
||||
if state == wl_keyboard::PRESSED {
|
||||
let old_mods = kb_state.mods();
|
||||
let keysyms = kb_state.unmodified_keysyms(key);
|
||||
for &sym in keysyms {
|
||||
if let Some(mods) = self.shortcuts.get(&(old_mods.mods_effective, sym)) {
|
||||
shortcuts.push(ModifiedKeySym {
|
||||
mods,
|
||||
sym: KeySym(sym),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
new_mods = kb_state.update(key, xkb_dir);
|
||||
}
|
||||
let node = self.keyboard_node.get();
|
||||
node.key(self, key, state, mods);
|
||||
if shortcuts.is_empty() {
|
||||
node.key(self, key, state);
|
||||
} else if let Some(config) = self.state.config.get() {
|
||||
for shortcut in shortcuts {
|
||||
config.invoke_shortcut(self.id(), &shortcut);
|
||||
}
|
||||
}
|
||||
if let Some(mods) = new_mods {
|
||||
node.mods(self, mods);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -206,6 +241,7 @@ impl WlSeatGlobal {
|
|||
mods_latched,
|
||||
mods_locked,
|
||||
group,
|
||||
..
|
||||
} = self.kb_state.borrow().mods();
|
||||
let serial = self.serial.fetch_add(1);
|
||||
self.surface_kb_event(0, &surface, |k| {
|
||||
|
|
@ -331,7 +367,15 @@ impl WlSeatGlobal {
|
|||
self.handle_new_position(true);
|
||||
}
|
||||
|
||||
pub fn tree_changed(self: &Rc<Self>) {
|
||||
pub fn add_shortcut(&self, mods: Modifiers, keysym: KeySym) {
|
||||
self.shortcuts.set((mods.0, keysym.0), mods);
|
||||
}
|
||||
|
||||
pub fn trigger_tree_changed(&self) {
|
||||
self.tree_changed.trigger();
|
||||
}
|
||||
|
||||
pub(super) fn tree_changed(self: &Rc<Self>) {
|
||||
self.handle_new_position(false);
|
||||
}
|
||||
|
||||
|
|
@ -417,27 +461,25 @@ impl WlSeatGlobal {
|
|||
|
||||
// Key callbacks
|
||||
impl WlSeatGlobal {
|
||||
pub fn key_surface(
|
||||
&self,
|
||||
surface: &WlSurface,
|
||||
key: u32,
|
||||
state: u32,
|
||||
mods: Option<ModifierState>,
|
||||
) {
|
||||
pub fn key_surface(&self, surface: &WlSurface, key: u32, state: u32) {
|
||||
let serial = self.serial.fetch_add(1);
|
||||
self.surface_kb_event(0, surface, |k| k.send_key(serial, 0, key, state));
|
||||
}
|
||||
}
|
||||
|
||||
// Modifiers callbacks
|
||||
impl WlSeatGlobal {
|
||||
pub fn mods_surface(&self, surface: &WlSurface, mods: ModifierState) {
|
||||
let serial = self.serial.fetch_add(1);
|
||||
if let Some(mods) = mods {
|
||||
self.surface_kb_event(0, surface, |k| {
|
||||
k.send_modifiers(
|
||||
serial,
|
||||
mods.mods_depressed,
|
||||
mods.mods_latched,
|
||||
mods.mods_locked,
|
||||
mods.group,
|
||||
)
|
||||
});
|
||||
}
|
||||
self.surface_kb_event(0, surface, |k| {
|
||||
k.send_modifiers(
|
||||
serial,
|
||||
mods.mods_depressed,
|
||||
mods.mods_latched,
|
||||
mods.mods_locked,
|
||||
mods.group,
|
||||
)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use crate::wire::wl_keyboard::*;
|
|||
use crate::wire::{WlKeyboardId, WlSurfaceId};
|
||||
use std::rc::Rc;
|
||||
use thiserror::Error;
|
||||
use uapi::{c, Errno, OwnedFd};
|
||||
use uapi::{OwnedFd};
|
||||
|
||||
pub const REPEAT_INFO_SINCE: u32 = 4;
|
||||
|
||||
|
|
@ -34,36 +34,6 @@ impl WlKeyboard {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn needs_dedicated_keymap_fd(&self) -> bool {
|
||||
self.seat.version < 7
|
||||
}
|
||||
|
||||
pub fn keymap_fd(&self) -> Result<Rc<OwnedFd>, WlKeyboardError> {
|
||||
if !self.needs_dedicated_keymap_fd() {
|
||||
return Ok(self.seat.global.layout.clone());
|
||||
}
|
||||
let fd = match uapi::memfd_create("shared-keymap", c::MFD_CLOEXEC) {
|
||||
Ok(fd) => fd,
|
||||
Err(e) => return Err(WlKeyboardError::KeymapMemfd(e.into())),
|
||||
};
|
||||
let target = self.seat.global.layout_size as c::off_t;
|
||||
let mut pos = 0;
|
||||
while pos < target {
|
||||
let rem = target - pos;
|
||||
let res = uapi::sendfile(
|
||||
fd.raw(),
|
||||
self.seat.global.layout.raw(),
|
||||
Some(&mut pos),
|
||||
rem as usize,
|
||||
);
|
||||
match res {
|
||||
Ok(_) | Err(Errno(c::EINTR)) => {}
|
||||
Err(e) => return Err(WlKeyboardError::KeymapCopy(e.into())),
|
||||
}
|
||||
}
|
||||
Ok(Rc::new(fd))
|
||||
}
|
||||
|
||||
pub fn send_keymap(self: &Rc<Self>, format: u32, fd: Rc<OwnedFd>, size: u32) {
|
||||
self.seat.client.event(Keymap {
|
||||
self_id: self.id,
|
||||
|
|
|
|||
|
|
@ -2,12 +2,11 @@ pub mod cursor;
|
|||
pub mod wl_subsurface;
|
||||
pub mod xdg_surface;
|
||||
|
||||
use crate::backend::{KeyState, ScrollAxis, SeatId};
|
||||
use crate::client::{Client, ClientError, RequestParser};
|
||||
use crate::fixed::Fixed;
|
||||
use crate::ifs::wl_buffer::WlBuffer;
|
||||
use crate::ifs::wl_callback::WlCallback;
|
||||
use crate::ifs::wl_seat::{Dnd, NodeSeatState, WlSeatGlobal};
|
||||
use crate::ifs::wl_seat::{Dnd, NodeSeatState, SeatId, WlSeatGlobal};
|
||||
use crate::ifs::wl_surface::cursor::CursorSurface;
|
||||
use crate::ifs::wl_surface::wl_subsurface::WlSubsurface;
|
||||
use crate::ifs::wl_surface::xdg_surface::{XdgSurface, XdgSurfaceError, XdgSurfaceRole};
|
||||
|
|
@ -32,6 +31,8 @@ use std::mem;
|
|||
use std::ops::{Deref, DerefMut};
|
||||
use std::rc::Rc;
|
||||
use thiserror::Error;
|
||||
use i4config::Direction;
|
||||
use crate::backend::{KeyState, ScrollAxis};
|
||||
|
||||
#[allow(dead_code)]
|
||||
const INVALID_SCALE: u32 = 0;
|
||||
|
|
@ -609,6 +610,14 @@ impl Node for WlSurface {
|
|||
self.seat_state.destroy_node(self);
|
||||
}
|
||||
|
||||
fn move_focus(&self, seat: &Rc<WlSeatGlobal>, direction: Direction) {
|
||||
let xdg = match self.xdg.get() {
|
||||
Some(x) => x,
|
||||
_ => return,
|
||||
};
|
||||
xdg.move_focus(seat, direction);
|
||||
}
|
||||
|
||||
fn absolute_position(&self) -> Rect {
|
||||
self.buffer_abs_pos.get()
|
||||
}
|
||||
|
|
@ -619,8 +628,12 @@ impl Node for WlSurface {
|
|||
}
|
||||
}
|
||||
|
||||
fn key(&self, seat: &WlSeatGlobal, key: u32, state: u32, mods: Option<ModifierState>) {
|
||||
seat.key_surface(self, key, state, mods);
|
||||
fn key(&self, seat: &WlSeatGlobal, key: u32, state: u32) {
|
||||
seat.key_surface(self, key, state);
|
||||
}
|
||||
|
||||
fn mods(&self, seat: &WlSeatGlobal, mods: ModifierState) {
|
||||
seat.mods_surface(self, mods);
|
||||
}
|
||||
|
||||
fn button(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, button: u32, state: KeyState) {
|
||||
|
|
@ -665,10 +678,6 @@ impl Node for WlSurface {
|
|||
Some(self)
|
||||
}
|
||||
|
||||
fn dnd_enter(&self, dnd: &Dnd, x: Fixed, y: Fixed) {
|
||||
dnd.seat.dnd_surface_enter(self, dnd, x, y);
|
||||
}
|
||||
|
||||
fn dnd_drop(&self, dnd: &Dnd) {
|
||||
dnd.seat.dnd_surface_drop(self, dnd);
|
||||
}
|
||||
|
|
@ -677,6 +686,10 @@ impl Node for WlSurface {
|
|||
dnd.seat.dnd_surface_leave(self, dnd);
|
||||
}
|
||||
|
||||
fn dnd_enter(&self, dnd: &Dnd, x: Fixed, y: Fixed) {
|
||||
dnd.seat.dnd_surface_enter(self, dnd, x, y);
|
||||
}
|
||||
|
||||
fn dnd_motion(&self, dnd: &Dnd, x: Fixed, y: Fixed) {
|
||||
dnd.seat.dnd_surface_motion(self, dnd, x, y);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
pub mod xdg_popup;
|
||||
pub mod xdg_toplevel;
|
||||
|
||||
use crate::backend::SeatId;
|
||||
use crate::client::ClientError;
|
||||
use crate::ifs::wl_seat::{NodeSeatState, WlSeatGlobal};
|
||||
use crate::ifs::wl_seat::{NodeSeatState, SeatId, WlSeatGlobal};
|
||||
use crate::ifs::wl_surface::xdg_surface::xdg_popup::{XdgPopup, XdgPopupError};
|
||||
use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevel;
|
||||
use crate::ifs::wl_surface::{
|
||||
|
|
@ -26,6 +25,7 @@ use std::cell::Cell;
|
|||
use std::fmt::Debug;
|
||||
use std::rc::Rc;
|
||||
use thiserror::Error;
|
||||
use i4config::Direction;
|
||||
|
||||
#[allow(dead_code)]
|
||||
const NOT_CONSTRUCTED: u32 = 1;
|
||||
|
|
@ -75,6 +75,11 @@ struct PendingXdgSurfaceData {
|
|||
}
|
||||
|
||||
pub trait XdgSurfaceExt: Debug {
|
||||
fn move_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, direction: Direction) {
|
||||
let _ = seat;
|
||||
let _ = direction;
|
||||
}
|
||||
|
||||
fn initial_configure(self: Rc<Self>) -> Result<(), XdgSurfaceError> {
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -137,6 +142,14 @@ impl XdgSurface {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn move_focus(&self, seat: &Rc<WlSeatGlobal>, direction: Direction) {
|
||||
let ext = match self.ext.get() {
|
||||
None => return,
|
||||
Some(e) => e,
|
||||
};
|
||||
ext.move_focus(seat, direction);
|
||||
}
|
||||
|
||||
pub fn role(&self) -> XdgSurfaceRole {
|
||||
self.role.get()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
use crate::backend::SeatId;
|
||||
use crate::bugs::Bugs;
|
||||
use crate::client::{Client, ClientError};
|
||||
use crate::cursor::KnownCursor;
|
||||
use crate::fixed::Fixed;
|
||||
use crate::ifs::wl_seat::{NodeSeatState, WlSeatGlobal};
|
||||
use crate::ifs::wl_seat::{NodeSeatState, SeatId, WlSeatGlobal};
|
||||
use crate::ifs::wl_surface::xdg_surface::{XdgSurface, XdgSurfaceError, XdgSurfaceExt};
|
||||
use crate::leaks::Tracker;
|
||||
use crate::object::Object;
|
||||
|
|
@ -27,6 +26,7 @@ use std::mem;
|
|||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
use thiserror::Error;
|
||||
use i4config::Direction;
|
||||
|
||||
#[derive(Copy, Clone, Debug, FromPrimitive)]
|
||||
pub enum ResizeEdge {
|
||||
|
|
@ -438,6 +438,10 @@ impl Node for XdgToplevel {
|
|||
self.xdg.seat_state.destroy_node(self)
|
||||
}
|
||||
|
||||
fn do_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, _direction: Direction) {
|
||||
seat.focus_toplevel(&self);
|
||||
}
|
||||
|
||||
fn absolute_position(&self) -> Rect {
|
||||
self.xdg.absolute_desired_extents.get()
|
||||
}
|
||||
|
|
@ -480,6 +484,14 @@ impl Node for XdgToplevel {
|
|||
}
|
||||
|
||||
impl XdgSurfaceExt for XdgToplevel {
|
||||
fn move_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, direction: Direction) {
|
||||
let pn = match self.parent_node.get() {
|
||||
Some(pn) => pn,
|
||||
_ => return,
|
||||
};
|
||||
pn.move_focus_from_child(seat, &*self, direction);
|
||||
}
|
||||
|
||||
fn initial_configure(self: Rc<Self>) -> Result<(), XdgSurfaceError> {
|
||||
self.send_configure(0, 0);
|
||||
Ok(())
|
||||
|
|
|
|||
485
src/keycodes.xkb
Normal file
485
src/keycodes.xkb
Normal file
|
|
@ -0,0 +1,485 @@
|
|||
<1> = 9; # ESC
|
||||
<2> = 10; # 1
|
||||
<3> = 11; # 2
|
||||
<4> = 12; # 3
|
||||
<5> = 13; # 4
|
||||
<6> = 14; # 5
|
||||
<7> = 15; # 6
|
||||
<8> = 16; # 7
|
||||
<9> = 17; # 8
|
||||
<10> = 18; # 9
|
||||
<11> = 19; # 0
|
||||
<12> = 20; # MINUS
|
||||
<13> = 21; # EQUAL
|
||||
<14> = 22; # BACKSPACE
|
||||
<15> = 23; # TAB
|
||||
<16> = 24; # Q
|
||||
<17> = 25; # W
|
||||
<18> = 26; # E
|
||||
<19> = 27; # R
|
||||
<20> = 28; # T
|
||||
<21> = 29; # Y
|
||||
<22> = 30; # U
|
||||
<23> = 31; # I
|
||||
<24> = 32; # O
|
||||
<25> = 33; # P
|
||||
<26> = 34; # LEFTBRACE
|
||||
<27> = 35; # RIGHTBRACE
|
||||
<28> = 36; # ENTER
|
||||
<29> = 37; # LEFTCTRL
|
||||
<30> = 38; # A
|
||||
<31> = 39; # S
|
||||
<32> = 40; # D
|
||||
<33> = 41; # F
|
||||
<34> = 42; # G
|
||||
<35> = 43; # H
|
||||
<36> = 44; # J
|
||||
<37> = 45; # K
|
||||
<38> = 46; # L
|
||||
<39> = 47; # SEMICOLON
|
||||
<40> = 48; # APOSTROPHE
|
||||
<41> = 49; # GRAVE
|
||||
<42> = 50; # LEFTSHIFT
|
||||
<43> = 51; # BACKSLASH
|
||||
<44> = 52; # Z
|
||||
<45> = 53; # X
|
||||
<46> = 54; # C
|
||||
<47> = 55; # V
|
||||
<48> = 56; # B
|
||||
<49> = 57; # N
|
||||
<50> = 58; # M
|
||||
<51> = 59; # COMMA
|
||||
<52> = 60; # DOT
|
||||
<53> = 61; # SLASH
|
||||
<54> = 62; # RIGHTSHIFT
|
||||
<55> = 63; # KPASTERISK
|
||||
<56> = 64; # LEFTALT
|
||||
<57> = 65; # SPACE
|
||||
<58> = 66; # CAPSLOCK
|
||||
<59> = 67; # F1
|
||||
<60> = 68; # F2
|
||||
<61> = 69; # F3
|
||||
<62> = 70; # F4
|
||||
<63> = 71; # F5
|
||||
<64> = 72; # F6
|
||||
<65> = 73; # F7
|
||||
<66> = 74; # F8
|
||||
<67> = 75; # F9
|
||||
<68> = 76; # F10
|
||||
<69> = 77; # NUMLOCK
|
||||
<70> = 78; # SCROLLLOCK
|
||||
<71> = 79; # KP7
|
||||
<72> = 80; # KP8
|
||||
<73> = 81; # KP9
|
||||
<74> = 82; # KPMINUS
|
||||
<75> = 83; # KP4
|
||||
<76> = 84; # KP5
|
||||
<77> = 85; # KP6
|
||||
<78> = 86; # KPPLUS
|
||||
<79> = 87; # KP1
|
||||
<80> = 88; # KP2
|
||||
<81> = 89; # KP3
|
||||
<82> = 90; # KP0
|
||||
<83> = 91; # KPDOT
|
||||
<85> = 93; # ZENKAKUHANKAKU
|
||||
<86> = 94; # 102ND
|
||||
<87> = 95; # F11
|
||||
<88> = 96; # F12
|
||||
<89> = 97; # RO
|
||||
<90> = 98; # KATAKANA
|
||||
<91> = 99; # HIRAGANA
|
||||
<92> = 100; # HENKAN
|
||||
<93> = 101; # KATAKANAHIRAGANA
|
||||
<94> = 102; # MUHENKAN
|
||||
<95> = 103; # KPJPCOMMA
|
||||
<96> = 104; # KPENTER
|
||||
<97> = 105; # RIGHTCTRL
|
||||
<98> = 106; # KPSLASH
|
||||
<99> = 107; # SYSRQ
|
||||
<100> = 108; # RIGHTALT
|
||||
<101> = 109; # LINEFEED
|
||||
<102> = 110; # HOME
|
||||
<103> = 111; # UP
|
||||
<104> = 112; # PAGEUP
|
||||
<105> = 113; # LEFT
|
||||
<106> = 114; # RIGHT
|
||||
<107> = 115; # END
|
||||
<108> = 116; # DOWN
|
||||
<109> = 117; # PAGEDOWN
|
||||
<110> = 118; # INSERT
|
||||
111> = 119; # DELETE
|
||||
<112> = 120; # MACRO
|
||||
<113> = 121; # MUTE
|
||||
<114> = 122; # VOLUMEDOWN
|
||||
<115> = 123; # VOLUMEUP
|
||||
<116> = 124; # POWER
|
||||
<117> = 125; # KPEQUAL
|
||||
<118> = 126; # KPPLUSMINUS
|
||||
<119> = 127; # PAUSE
|
||||
<120> = 128; # SCALE
|
||||
<121> = 129; # KPCOMMA
|
||||
<122> = 130; # HANGEUL
|
||||
<123> = 131; # HANJA
|
||||
<124> = 132; # YEN
|
||||
<125> = 133; # LEFTMETA
|
||||
<126> = 134; # RIGHTMETA
|
||||
<127> = 135; # COMPOSE
|
||||
<128> = 136; # STOP
|
||||
<129> = 137; # AGAIN
|
||||
<130> = 138; # PROPS
|
||||
<131> = 139; # UNDO
|
||||
<132> = 140; # FRONT
|
||||
<133> = 141; # COPY
|
||||
<134> = 142; # OPEN
|
||||
<135> = 143; # PASTE
|
||||
<136> = 144; # FIND
|
||||
<137> = 145; # CUT
|
||||
<138> = 146; # HELP
|
||||
<139> = 147; # MENU
|
||||
<140> = 148; # CALC
|
||||
<141> = 149; # SETUP
|
||||
<142> = 150; # SLEEP
|
||||
<143> = 151; # WAKEUP
|
||||
<144> = 152; # FILE
|
||||
<145> = 153; # SENDFILE
|
||||
<146> = 154; # DELETEFILE
|
||||
<147> = 155; # XFER
|
||||
<148> = 156; # PROG1
|
||||
<149> = 157; # PROG2
|
||||
<150> = 158; # WWW
|
||||
<151> = 159; # MSDOS
|
||||
<152> = 160; # COFFEE
|
||||
<153> = 161; # ROTATE_DISPLAY
|
||||
<154> = 162; # CYCLEWINDOWS
|
||||
<155> = 163; # MAIL
|
||||
<156> = 164; # BOOKMARKS
|
||||
<157> = 165; # COMPUTER
|
||||
<158> = 166; # BACK
|
||||
<159> = 167; # FORWARD
|
||||
<160> = 168; # CLOSECD
|
||||
<161> = 169; # EJECTCD
|
||||
<162> = 170; # EJECTCLOSECD
|
||||
<163> = 171; # NEXTSONG
|
||||
<164> = 172; # PLAYPAUSE
|
||||
<165> = 173; # PREVIOUSSONG
|
||||
<166> = 174; # STOPCD
|
||||
<167> = 175; # RECORD
|
||||
<168> = 176; # REWIND
|
||||
<169> = 177; # PHONE
|
||||
<170> = 178; # ISO
|
||||
<171> = 179; # CONFIG
|
||||
<172> = 180; # HOMEPAGE
|
||||
<173> = 181; # REFRESH
|
||||
<174> = 182; # EXIT
|
||||
<175> = 183; # MOVE
|
||||
<176> = 184; # EDIT
|
||||
<177> = 185; # SCROLLUP
|
||||
<178> = 186; # SCROLLDOWN
|
||||
<179> = 187; # KPLEFTPAREN
|
||||
<180> = 188; # KPRIGHTPAREN
|
||||
<181> = 189; # NEW
|
||||
<182> = 190; # REDO
|
||||
<183> = 191; # F13
|
||||
<184> = 192; # F14
|
||||
<185> = 193; # F15
|
||||
<186> = 194; # F16
|
||||
<187> = 195; # F17
|
||||
<188> = 196; # F18
|
||||
<189> = 197; # F19
|
||||
<190> = 198; # F20
|
||||
<191> = 199; # F21
|
||||
<192> = 200; # F22
|
||||
<193> = 201; # F23
|
||||
<194> = 202; # F24
|
||||
<200> = 208; # PLAYCD
|
||||
<201> = 209; # PAUSECD
|
||||
<202> = 210; # PROG3
|
||||
<203> = 211; # PROG4
|
||||
<204> = 212; # DASHBOARD
|
||||
<205> = 213; # SUSPEND
|
||||
<206> = 214; # CLOSE
|
||||
<207> = 215; # PLAY
|
||||
<208> = 216; # FASTFORWARD
|
||||
<209> = 217; # BASSBOOST
|
||||
<210> = 218; # PRINT
|
||||
<211> = 219; # HP
|
||||
<212> = 220; # CAMERA
|
||||
<213> = 221; # SOUND
|
||||
<214> = 222; # QUESTION
|
||||
<215> = 223; # EMAIL
|
||||
<216> = 224; # CHAT
|
||||
<217> = 225; # SEARCH
|
||||
<218> = 226; # CONNECT
|
||||
<219> = 227; # FINANCE
|
||||
<220> = 228; # SPORT
|
||||
<221> = 229; # SHOP
|
||||
<222> = 230; # ALTERASE
|
||||
<223> = 231; # CANCEL
|
||||
<224> = 232; # BRIGHTNESSDOWN
|
||||
<225> = 233; # BRIGHTNESSUP
|
||||
<226> = 234; # MEDIA
|
||||
<227> = 235; # SWITCHVIDEOMODE
|
||||
<228> = 236; # KBDILLUMTOGGLE
|
||||
<229> = 237; # KBDILLUMDOWN
|
||||
<230> = 238; # KBDILLUMUP
|
||||
<231> = 239; # SEND
|
||||
<232> = 240; # REPLY
|
||||
<233> = 241; # FORWARDMAIL
|
||||
<234> = 242; # SAVE
|
||||
<235> = 243; # DOCUMENTS
|
||||
<236> = 244; # BATTERY
|
||||
<237> = 245; # BLUETOOTH
|
||||
<238> = 246; # WLAN
|
||||
<239> = 247; # UWB
|
||||
<240> = 248; # UNKNOWN
|
||||
<241> = 249; # VIDEO_NEXT
|
||||
<242> = 250; # VIDEO_PREV
|
||||
<243> = 251; # BRIGHTNESS_CYCLE
|
||||
<244> = 252; # BRIGHTNESS_AUTO
|
||||
<245> = 253; # DISPLAY_OFF
|
||||
<246> = 254; # WWAN
|
||||
<247> = 255; # RFKILL
|
||||
<248> = 256; # MICMUTE
|
||||
<352> = 360; # OK
|
||||
<353> = 361; # SELECT
|
||||
<354> = 362; # GOTO
|
||||
<355> = 363; # CLEAR
|
||||
<356> = 364; # POWER2
|
||||
<357> = 365; # OPTION
|
||||
<358> = 366; # INFO
|
||||
<359> = 367; # TIME
|
||||
<360> = 368; # VENDOR
|
||||
<361> = 369; # ARCHIVE
|
||||
<362> = 370; # PROGRAM
|
||||
<363> = 371; # CHANNEL
|
||||
<364> = 372; # FAVORITES
|
||||
<365> = 373; # EPG
|
||||
<366> = 374; # PVR
|
||||
<367> = 375; # MHP
|
||||
<368> = 376; # LANGUAGE
|
||||
<369> = 377; # TITLE
|
||||
<370> = 378; # SUBTITLE
|
||||
<371> = 379; # ANGLE
|
||||
<372> = 380; # FULL_SCREEN
|
||||
<373> = 381; # MODE
|
||||
<374> = 382; # KEYBOARD
|
||||
<375> = 383; # ASPECT_RATIO
|
||||
<376> = 384; # PC
|
||||
<377> = 385; # TV
|
||||
<378> = 386; # TV2
|
||||
<379> = 387; # VCR
|
||||
<380> = 388; # VCR2
|
||||
<381> = 389; # SAT
|
||||
<382> = 390; # SAT2
|
||||
<383> = 391; # CD
|
||||
<384> = 392; # TAPE
|
||||
<385> = 393; # RADIO
|
||||
<386> = 394; # TUNER
|
||||
<387> = 395; # PLAYER
|
||||
<388> = 396; # TEXT
|
||||
<389> = 397; # DVD
|
||||
<390> = 398; # AUX
|
||||
<391> = 399; # MP3
|
||||
<392> = 400; # AUDIO
|
||||
<393> = 401; # VIDEO
|
||||
<394> = 402; # DIRECTORY
|
||||
<395> = 403; # LIST
|
||||
<396> = 404; # MEMO
|
||||
<397> = 405; # CALENDAR
|
||||
<398> = 406; # RED
|
||||
<399> = 407; # GREEN
|
||||
<400> = 408; # YELLOW
|
||||
<401> = 409; # BLUE
|
||||
<402> = 410; # CHANNELUP
|
||||
<403> = 411; # CHANNELDOWN
|
||||
<404> = 412; # FIRST
|
||||
<405> = 413; # LAST
|
||||
<406> = 414; # AB
|
||||
<407> = 415; # NEXT
|
||||
<408> = 416; # RESTART
|
||||
<409> = 417; # SLOW
|
||||
<410> = 418; # SHUFFLE
|
||||
<411> = 419; # BREAK
|
||||
<412> = 420; # PREVIOUS
|
||||
<413> = 421; # DIGITS
|
||||
<414> = 422; # TEEN
|
||||
<415> = 423; # TWEN
|
||||
<416> = 424; # VIDEOPHONE
|
||||
<417> = 425; # GAMES
|
||||
<418> = 426; # ZOOMIN
|
||||
<419> = 427; # ZOOMOUT
|
||||
<420> = 428; # ZOOMRESET
|
||||
<421> = 429; # WORDPROCESSOR
|
||||
<422> = 430; # EDITOR
|
||||
<423> = 431; # SPREADSHEET
|
||||
<424> = 432; # GRAPHICSEDITOR
|
||||
<425> = 433; # PRESENTATION
|
||||
<426> = 434; # DATABASE
|
||||
<427> = 435; # NEWS
|
||||
<428> = 436; # VOICEMAIL
|
||||
<429> = 437; # ADDRESSBOOK
|
||||
<430> = 438; # MESSENGER
|
||||
<431> = 439; # DISPLAYTOGGLE
|
||||
<432> = 440; # SPELLCHECK
|
||||
<433> = 441; # LOGOFF
|
||||
<434> = 442; # DOLLAR
|
||||
<435> = 443; # EURO
|
||||
<436> = 444; # FRAMEBACK
|
||||
<437> = 445; # FRAMEFORWARD
|
||||
<438> = 446; # CONTEXT_MENU
|
||||
<439> = 447; # MEDIA_REPEAT
|
||||
<440> = 448; # 10CHANNELSUP
|
||||
<441> = 449; # 10CHANNELSDOWN
|
||||
<442> = 450; # IMAGES
|
||||
<444> = 452; # NOTIFICATION_CENTER
|
||||
<445> = 453; # PICKUP_PHONE
|
||||
<446> = 454; # HANGUP_PHONE
|
||||
<448> = 456; # DEL_EOL
|
||||
<449> = 457; # DEL_EOS
|
||||
<450> = 458; # INS_LINE
|
||||
<451> = 459; # DEL_LINE
|
||||
<464> = 472; # FN
|
||||
<465> = 473; # FN_ESC
|
||||
<466> = 474; # FN_F1
|
||||
<467> = 475; # FN_F2
|
||||
<468> = 476; # FN_F3
|
||||
<469> = 477; # FN_F4
|
||||
<470> = 478; # FN_F5
|
||||
<471> = 479; # FN_F6
|
||||
<472> = 480; # FN_F7
|
||||
<473> = 481; # FN_F8
|
||||
<474> = 482; # FN_F9
|
||||
<475> = 483; # FN_F10
|
||||
<476> = 484; # FN_F11
|
||||
<477> = 485; # FN_F12
|
||||
<478> = 486; # FN_1
|
||||
<479> = 487; # FN_2
|
||||
<480> = 488; # FN_D
|
||||
<481> = 489; # FN_E
|
||||
<482> = 490; # FN_F
|
||||
<483> = 491; # FN_S
|
||||
<484> = 492; # FN_B
|
||||
<485> = 493; # FN_RIGHT_SHIFT
|
||||
<497> = 505; # BRL_DOT1
|
||||
<498> = 506; # BRL_DOT2
|
||||
<499> = 507; # BRL_DOT3
|
||||
<500> = 508; # BRL_DOT4
|
||||
<501> = 509; # BRL_DOT5
|
||||
<502> = 510; # BRL_DOT6
|
||||
<503> = 511; # BRL_DOT7
|
||||
<504> = 512; # BRL_DOT8
|
||||
<505> = 513; # BRL_DOT9
|
||||
<506> = 514; # BRL_DOT10
|
||||
<512> = 520; # NUMERIC_0
|
||||
<513> = 521; # NUMERIC_1
|
||||
<514> = 522; # NUMERIC_2
|
||||
<515> = 523; # NUMERIC_3
|
||||
<516> = 524; # NUMERIC_4
|
||||
<517> = 525; # NUMERIC_5
|
||||
<518> = 526; # NUMERIC_6
|
||||
<519> = 527; # NUMERIC_7
|
||||
<520> = 528; # NUMERIC_8
|
||||
<521> = 529; # NUMERIC_9
|
||||
<522> = 530; # NUMERIC_STAR
|
||||
<523> = 531; # NUMERIC_POUND
|
||||
<524> = 532; # NUMERIC_A
|
||||
<525> = 533; # NUMERIC_B
|
||||
<526> = 534; # NUMERIC_C
|
||||
<527> = 535; # NUMERIC_D
|
||||
<528> = 536; # CAMERA_FOCUS
|
||||
<529> = 537; # WPS_BUTTON
|
||||
<530> = 538; # TOUCHPAD_TOGGLE
|
||||
<531> = 539; # TOUCHPAD_ON
|
||||
<532> = 540; # TOUCHPAD_OFF
|
||||
<533> = 541; # CAMERA_ZOOMIN
|
||||
<534> = 542; # CAMERA_ZOOMOUT
|
||||
<535> = 543; # CAMERA_UP
|
||||
<536> = 544; # CAMERA_DOWN
|
||||
<537> = 545; # CAMERA_LEFT
|
||||
<538> = 546; # CAMERA_RIGHT
|
||||
<539> = 547; # ATTENDANT_ON
|
||||
<540> = 548; # ATTENDANT_OFF
|
||||
<541> = 549; # ATTENDANT_TOGGLE
|
||||
<542> = 550; # LIGHTS_TOGGLE
|
||||
<560> = 568; # ALS_TOGGLE
|
||||
<561> = 569; # ROTATE_LOCK_TOGGLE
|
||||
<576> = 584; # BUTTONCONFIG
|
||||
<577> = 585; # TASKMANAGER
|
||||
<578> = 586; # JOURNAL
|
||||
<579> = 587; # CONTROLPANEL
|
||||
<580> = 588; # APPSELECT
|
||||
<581> = 589; # SCREENSAVER
|
||||
<582> = 590; # VOICECOMMAND
|
||||
<583> = 591; # ASSISTANT
|
||||
<584> = 592; # KBD_LAYOUT_NEXT
|
||||
<585> = 593; # EMOJI_PICKER
|
||||
<592> = 600; # BRIGHTNESS_MIN
|
||||
<593> = 601; # BRIGHTNESS_MAX
|
||||
<608> = 616; # KBDINPUTASSIST_PREV
|
||||
<609> = 617; # KBDINPUTASSIST_NEXT
|
||||
<610> = 618; # KBDINPUTASSIST_PREVGROUP
|
||||
<611> = 619; # KBDINPUTASSIST_NEXTGROUP
|
||||
<612> = 620; # KBDINPUTASSIST_ACCEPT
|
||||
<613> = 621; # KBDINPUTASSIST_CANCEL
|
||||
<614> = 622; # RIGHT_UP
|
||||
<615> = 623; # RIGHT_DOWN
|
||||
<616> = 624; # LEFT_UP
|
||||
<617> = 625; # LEFT_DOWN
|
||||
<618> = 626; # ROOT_MENU
|
||||
<619> = 627; # MEDIA_TOP_MENU
|
||||
<620> = 628; # NUMERIC_11
|
||||
<621> = 629; # NUMERIC_12
|
||||
<622> = 630; # AUDIO_DESC
|
||||
<623> = 631; # 3D_MODE
|
||||
<624> = 632; # NEXT_FAVORITE
|
||||
<625> = 633; # STOP_RECORD
|
||||
<626> = 634; # PAUSE_RECORD
|
||||
<627> = 635; # VOD
|
||||
<628> = 636; # UNMUTE
|
||||
<629> = 637; # FASTREVERSE
|
||||
<630> = 638; # SLOWREVERSE
|
||||
<631> = 639; # DATA
|
||||
<632> = 640; # ONSCREEN_KEYBOARD
|
||||
<633> = 641; # PRIVACY_SCREEN_TOGGLE
|
||||
<634> = 642; # SELECTIVE_SCREENSHOT
|
||||
<656> = 664; # MACRO1
|
||||
<657> = 665; # MACRO2
|
||||
<658> = 666; # MACRO3
|
||||
<659> = 667; # MACRO4
|
||||
<660> = 668; # MACRO5
|
||||
<661> = 669; # MACRO6
|
||||
<662> = 670; # MACRO7
|
||||
<663> = 671; # MACRO8
|
||||
<664> = 672; # MACRO9
|
||||
<665> = 673; # MACRO10
|
||||
<666> = 674; # MACRO11
|
||||
<667> = 675; # MACRO12
|
||||
<668> = 676; # MACRO13
|
||||
<669> = 677; # MACRO14
|
||||
<670> = 678; # MACRO15
|
||||
<671> = 679; # MACRO16
|
||||
<672> = 680; # MACRO17
|
||||
<673> = 681; # MACRO18
|
||||
<674> = 682; # MACRO19
|
||||
<675> = 683; # MACRO20
|
||||
<676> = 684; # MACRO21
|
||||
<677> = 685; # MACRO22
|
||||
<678> = 686; # MACRO23
|
||||
<679> = 687; # MACRO24
|
||||
<680> = 688; # MACRO25
|
||||
<681> = 689; # MACRO26
|
||||
<682> = 690; # MACRO27
|
||||
<683> = 691; # MACRO28
|
||||
<684> = 692; # MACRO29
|
||||
<685> = 693; # MACRO30
|
||||
<688> = 696; # MACRO_RECORD_START
|
||||
<689> = 697; # MACRO_RECORD_STOP
|
||||
<690> = 698; # MACRO_PRESET_CYCLE
|
||||
<691> = 699; # MACRO_PRESET1
|
||||
<692> = 700; # MACRO_PRESET2
|
||||
<693> = 701; # MACRO_PRESET3
|
||||
<696> = 704; # KBD_LCD_MENU1
|
||||
<697> = 705; # KBD_LCD_MENU2
|
||||
<698> = 706; # KBD_LCD_MENU3
|
||||
<699> = 707; # KBD_LCD_MENU4
|
||||
<700> = 708; # KBD_LCD_MENU5
|
||||
285
src/keymap.xkb
Normal file
285
src/keymap.xkb
Normal file
|
|
@ -0,0 +1,285 @@
|
|||
xkb_keymap {
|
||||
|
||||
xkb_keycodes {
|
||||
|
||||
<1> = 9; # ESC
|
||||
<2> = 10; # 1
|
||||
<3> = 11; # 2
|
||||
<4> = 12; # 3
|
||||
<5> = 13; # 4
|
||||
<6> = 14; # 5
|
||||
<7> = 15; # 6
|
||||
<8> = 16; # 7
|
||||
<9> = 17; # 8
|
||||
<10> = 18; # 9
|
||||
<11> = 19; # 0
|
||||
<12> = 20; # MINUS
|
||||
<13> = 21; # EQUAL
|
||||
<14> = 22; # BACKSPACE
|
||||
<15> = 23; # TAB
|
||||
<16> = 24; # Q
|
||||
<17> = 25; # W
|
||||
<18> = 26; # E
|
||||
<19> = 27; # R
|
||||
<20> = 28; # T
|
||||
<21> = 29; # Y
|
||||
<22> = 30; # U
|
||||
<23> = 31; # I
|
||||
<24> = 32; # O
|
||||
<25> = 33; # P
|
||||
<26> = 34; # LEFTBRACE
|
||||
<27> = 35; # RIGHTBRACE
|
||||
<28> = 36; # ENTER
|
||||
<29> = 37; # LEFTCTRL
|
||||
<30> = 38; # A
|
||||
<31> = 39; # S
|
||||
<32> = 40; # D
|
||||
<33> = 41; # F
|
||||
<34> = 42; # G
|
||||
<35> = 43; # H
|
||||
<36> = 44; # J
|
||||
<37> = 45; # K
|
||||
<38> = 46; # L
|
||||
<39> = 47; # SEMICOLON
|
||||
<40> = 48; # APOSTROPHE
|
||||
<41> = 49; # GRAVE
|
||||
<42> = 50; # LEFTSHIFT
|
||||
<43> = 51; # BACKSLASH
|
||||
<44> = 52; # Z
|
||||
<45> = 53; # X
|
||||
<46> = 54; # C
|
||||
<47> = 55; # V
|
||||
<48> = 56; # B
|
||||
<49> = 57; # N
|
||||
<50> = 58; # M
|
||||
<51> = 59; # COMMA
|
||||
<52> = 60; # DOT
|
||||
<53> = 61; # SLASH
|
||||
<54> = 62; # RIGHTSHIFT
|
||||
<55> = 63; # KPASTERISK
|
||||
<56> = 64; # LEFTALT
|
||||
<57> = 65; # SPACE
|
||||
<58> = 66; # CAPSLOCK
|
||||
<59> = 67; # F1
|
||||
<60> = 68; # F2
|
||||
<61> = 69; # F3
|
||||
<62> = 70; # F4
|
||||
<63> = 71; # F5
|
||||
<64> = 72; # F6
|
||||
<65> = 73; # F7
|
||||
<66> = 74; # F8
|
||||
<67> = 75; # F9
|
||||
<68> = 76; # F10
|
||||
<69> = 77; # NUMLOCK
|
||||
<70> = 78; # SCROLLLOCK
|
||||
<71> = 79; # KP7
|
||||
<72> = 80; # KP8
|
||||
<73> = 81; # KP9
|
||||
<74> = 82; # KPMINUS
|
||||
<75> = 83; # KP4
|
||||
<76> = 84; # KP5
|
||||
<77> = 85; # KP6
|
||||
<78> = 86; # KPPLUS
|
||||
<79> = 87; # KP1
|
||||
<80> = 88; # KP2
|
||||
<81> = 89; # KP3
|
||||
<82> = 90; # KP0
|
||||
<83> = 91; # KPDOT
|
||||
<87> = 95; # F11
|
||||
<88> = 96; # F12
|
||||
<96> = 104; # KPENTER
|
||||
<97> = 105; # RIGHTCTRL
|
||||
<98> = 106; # KPSLASH
|
||||
<100> = 108; # RIGHTALT
|
||||
<102> = 110; # HOME
|
||||
<103> = 111; # UP
|
||||
<104> = 112; # PAGEUP
|
||||
<105> = 113; # LEFT
|
||||
<106> = 114; # RIGHT
|
||||
<107> = 115; # END
|
||||
<108> = 116; # DOWN
|
||||
<109> = 117; # PAGEDOWN
|
||||
<110> = 118; # INSERT
|
||||
<111> = 119; # DELETE
|
||||
<117> = 125; # KPEQUAL
|
||||
<119> = 127; # PAUSE
|
||||
<125> = 133; # LEFTMETA
|
||||
<126> = 134; # RIGHTMETA
|
||||
<139> = 147; # MENU
|
||||
<210> = 218; # PRINT
|
||||
|
||||
# We must include at least one indicator here. Otherwise Xwayland segfaults.
|
||||
indicator 1 = "DUMMY";
|
||||
};
|
||||
|
||||
xkb_types {
|
||||
|
||||
# We must include at least one virtual modifier.
|
||||
# Otherwise Xwayland rejects our keymap.
|
||||
virtual_modifiers Dummy;
|
||||
|
||||
type "ONE_LEVEL" {
|
||||
modifiers = none;
|
||||
};
|
||||
type "TWO_LEVEL" {
|
||||
modifiers = Shift;
|
||||
map[Shift] = Level2;
|
||||
};
|
||||
type "ALPHABETIC" {
|
||||
modifiers = Shift+Lock;
|
||||
map[Shift] = Level2;
|
||||
map[Lock] = Level2;
|
||||
};
|
||||
type "KEYPAD" {
|
||||
modifiers = Shift+Mod2;
|
||||
map[Mod2] = Level2;
|
||||
};
|
||||
};
|
||||
|
||||
xkb_compatibility {
|
||||
|
||||
interpret.repeat = False;
|
||||
interpret.locking = False;
|
||||
interpret Shift_L {
|
||||
action = SetMods(modifiers=Shift);
|
||||
};
|
||||
interpret Shift_R {
|
||||
action = SetMods(modifiers=Shift);
|
||||
};
|
||||
interpret Caps_Lock {
|
||||
action = LockMods(modifiers=Lock);
|
||||
};
|
||||
interpret Control_L {
|
||||
action = SetMods(modifiers=Control);
|
||||
};
|
||||
interpret Control_R {
|
||||
action = SetMods(modifiers=Control);
|
||||
};
|
||||
interpret Alt_L {
|
||||
action = SetMods(modifiers=Mod1);
|
||||
};
|
||||
interpret Alt_R {
|
||||
action = SetMods(modifiers=Mod1);
|
||||
};
|
||||
interpret Num_Lock {
|
||||
action = LockMods(modifiers=Mod2);
|
||||
};
|
||||
};
|
||||
|
||||
xkb_symbols {
|
||||
|
||||
key <1> { [ Escape ] };
|
||||
key <59> { [ F1 ] };
|
||||
key <60> { [ F2 ] };
|
||||
key <61> { [ F3 ] };
|
||||
key <62> { [ F4 ] };
|
||||
key <63> { [ F5 ] };
|
||||
key <64> { [ F6 ] };
|
||||
key <65> { [ F7 ] };
|
||||
key <66> { [ F8 ] };
|
||||
key <67> { [ F9 ] };
|
||||
key <68> { [ F10 ] };
|
||||
key <87> { [ F11 ] };
|
||||
key <88> { [ F12 ] };
|
||||
key <210> { [ Print ] };
|
||||
key <70> { [ Scroll_Lock ] };
|
||||
key <119> { [ Pause ] };
|
||||
|
||||
key <69> { [ Num_Lock ] };
|
||||
key <96> { [ KP_Enter ] };
|
||||
key <98> { [ KP_Divide ] };
|
||||
key <74> { [ KP_Subtract ] };
|
||||
key <55> { [ KP_Multiply ] };
|
||||
key <78> { [ KP_Add ] };
|
||||
key <117> { [ KP_Equal ] };
|
||||
key <83> { [ KP_Delete, KP_Decimal ] };
|
||||
key <71> { [ KP_Home, KP_7 ] };
|
||||
key <72> { [ KP_Up, KP_8 ] };
|
||||
key <73> { [ KP_Prior, KP_9 ] };
|
||||
key <75> { [ KP_Left, KP_4 ] };
|
||||
key <76> { [ KP_Begin, KP_5 ] };
|
||||
key <77> { [ KP_Right, KP_6 ] };
|
||||
key <79> { [ KP_End, KP_1 ] };
|
||||
key <80> { [ KP_Down, KP_2 ] };
|
||||
key <81> { [ KP_Next, KP_3 ] };
|
||||
key <82> { [ KP_Insert, KP_0 ] };
|
||||
|
||||
key <103> { [ Up ] };
|
||||
key <105> { [ Left ] };
|
||||
key <106> { [ Right ] };
|
||||
key <108> { [ Down ] };
|
||||
|
||||
key <102> { [ Home ] };
|
||||
key <104> { [ Prior ] };
|
||||
key <107> { [ End ] };
|
||||
key <109> { [ Next ] };
|
||||
key <110> { [ Insert ] };
|
||||
key <111> { [ Delete ] };
|
||||
|
||||
key <14> { [ BackSpace ] };
|
||||
key <15> { [ Tab, ISO_Left_Tab ] };
|
||||
key <58> { [ Caps_Lock ] };
|
||||
key <28> { [ Return ] };
|
||||
key <42> { [ Shift_L ] };
|
||||
key <54> { [ Shift_R ] };
|
||||
key <29> { [ Control_L ] };
|
||||
key <125> { [ Super_L ] };
|
||||
key <56> { [ Alt_L ] };
|
||||
key <57> { [ space ] };
|
||||
key <100> { [ Alt_R ] };
|
||||
key <126> { [ Super_R ] };
|
||||
key <139> { [ Menu ] };
|
||||
key <97> { [ Control_R ] };
|
||||
|
||||
key <41> { [ grave, asciitilde ] };
|
||||
key <12> { [ minus, underscore ] };
|
||||
key <13> { [ equal, plus ] };
|
||||
key <26> { [ bracketleft, braceleft ] };
|
||||
key <27> { [ bracketright, braceright ] };
|
||||
key <43> { [ backslash, bar ] };
|
||||
key <39> { [ semicolon, colon ] };
|
||||
key <40> { [ apostrophe, quotedbl ] };
|
||||
key <51> { [ comma, less ] };
|
||||
key <52> { [ period, greater ] };
|
||||
key <53> { [ slash, question ] };
|
||||
|
||||
key <16> { [ q, Q ] };
|
||||
key <17> { [ w, W ] };
|
||||
key <18> { [ e, E ] };
|
||||
key <19> { [ r, R ] };
|
||||
key <20> { [ t, T ] };
|
||||
key <21> { [ y, Y ] };
|
||||
key <22> { [ u, U ] };
|
||||
key <23> { [ i, I ] };
|
||||
key <24> { [ o, O ] };
|
||||
key <25> { [ p, P ] };
|
||||
key <30> { [ a, A ] };
|
||||
key <31> { [ s, S ] };
|
||||
key <32> { [ d, D ] };
|
||||
key <33> { [ f, F ] };
|
||||
key <34> { [ g, G ] };
|
||||
key <35> { [ h, H ] };
|
||||
key <36> { [ j, J ] };
|
||||
key <37> { [ k, K ] };
|
||||
key <38> { [ l, L ] };
|
||||
key <44> { [ z, Z ] };
|
||||
key <45> { [ x, X ] };
|
||||
key <46> { [ c, C ] };
|
||||
key <47> { [ v, V ] };
|
||||
key <48> { [ b, B ] };
|
||||
key <49> { [ n, N ] };
|
||||
key <50> { [ m, M ] };
|
||||
|
||||
key <2> { [ 1, exclam ] };
|
||||
key <3> { [ 2, at ] };
|
||||
key <4> { [ 3, numbersign ] };
|
||||
key <5> { [ 4, dollar ] };
|
||||
key <6> { [ 5, percent ] };
|
||||
key <7> { [ 6, asciicircum ] };
|
||||
key <8> { [ 7, ampersand ] };
|
||||
key <9> { [ 8, asterisk ] };
|
||||
key <10> { [ 9, parenleft ] };
|
||||
key <11> { [ 0, parenright ] };
|
||||
};
|
||||
|
||||
};
|
||||
51
src/leaks.rs
51
src/leaks.rs
|
|
@ -1,8 +1,14 @@
|
|||
pub use leaks::*;
|
||||
|
||||
macro_rules! track {
|
||||
($client:expr, $rc:expr) => {
|
||||
$rc.tracker.register($client.id);
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "rc_tracking"))]
|
||||
#[macro_use]
|
||||
mod leaks {
|
||||
use crate::client::ClientId;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub fn init() {
|
||||
|
|
@ -17,6 +23,12 @@ mod leaks {
|
|||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> Tracker<T> {
|
||||
pub fn register(&self, _client: ClientId) {
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for Tracker<T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
|
|
@ -24,16 +36,9 @@ mod leaks {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! track {
|
||||
($client:expr, $rc:expr) => {
|
||||
let _ = $rc.tracker;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rc_tracking")]
|
||||
#[macro_use]
|
||||
mod leaks {
|
||||
use crate::client::ClientId;
|
||||
use crate::utils::ptr_ext::{MutPtrExt, PtrExt};
|
||||
|
|
@ -59,7 +64,12 @@ mod leaks {
|
|||
}
|
||||
}
|
||||
|
||||
fn log_containers(prefix: &str, allocation: &mut Allocation, offset: usize, logged: &mut AHashSet<*mut u8>) {
|
||||
fn log_containers(
|
||||
prefix: &str,
|
||||
allocation: &mut Allocation,
|
||||
offset: usize,
|
||||
logged: &mut AHashSet<*mut u8>,
|
||||
) {
|
||||
log::info!(
|
||||
"{}Contained in allocation {:?} at offset {}. Backtrace:",
|
||||
prefix,
|
||||
|
|
@ -94,6 +104,9 @@ mod leaks {
|
|||
for (id, obj) in MAP.deref_mut().drain() {
|
||||
map.entry(obj.client).or_default().push((id, obj));
|
||||
}
|
||||
if map.is_empty() {
|
||||
log::info!("No leaks");
|
||||
}
|
||||
for (_, mut objs) in map.drain() {
|
||||
if objs.len() == 0 {
|
||||
continue;
|
||||
|
|
@ -102,13 +115,11 @@ mod leaks {
|
|||
log::info!("Client {} leaked {} objects", objs[0].1.client, objs.len());
|
||||
for (_, obj) in objs {
|
||||
let time = chrono::NaiveDateTime::from_timestamp(obj.time.0, obj.time.1);
|
||||
log::info!(
|
||||
" [{}] {}",
|
||||
time.format("%H:%M:%S%.3f"),
|
||||
obj.ty,
|
||||
);
|
||||
log::info!(" [{}] {}", time.format("%H:%M:%S%.3f"), obj.ty,);
|
||||
match find_allocation_containing(obj.addr) {
|
||||
Some(mut alloc) => log_containers(" ", &mut alloc, 0, &mut AHashSet::new()),
|
||||
Some(mut alloc) => {
|
||||
log_containers(" ", &mut alloc, 0, &mut AHashSet::new())
|
||||
}
|
||||
_ => log::error!(" Not contained in any allocation??"),
|
||||
}
|
||||
}
|
||||
|
|
@ -174,14 +185,6 @@ mod leaks {
|
|||
}
|
||||
}
|
||||
|
||||
macro_rules! track {
|
||||
($client:expr, $rc:expr) => {
|
||||
($rc)
|
||||
.tracker
|
||||
.register($client.id);
|
||||
};
|
||||
}
|
||||
|
||||
struct TracingAllocator;
|
||||
|
||||
#[global_allocator]
|
||||
|
|
@ -225,7 +228,7 @@ mod leaks {
|
|||
if INITIALIZED {
|
||||
ALLOCATIONS.deref_mut().remove(&ptr);
|
||||
}
|
||||
c::memset(ptr as _, 0, layout.size());
|
||||
// c::memset(ptr as _, 0, layout.size());
|
||||
c::free(ptr as _);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -168,6 +168,11 @@ macro_rules! linear_ids {
|
|||
pub fn raw(&self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn from_raw(id: u32) -> Self {
|
||||
Self(id)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for $id {
|
||||
|
|
|
|||
35
src/main.rs
35
src/main.rs
|
|
@ -1,11 +1,4 @@
|
|||
#![feature(
|
||||
c_variadic,
|
||||
thread_local,
|
||||
label_break_value,
|
||||
ptr_metadata,
|
||||
linkage,
|
||||
const_type_name
|
||||
)]
|
||||
#![feature(c_variadic, thread_local, label_break_value)]
|
||||
#![allow(
|
||||
clippy::len_zero,
|
||||
clippy::needless_lifetimes,
|
||||
|
|
@ -39,18 +32,18 @@ use crate::wheel::WheelError;
|
|||
use acceptor::Acceptor;
|
||||
use async_engine::AsyncEngine;
|
||||
use event_loop::EventLoop;
|
||||
use isnt::std_1::primitive::IsntMutPtrExt;
|
||||
use log::LevelFilter;
|
||||
use std::cell::Cell;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
use thiserror::Error;
|
||||
use wheel::Wheel;
|
||||
use crate::xkbcommon::XkbContext;
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
#[macro_use]
|
||||
pub mod leaks;
|
||||
mod leaks;
|
||||
mod acceptor;
|
||||
mod async_engine;
|
||||
mod backend;
|
||||
|
|
@ -58,6 +51,7 @@ mod backends;
|
|||
mod bugs;
|
||||
mod client;
|
||||
mod clientmem;
|
||||
mod config;
|
||||
mod cursor;
|
||||
mod drm;
|
||||
mod event_loop;
|
||||
|
|
@ -81,15 +75,6 @@ mod wire;
|
|||
mod xkbcommon;
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
extern "C" {
|
||||
#[linkage = "extern_weak"]
|
||||
static BYTEHOUND_REACHED_MAIN: *mut bool;
|
||||
}
|
||||
if BYTEHOUND_REACHED_MAIN.is_not_null() {
|
||||
*BYTEHOUND_REACHED_MAIN = true;
|
||||
}
|
||||
}
|
||||
env_logger::builder()
|
||||
.filter_level(LevelFilter::Info)
|
||||
.filter_level(LevelFilter::Debug)
|
||||
|
|
@ -127,10 +112,14 @@ fn main_() -> Result<(), MainError> {
|
|||
clientmem::init()?;
|
||||
let el = EventLoop::new()?;
|
||||
sighand::install(&el)?;
|
||||
let xkb_ctx = XkbContext::new().unwrap();
|
||||
let xkb_keymap = xkb_ctx.keymap_from_str(include_str!("keymap.xkb")).unwrap();
|
||||
let wheel = Wheel::install(&el)?;
|
||||
let engine = AsyncEngine::install(&el, &wheel)?;
|
||||
let node_ids = NodeIds::default();
|
||||
let state = Rc::new(State {
|
||||
xkb_ctx,
|
||||
default_keymap: xkb_keymap,
|
||||
eng: engine.clone(),
|
||||
el: el.clone(),
|
||||
render_ctx: Default::default(),
|
||||
|
|
@ -144,14 +133,20 @@ fn main_() -> Result<(), MainError> {
|
|||
node_ids,
|
||||
backend_events: AsyncQueue::new(),
|
||||
output_handlers: Default::default(),
|
||||
mouse_handlers: Default::default(),
|
||||
seat_ids: Default::default(),
|
||||
seats: Default::default(),
|
||||
kb_ids: Default::default(),
|
||||
outputs: Default::default(),
|
||||
seat_queue: Default::default(),
|
||||
slow_clients: AsyncQueue::new(),
|
||||
none_surface_ext: Rc::new(NoneSurfaceExt),
|
||||
tree_changed_sent: Cell::new(false),
|
||||
config: Default::default(),
|
||||
mouse_ids: Default::default(),
|
||||
kb_handlers: Default::default(),
|
||||
});
|
||||
let config = config::ConfigProxy::default(&state);
|
||||
state.config.set(Some(Rc::new(config)));
|
||||
let _global_event_handler = engine.spawn(tasks::handle_backend_events(state.clone()));
|
||||
let _slow_client_handler = engine.spawn(tasks::handle_slow_clients(state.clone()));
|
||||
Acceptor::install(&state)?;
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ impl GlProgram {
|
|||
|
||||
let mut ok = 0;
|
||||
glGetProgramiv(res.prog, GL_LINK_STATUS, &mut ok);
|
||||
if ok == GL_FALSE as _ {
|
||||
if ok == GL_FALSE as GLint {
|
||||
return Err(RenderError::ProgramLink);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use crate::render::gl::sys::{
|
|||
glCompileShader, glCreateShader, glDeleteShader, glGetShaderiv, glShaderSource, GLenum, GLuint,
|
||||
GL_COMPILE_STATUS, GL_FALSE,
|
||||
};
|
||||
use crate::render::sys::GLint;
|
||||
use crate::render::RenderError;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
|
@ -28,7 +29,7 @@ impl GlShader {
|
|||
|
||||
let mut ok = 0;
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &mut ok);
|
||||
if ok == GL_FALSE as _ {
|
||||
if ok == GL_FALSE as GLint {
|
||||
return Err(RenderError::ShaderCompileFailed);
|
||||
}
|
||||
Ok(res)
|
||||
|
|
|
|||
36
src/state.rs
36
src/state.rs
|
|
@ -1,26 +1,29 @@
|
|||
use crate::async_engine::{AsyncEngine, SpawnedFuture};
|
||||
use crate::backend::{BackendEvent, OutputId, OutputIds, SeatId, SeatIds};
|
||||
use crate::backend::{BackendEvent, KeyboardId, KeyboardIds, MouseId, MouseIds, OutputId, OutputIds};
|
||||
use crate::client::{Client, Clients};
|
||||
use crate::config::ConfigProxy;
|
||||
use crate::cursor::ServerCursors;
|
||||
use crate::event_loop::EventLoop;
|
||||
use crate::globals::{Globals, GlobalsError, WaylandGlobal};
|
||||
use crate::ifs::wl_output::WlOutputGlobal;
|
||||
use crate::ifs::wl_seat::WlSeatGlobal;
|
||||
use crate::ifs::wl_seat::{SeatIds, WlSeatGlobal};
|
||||
use crate::ifs::wl_surface::NoneSurfaceExt;
|
||||
use crate::render::RenderContext;
|
||||
use crate::tree::{DisplayNode, NodeIds};
|
||||
use crate::utils::asyncevent::AsyncEvent;
|
||||
use crate::utils::clonecell::CloneCell;
|
||||
use crate::utils::copyhashmap::CopyHashMap;
|
||||
use crate::utils::linkedlist::LinkedList;
|
||||
use crate::utils::numcell::NumCell;
|
||||
use crate::utils::queue::AsyncQueue;
|
||||
use crate::{ErrorFmt, Wheel};
|
||||
use crate::{ErrorFmt, Wheel, XkbContext};
|
||||
use ahash::AHashMap;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::rc::Rc;
|
||||
use crate::xkbcommon::XkbKeymap;
|
||||
|
||||
pub struct State {
|
||||
pub xkb_ctx: XkbContext,
|
||||
pub default_keymap: Rc<XkbKeymap>,
|
||||
pub eng: Rc<AsyncEngine>,
|
||||
pub el: Rc<EventLoop>,
|
||||
pub render_ctx: CloneCell<Option<Rc<RenderContext>>>,
|
||||
|
|
@ -31,21 +34,36 @@ pub struct State {
|
|||
pub globals: Globals,
|
||||
pub output_ids: OutputIds,
|
||||
pub seat_ids: SeatIds,
|
||||
pub kb_ids: KeyboardIds,
|
||||
pub mouse_ids: MouseIds,
|
||||
pub node_ids: NodeIds,
|
||||
pub root: Rc<DisplayNode>,
|
||||
pub backend_events: AsyncQueue<BackendEvent>,
|
||||
pub output_handlers: RefCell<AHashMap<OutputId, SpawnedFuture<()>>>,
|
||||
pub seats: RefCell<AHashMap<SeatId, SeatData>>,
|
||||
pub mouse_handlers: RefCell<AHashMap<MouseId, MouseData>>,
|
||||
pub kb_handlers: RefCell<AHashMap<KeyboardId, KeyboardData>>,
|
||||
pub outputs: CopyHashMap<OutputId, Rc<WlOutputGlobal>>,
|
||||
pub seat_queue: LinkedList<Rc<WlSeatGlobal>>,
|
||||
pub slow_clients: AsyncQueue<Rc<Client>>,
|
||||
pub none_surface_ext: Rc<NoneSurfaceExt>,
|
||||
pub tree_changed_sent: Cell<bool>,
|
||||
pub config: CloneCell<Option<Rc<ConfigProxy>>>,
|
||||
}
|
||||
|
||||
pub struct SeatData {
|
||||
pub struct MouseData {
|
||||
pub handler: SpawnedFuture<()>,
|
||||
pub tree_changed: Rc<AsyncEvent>,
|
||||
pub id: MouseId,
|
||||
pub data: Rc<DeviceHandlerData>
|
||||
}
|
||||
|
||||
pub struct KeyboardData {
|
||||
pub handler: SpawnedFuture<()>,
|
||||
pub id: KeyboardId,
|
||||
pub data: Rc<DeviceHandlerData>
|
||||
}
|
||||
|
||||
pub struct DeviceHandlerData {
|
||||
pub seat: CloneCell<Option<Rc<WlSeatGlobal>>>,
|
||||
}
|
||||
|
||||
impl State {
|
||||
|
|
@ -73,9 +91,9 @@ impl State {
|
|||
if self.tree_changed_sent.replace(true) {
|
||||
return;
|
||||
}
|
||||
let seats = self.seats.borrow();
|
||||
let seats = self.globals.seats.lock();
|
||||
for seat in seats.values() {
|
||||
seat.tree_changed.trigger();
|
||||
seat.trigger_tree_changed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
use crate::backend::{BackendEvent, Output, Seat};
|
||||
use crate::state::SeatData;
|
||||
use crate::backend::{BackendEvent, Output};
|
||||
use crate::tasks::output::OutputHandler;
|
||||
use crate::tasks::seat::SeatHandler;
|
||||
use crate::utils::asyncevent::AsyncEvent;
|
||||
use crate::State;
|
||||
use std::rc::Rc;
|
||||
use crate::tasks::device;
|
||||
|
||||
pub struct BackendEventHandler {
|
||||
pub state: Rc<State>,
|
||||
|
|
@ -21,7 +19,8 @@ impl BackendEventHandler {
|
|||
fn handle_event(&mut self, event: BackendEvent) {
|
||||
match event {
|
||||
BackendEvent::NewOutput(output) => self.handle_new_output(output),
|
||||
BackendEvent::NewSeat(seat) => self.handle_new_seat(seat),
|
||||
BackendEvent::NewMouse(s) => device::handle(&self.state, s),
|
||||
BackendEvent::NewKeyboard(s) => device::handle(&self.state, s),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -34,22 +33,4 @@ impl BackendEventHandler {
|
|||
let future = self.state.eng.spawn(oh.handle());
|
||||
self.state.output_handlers.borrow_mut().insert(id, future);
|
||||
}
|
||||
|
||||
fn handle_new_seat(&mut self, seat: Rc<dyn Seat>) {
|
||||
let id = seat.id();
|
||||
let tree_changed = Rc::new(AsyncEvent::default());
|
||||
let oh = SeatHandler {
|
||||
state: self.state.clone(),
|
||||
seat,
|
||||
tree_changed: tree_changed.clone(),
|
||||
};
|
||||
let handler = self.state.eng.spawn(oh.handle());
|
||||
self.state.seats.borrow_mut().insert(
|
||||
id,
|
||||
SeatData {
|
||||
handler,
|
||||
tree_changed,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
157
src/tasks/device.rs
Normal file
157
src/tasks/device.rs
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
use crate::backend::{Keyboard, KeyboardEvent, Mouse, MouseEvent};
|
||||
use crate::ifs::wl_seat::WlSeatGlobal;
|
||||
use crate::utils::asyncevent::AsyncEvent;
|
||||
use crate::State;
|
||||
use std::rc::Rc;
|
||||
use crate::async_engine::SpawnedFuture;
|
||||
use crate::config::ConfigProxy;
|
||||
use crate::state::{DeviceHandlerData, KeyboardData, MouseData};
|
||||
|
||||
pub trait DeviceApi: 'static {
|
||||
type Event;
|
||||
|
||||
fn on_change(&self, cb: Rc<dyn Fn()>);
|
||||
fn announce(&self, config: &ConfigProxy);
|
||||
fn announce_del(&self, config: &ConfigProxy);
|
||||
fn removed(&self) -> bool;
|
||||
fn add(&self, state: &State, handler: SpawnedFuture<()>, data: Rc<DeviceHandlerData>);
|
||||
fn remove(&self, state: &State);
|
||||
fn event(&self) -> Option<Self::Event>;
|
||||
fn send(seat: &Rc<WlSeatGlobal>, event: Self::Event);
|
||||
}
|
||||
|
||||
impl DeviceApi for dyn Keyboard {
|
||||
type Event = KeyboardEvent;
|
||||
|
||||
fn on_change(&self, cb: Rc<dyn Fn()>) {
|
||||
self.on_change(cb);
|
||||
}
|
||||
|
||||
fn announce(&self, config: &ConfigProxy) {
|
||||
config.new_keyboard(self.id());
|
||||
}
|
||||
|
||||
fn announce_del(&self, config: &ConfigProxy) {
|
||||
config.del_keyboard(self.id());
|
||||
}
|
||||
|
||||
fn removed(&self) -> bool {
|
||||
self.removed()
|
||||
}
|
||||
|
||||
fn add(&self, state: &State, handler: SpawnedFuture<()>, data: Rc<DeviceHandlerData>) {
|
||||
state.kb_handlers.borrow_mut().insert(self.id(), KeyboardData {
|
||||
handler,
|
||||
id: self.id(),
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
fn remove(&self, state: &State) {
|
||||
state.kb_handlers.borrow_mut().remove(&self.id());
|
||||
}
|
||||
|
||||
fn event(&self) -> Option<Self::Event> {
|
||||
self.event()
|
||||
}
|
||||
|
||||
fn send(seat: &Rc<WlSeatGlobal>, event: Self::Event) {
|
||||
seat.kb_event(event);
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceApi for dyn Mouse {
|
||||
type Event = MouseEvent;
|
||||
|
||||
fn on_change(&self, cb: Rc<dyn Fn()>) {
|
||||
self.on_change(cb);
|
||||
}
|
||||
|
||||
fn announce(&self, config: &ConfigProxy) {
|
||||
config.new_mouse(self.id());
|
||||
}
|
||||
|
||||
fn announce_del(&self, config: &ConfigProxy) {
|
||||
config.del_mouse(self.id());
|
||||
}
|
||||
|
||||
fn removed(&self) -> bool {
|
||||
self.removed()
|
||||
}
|
||||
|
||||
fn add(&self, state: &State, handler: SpawnedFuture<()>, data: Rc<DeviceHandlerData>) {
|
||||
state.mouse_handlers.borrow_mut().insert(self.id(), MouseData {
|
||||
handler,
|
||||
id: self.id(),
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
fn remove(&self, state: &State) {
|
||||
state.mouse_handlers.borrow_mut().remove(&self.id());
|
||||
}
|
||||
|
||||
fn event(&self) -> Option<Self::Event> {
|
||||
self.event()
|
||||
}
|
||||
|
||||
fn send(seat: &Rc<WlSeatGlobal>, event: Self::Event) {
|
||||
seat.mouse_event(event);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle<T: DeviceApi + ?Sized>(state: &Rc<State>, dev: Rc<T>) {
|
||||
let data = Rc::new(DeviceHandlerData {
|
||||
seat: Default::default(),
|
||||
});
|
||||
let oh = DeviceHandler {
|
||||
state: state.clone(),
|
||||
dev: dev.clone(),
|
||||
data: data.clone(),
|
||||
};
|
||||
let handler = state.eng.spawn(oh.handle());
|
||||
dev.add(&state, handler, data);
|
||||
}
|
||||
|
||||
pub struct DeviceHandler<T: DeviceApi + ?Sized> {
|
||||
pub state: Rc<State>,
|
||||
pub dev: Rc<T>,
|
||||
pub data: Rc<DeviceHandlerData>,
|
||||
}
|
||||
|
||||
impl<T: DeviceApi + ?Sized> DeviceHandler<T> {
|
||||
pub async fn handle(self) {
|
||||
let ae = Rc::new(AsyncEvent::default());
|
||||
{
|
||||
let ae = ae.clone();
|
||||
self.dev.on_change(Rc::new(move || ae.trigger()));
|
||||
}
|
||||
if let Some(config) = self.state.config.get() {
|
||||
self.dev.announce(&config);
|
||||
}
|
||||
loop {
|
||||
if self.dev.removed() {
|
||||
break;
|
||||
}
|
||||
if let Some(seat) = self.data.seat.get() {
|
||||
let mut any_events = false;
|
||||
while let Some(event) = self.dev.event() {
|
||||
T::send(&seat, event);
|
||||
any_events = true;
|
||||
}
|
||||
if any_events {
|
||||
seat.mark_last_active();
|
||||
}
|
||||
} else {
|
||||
while self.dev.event().is_some() {
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
ae.triggered().await;
|
||||
}
|
||||
if let Some(config) = self.state.config.get() {
|
||||
self.dev.announce_del(&config);
|
||||
}
|
||||
self.dev.remove(&self.state);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
mod backend;
|
||||
mod output;
|
||||
mod seat;
|
||||
mod slow_clients;
|
||||
mod device;
|
||||
|
||||
use crate::tasks::backend::BackendEventHandler;
|
||||
use crate::tasks::slow_clients::SlowClientHandler;
|
||||
|
|
|
|||
|
|
@ -1,60 +0,0 @@
|
|||
use crate::backend::Seat;
|
||||
use crate::ifs::wl_seat::WlSeatGlobal;
|
||||
use crate::utils::asyncevent::AsyncEvent;
|
||||
use crate::State;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct SeatHandler {
|
||||
pub state: Rc<State>,
|
||||
pub seat: Rc<dyn Seat>,
|
||||
pub tree_changed: Rc<AsyncEvent>,
|
||||
}
|
||||
|
||||
impl SeatHandler {
|
||||
pub async fn handle(self) {
|
||||
let ae = Rc::new(AsyncEvent::default());
|
||||
{
|
||||
let ae = ae.clone();
|
||||
self.seat.on_change(Rc::new(move || ae.trigger()));
|
||||
}
|
||||
let name = self.state.globals.name();
|
||||
let global = Rc::new(WlSeatGlobal::new(
|
||||
name,
|
||||
&self.state,
|
||||
&self.seat,
|
||||
&self.tree_changed,
|
||||
));
|
||||
let _tree_changed = self.state.eng.spawn(tree_changed(
|
||||
self.state.clone(),
|
||||
global.clone(),
|
||||
self.tree_changed.clone(),
|
||||
));
|
||||
let mut _node = self.state.seat_queue.add_last(global.clone());
|
||||
self.state.add_global(&global);
|
||||
loop {
|
||||
if self.seat.removed() {
|
||||
break;
|
||||
}
|
||||
let mut any_events = false;
|
||||
while let Some(event) = self.seat.event() {
|
||||
global.event(event);
|
||||
any_events = true;
|
||||
}
|
||||
if any_events {
|
||||
_node = self.state.seat_queue.add_last(global.clone());
|
||||
}
|
||||
ae.triggered().await;
|
||||
}
|
||||
global.set_cursor(None);
|
||||
let _ = self.state.remove_global(&*global);
|
||||
self.state.seats.borrow_mut().remove(&self.seat.id());
|
||||
}
|
||||
}
|
||||
|
||||
async fn tree_changed(state: Rc<State>, global: Rc<WlSeatGlobal>, tree_changed: Rc<AsyncEvent>) {
|
||||
loop {
|
||||
tree_changed.triggered().await;
|
||||
state.tree_changed_sent.set(false);
|
||||
global.tree_changed();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
use crate::backend::{KeyState, SeatId};
|
||||
use crate::backend::{KeyState};
|
||||
use crate::cursor::KnownCursor;
|
||||
use crate::fixed::Fixed;
|
||||
use crate::ifs::wl_seat::{NodeSeatState, WlSeatGlobal, BTN_LEFT};
|
||||
use crate::ifs::wl_seat::{NodeSeatState, WlSeatGlobal, BTN_LEFT, SeatId};
|
||||
use crate::rect::Rect;
|
||||
use crate::render::Renderer;
|
||||
use crate::tree::{FindTreeResult, FoundNode, Node, NodeId, WorkspaceNode};
|
||||
|
|
@ -14,6 +14,7 @@ use std::fmt::{Debug, Formatter};
|
|||
use std::mem;
|
||||
use std::ops::DerefMut;
|
||||
use std::rc::Rc;
|
||||
use i4config::Direction;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
|
|
@ -421,6 +422,52 @@ impl Node for ContainerNode {
|
|||
self.seat_state.destroy_node(self);
|
||||
}
|
||||
|
||||
fn do_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, direction: Direction) {
|
||||
let node = match direction {
|
||||
Direction::Left => self.children.last(),
|
||||
Direction::Down => self.children.first(),
|
||||
Direction::Up => self.children.last(),
|
||||
Direction::Right => self.children.first(),
|
||||
};
|
||||
if let Some(node) = node {
|
||||
node.node.clone().do_focus(seat, direction);
|
||||
}
|
||||
}
|
||||
|
||||
fn move_focus_from_child(&self, seat: &Rc<WlSeatGlobal>, child: &dyn Node, direction: Direction) {
|
||||
let children = self.child_nodes.borrow_mut();
|
||||
let child = match children.get(&child.id()) {
|
||||
Some(c) => c,
|
||||
_ => return,
|
||||
};
|
||||
let in_line = match self.split.get() {
|
||||
ContainerSplit::Horizontal => matches!(direction, Direction::Left | Direction::Right),
|
||||
ContainerSplit::Vertical => matches!(direction, Direction::Up | Direction::Down),
|
||||
};
|
||||
if !in_line {
|
||||
self.parent.get().move_focus_from_child(seat, self, direction);
|
||||
return;
|
||||
}
|
||||
let prev = match direction {
|
||||
Direction::Left => true,
|
||||
Direction::Down => false,
|
||||
Direction::Up => true,
|
||||
Direction::Right => false,
|
||||
};
|
||||
let sibling = match prev {
|
||||
true => child.prev(),
|
||||
false => child.next()
|
||||
};
|
||||
let sibling = match sibling {
|
||||
Some(s) => s,
|
||||
None => {
|
||||
self.parent.get().move_focus_from_child(seat, self, direction);
|
||||
return;
|
||||
}
|
||||
};
|
||||
sibling.node.clone().do_focus(seat, direction);
|
||||
}
|
||||
|
||||
fn absolute_position(&self) -> Rect {
|
||||
Rect::new_sized(
|
||||
self.abs_x1.get(),
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ use std::cell::{Cell, RefCell};
|
|||
use std::fmt::{Debug, Display, Formatter};
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
use i4config::Direction;
|
||||
pub use workspace::*;
|
||||
|
||||
mod container;
|
||||
|
|
@ -66,6 +67,22 @@ pub trait Node {
|
|||
fn seat_state(&self) -> &NodeSeatState;
|
||||
fn destroy_node(&self, detach: bool);
|
||||
|
||||
fn do_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, direction: Direction) {
|
||||
let _ = seat;
|
||||
let _ = direction;
|
||||
}
|
||||
|
||||
fn move_focus(&self, seat: &Rc<WlSeatGlobal>, direction: Direction) {
|
||||
let _ = seat;
|
||||
let _ = direction;
|
||||
}
|
||||
|
||||
fn move_focus_from_child(&self, seat: &Rc<WlSeatGlobal>, child: &dyn Node, direction: Direction) {
|
||||
let _ = seat;
|
||||
let _ = direction;
|
||||
let _ = child;
|
||||
}
|
||||
|
||||
fn absolute_position(&self) -> Rect {
|
||||
Rect::new_empty(0, 0)
|
||||
}
|
||||
|
|
@ -78,10 +95,14 @@ pub trait Node {
|
|||
let _ = active;
|
||||
}
|
||||
|
||||
fn key(&self, seat: &WlSeatGlobal, key: u32, state: u32, mods: Option<ModifierState>) {
|
||||
fn key(&self, seat: &WlSeatGlobal, key: u32, state: u32) {
|
||||
let _ = seat;
|
||||
let _ = key;
|
||||
let _ = state;
|
||||
}
|
||||
|
||||
fn mods(&self, seat: &WlSeatGlobal, mods: ModifierState) {
|
||||
let _ = seat;
|
||||
let _ = mods;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use crate::utils::ptr_ext::PtrExt;
|
|||
use crate::NumCell;
|
||||
use std::cell::Cell;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::mem;
|
||||
use std::ops::Deref;
|
||||
use std::ptr::NonNull;
|
||||
|
||||
|
|
@ -153,6 +154,7 @@ impl<T> Drop for RevLinkedListIter<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[repr(transparent)]
|
||||
pub struct LinkedNode<T> {
|
||||
data: NonNull<NodeData<T>>,
|
||||
}
|
||||
|
|
@ -164,13 +166,14 @@ impl<T: Debug> Debug for LinkedNode<T> {
|
|||
}
|
||||
|
||||
impl<T> Deref for LinkedNode<T> {
|
||||
type Target = T;
|
||||
type Target = NodeRef<T>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe { self.data.as_ref().data.as_ref().unwrap_unchecked() }
|
||||
unsafe { mem::transmute(self) }
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(transparent)]
|
||||
pub struct NodeRef<T> {
|
||||
data: NonNull<NodeData<T>>,
|
||||
}
|
||||
|
|
@ -215,10 +218,12 @@ impl<T> NodeRef<T> {
|
|||
unsafe { append(self.data, t) }
|
||||
}
|
||||
|
||||
pub fn prev(&self) -> Option<NodeRef<T>> {
|
||||
fn peer<F>(&self, peer: F) -> Option<NodeRef<T>>
|
||||
where F: FnOnce(&NodeData<T>) -> &Cell<NonNull<NodeData<T>>>,
|
||||
{
|
||||
unsafe {
|
||||
let data = self.data.as_ref();
|
||||
let other = data.prev.get();
|
||||
let other = peer(&data).get();
|
||||
if other.as_ref().data.is_some() {
|
||||
other.as_ref().rc.fetch_add(1);
|
||||
Some(NodeRef { data: other })
|
||||
|
|
@ -227,6 +232,14 @@ impl<T> NodeRef<T> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prev(&self) -> Option<NodeRef<T>> {
|
||||
self.peer(|d| &d.prev)
|
||||
}
|
||||
|
||||
pub fn next(&self) -> Option<NodeRef<T>> {
|
||||
self.peer(|d| &d.next)
|
||||
}
|
||||
}
|
||||
|
||||
struct NodeData<T> {
|
||||
|
|
|
|||
|
|
@ -11,3 +11,4 @@ pub mod ptr_ext;
|
|||
pub mod queue;
|
||||
pub mod smallmap;
|
||||
pub mod vec_ext;
|
||||
pub mod stack;
|
||||
|
|
|
|||
28
src/utils/stack.rs
Normal file
28
src/utils/stack.rs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
use std::cell::UnsafeCell;
|
||||
use crate::utils::ptr_ext::MutPtrExt;
|
||||
|
||||
pub struct Stack<T> {
|
||||
vec: UnsafeCell<Vec<T>>,
|
||||
}
|
||||
|
||||
impl<T> Default for Stack<T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
vec: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Stack<T> {
|
||||
pub fn push(&self, v: T) {
|
||||
unsafe {
|
||||
self.vec.get().deref_mut().push(v);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pop(&self) -> Option<T> {
|
||||
unsafe {
|
||||
self.vec.get().deref_mut().pop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,12 +7,14 @@ include!(concat!(env!("OUT_DIR"), "/xkbcommon_tys.rs"));
|
|||
use bstr::{BStr, ByteSlice};
|
||||
pub use consts::*;
|
||||
use std::ffi::{CStr, VaList};
|
||||
use std::io::Write;
|
||||
use std::ops::Deref;
|
||||
use std::ptr;
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::utils::ptr_ext::PtrExt;
|
||||
use thiserror::Error;
|
||||
use uapi::c;
|
||||
use uapi::{c, OwnedFd};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum XkbCommonError {
|
||||
|
|
@ -20,8 +22,8 @@ pub enum XkbCommonError {
|
|||
CreateContext,
|
||||
#[error("Could not create an xkbcommon state")]
|
||||
CreateState,
|
||||
#[error("Could not create keymap from names")]
|
||||
KeymapFromNames,
|
||||
#[error("Could not create keymap from buffer")]
|
||||
KeymapFromBuffer,
|
||||
#[error("Could not convert the keymap to a string")]
|
||||
AsStr,
|
||||
}
|
||||
|
|
@ -30,6 +32,11 @@ struct xkb_context;
|
|||
struct xkb_keymap;
|
||||
struct xkb_state;
|
||||
|
||||
type xkb_keycode_t = u32;
|
||||
type xkb_layout_index_t = u32;
|
||||
type xkb_level_index_t = u32;
|
||||
type xkb_keysym_t = u32;
|
||||
|
||||
#[repr(C)]
|
||||
struct xkb_rule_names {
|
||||
rules: *const c::c_char,
|
||||
|
|
@ -55,6 +62,7 @@ impl Default for xkb_rule_names {
|
|||
extern "C" {
|
||||
fn xkb_context_new(flags: xkb_context_flags) -> *mut xkb_context;
|
||||
fn xkb_context_unref(context: *mut xkb_context);
|
||||
fn xkb_context_set_log_verbosity(context: *mut xkb_context, verbosity: c::c_int);
|
||||
fn xkb_context_set_log_fn(
|
||||
context: *mut xkb_context,
|
||||
log_fn: unsafe extern "C" fn(
|
||||
|
|
@ -64,9 +72,11 @@ extern "C" {
|
|||
args: VaList,
|
||||
),
|
||||
);
|
||||
fn xkb_keymap_new_from_names(
|
||||
fn xkb_keymap_new_from_buffer(
|
||||
context: *mut xkb_context,
|
||||
name: *const xkb_rule_names,
|
||||
buffer: *const u8,
|
||||
length: usize,
|
||||
format: xkb_keymap_format,
|
||||
flags: xkb_keymap_compile_flags,
|
||||
) -> *mut xkb_keymap;
|
||||
fn xkb_keymap_get_as_string(
|
||||
|
|
@ -74,6 +84,14 @@ extern "C" {
|
|||
format: xkb_keymap_format,
|
||||
) -> *mut c::c_char;
|
||||
fn xkb_keymap_unref(keymap: *mut xkb_keymap);
|
||||
// fn xkb_keymap_ref(keymap: *mut xkb_keymap) -> *mut xkb_keymap;
|
||||
fn xkb_keymap_key_get_syms_by_level(
|
||||
keymap: *mut xkb_keymap,
|
||||
key: xkb_keycode_t,
|
||||
layout: xkb_layout_index_t,
|
||||
level: xkb_level_index_t,
|
||||
syms_out: *mut *const xkb_keysym_t,
|
||||
) -> c::c_int;
|
||||
fn xkb_state_unref(state: *mut xkb_state);
|
||||
fn xkb_state_new(keymap: *mut xkb_keymap) -> *mut xkb_state;
|
||||
#[allow(dead_code)]
|
||||
|
|
@ -99,19 +117,47 @@ impl XkbContext {
|
|||
return Err(XkbCommonError::CreateContext);
|
||||
}
|
||||
unsafe {
|
||||
xkb_context_set_log_verbosity(res, 10);
|
||||
xkb_context_set_log_fn(res, xkbcommon_logger);
|
||||
}
|
||||
Ok(Self { context: res })
|
||||
}
|
||||
|
||||
pub fn default_keymap(&self) -> Result<XkbKeymap, XkbCommonError> {
|
||||
unsafe {
|
||||
let names = Default::default();
|
||||
let keymap = xkb_keymap_new_from_names(self.context, &names, 0);
|
||||
if keymap.is_null() {
|
||||
return Err(XkbCommonError::KeymapFromNames);
|
||||
fn raw_to_map(raw: *mut xkb_keymap) -> Result<Rc<XkbKeymap>, XkbCommonError> {
|
||||
let res =
|
||||
unsafe { xkb_keymap_get_as_string(raw, XKB_KEYMAP_FORMAT_TEXT_V1.raw() as _) };
|
||||
if res.is_null() {
|
||||
unsafe {
|
||||
xkb_keymap_unref(raw);
|
||||
}
|
||||
Ok(XkbKeymap { keymap })
|
||||
return Err(XkbCommonError::AsStr);
|
||||
}
|
||||
let str = XkbKeymapStr {
|
||||
s: unsafe { CStr::from_ptr(res).to_bytes().as_bstr() },
|
||||
};
|
||||
let mut memfd =
|
||||
uapi::memfd_create("keymap", c::MFD_CLOEXEC | c::MFD_ALLOW_SEALING).unwrap();
|
||||
memfd.write_all(str.as_bytes()).unwrap();
|
||||
memfd.write_all(&[0]).unwrap();
|
||||
uapi::lseek(memfd.raw(), 0, c::SEEK_SET).unwrap();
|
||||
uapi::fcntl_add_seals(
|
||||
memfd.raw(),
|
||||
c::F_SEAL_SEAL | c::F_SEAL_GROW | c::F_SEAL_SHRINK | c::F_SEAL_WRITE,
|
||||
).unwrap();
|
||||
Ok(Rc::new(XkbKeymap {
|
||||
keymap: raw,
|
||||
map: Rc::new(memfd),
|
||||
map_len: str.len() + 1,
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn keymap_from_str(&self, s: &str) -> Result<Rc<XkbKeymap>, XkbCommonError> {
|
||||
unsafe {
|
||||
let keymap = xkb_keymap_new_from_buffer(self.context, s.as_bytes().as_ptr(), s.len(), XKB_KEYMAP_FORMAT_TEXT_V1.raw(), 0);
|
||||
if keymap.is_null() {
|
||||
return Err(XkbCommonError::KeymapFromBuffer);
|
||||
}
|
||||
Self::raw_to_map(keymap)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -126,31 +172,24 @@ impl Drop for XkbContext {
|
|||
|
||||
pub struct XkbKeymap {
|
||||
keymap: *mut xkb_keymap,
|
||||
pub map: Rc<OwnedFd>,
|
||||
pub map_len: usize,
|
||||
}
|
||||
|
||||
impl XkbKeymap {
|
||||
pub fn as_str(&self) -> Result<XkbKeymapStr, XkbCommonError> {
|
||||
let res =
|
||||
unsafe { xkb_keymap_get_as_string(self.keymap, XKB_KEYMAP_FORMAT_TEXT_V1.raw() as _) };
|
||||
if res.is_null() {
|
||||
return Err(XkbCommonError::AsStr);
|
||||
}
|
||||
Ok(XkbKeymapStr {
|
||||
s: unsafe { CStr::from_ptr(res).to_bytes().as_bstr() },
|
||||
})
|
||||
}
|
||||
|
||||
pub fn state(&self) -> Result<XkbState, XkbCommonError> {
|
||||
pub fn state(self: &Rc<Self>) -> Result<XkbState, XkbCommonError> {
|
||||
let res = unsafe { xkb_state_new(self.keymap) };
|
||||
if res.is_null() {
|
||||
return Err(XkbCommonError::CreateState);
|
||||
}
|
||||
Ok(XkbState {
|
||||
map: self.clone(),
|
||||
state: res,
|
||||
mods: ModifierState {
|
||||
mods_depressed: 0,
|
||||
mods_latched: 0,
|
||||
mods_locked: 0,
|
||||
mods_effective: 0,
|
||||
group: 0,
|
||||
},
|
||||
})
|
||||
|
|
@ -188,10 +227,12 @@ pub struct ModifierState {
|
|||
pub mods_depressed: u32,
|
||||
pub mods_latched: u32,
|
||||
pub mods_locked: u32,
|
||||
pub mods_effective: u32,
|
||||
pub group: u32,
|
||||
}
|
||||
|
||||
pub struct XkbState {
|
||||
map: Rc<XkbKeymap>,
|
||||
state: *mut xkb_state,
|
||||
mods: ModifierState,
|
||||
}
|
||||
|
|
@ -212,6 +253,8 @@ impl XkbState {
|
|||
xkb_state_serialize_mods(self.state, XKB_STATE_MODS_LATCHED.raw() as _);
|
||||
self.mods.mods_locked =
|
||||
xkb_state_serialize_mods(self.state, XKB_STATE_MODS_LOCKED.raw() as _);
|
||||
self.mods.mods_effective =
|
||||
self.mods.mods_depressed | self.mods.mods_latched | self.mods.mods_locked;
|
||||
self.mods.group =
|
||||
xkb_state_serialize_layout(self.state, XKB_STATE_LAYOUT_EFFECTIVE.raw() as _);
|
||||
Some(self.mods)
|
||||
|
|
@ -220,6 +263,24 @@ impl XkbState {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unmodified_keysyms(&self, key: u32) -> &[xkb_keysym_t] {
|
||||
let mut res = ptr::null();
|
||||
unsafe {
|
||||
let num = xkb_keymap_key_get_syms_by_level(
|
||||
self.map.keymap,
|
||||
key + 8,
|
||||
self.mods.group,
|
||||
0,
|
||||
&mut res,
|
||||
);
|
||||
if num > 0 {
|
||||
std::slice::from_raw_parts(res, num as usize)
|
||||
} else {
|
||||
&[]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for XkbState {
|
||||
|
|
@ -242,10 +303,10 @@ unsafe extern "C" fn xkbcommon_logger(
|
|||
let mut buf = ptr::null_mut();
|
||||
let res = vasprintf(&mut buf, format, args);
|
||||
if res < 0 {
|
||||
log::warn!("Could not vasprintf");
|
||||
log::error!("Could not vasprintf");
|
||||
return;
|
||||
}
|
||||
let buf = std::slice::from_raw_parts(buf as *const u8, res as usize);
|
||||
let buf = buf.as_bstr();
|
||||
let level = match XkbLogLevel(level) {
|
||||
XKB_LOG_LEVEL_CRITICAL | XKB_LOG_LEVEL_ERROR => log::Level::Error,
|
||||
XKB_LOG_LEVEL_WARNING => log::Level::Warn,
|
||||
|
|
@ -253,5 +314,5 @@ unsafe extern "C" fn xkbcommon_logger(
|
|||
XKB_LOG_LEVEL_DEBUG => log::Level::Debug,
|
||||
_ => log::Level::Error,
|
||||
};
|
||||
log::log!(level, "xkbcommon: {}", buf);
|
||||
log::log!(level, "xkbcommon: {}", buf.trim_end().as_bstr());
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue