├── .github └── workflows │ └── rust.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENCE ├── README.md ├── build.rs └── src ├── config ├── check.rs ├── command.rs ├── filehandler.rs ├── keybind.rs ├── layout.rs ├── mod.rs ├── modifier.rs ├── structs.rs └── values.rs ├── main.rs ├── tui ├── key_handler.rs ├── mod.rs └── popups.rs └── utils ├── mod.rs ├── x11_keys.rs └── xkeysym_lookup.rs /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | RUSTFLAGS: -Dwarnings 12 | RUSTDOCFLAGS: -Dwarnings 13 | 14 | 15 | jobs: 16 | build: 17 | 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - uses: actions/checkout@v3 22 | - uses: actions-rs/toolchain@v1 23 | with: 24 | toolchain: stable 25 | override: true 26 | - name: apt update 27 | run: sudo apt update 28 | - name: Build 29 | run: cargo build --verbose 30 | 31 | clippy: 32 | 33 | runs-on: ubuntu-latest 34 | 35 | steps: 36 | - uses: actions/checkout@v3 37 | - uses: actions-rs/toolchain@v1 38 | with: 39 | toolchain: stable 40 | components: clippy 41 | override: true 42 | - name: apt update 43 | run: sudo apt update 44 | - name: Clippy 45 | run: cargo clippy --all-targets 46 | 47 | fmt: 48 | runs-on: ubuntu-latest 49 | 50 | steps: 51 | - uses: actions/checkout@v3 52 | - uses: actions-rs/toolchain@v1 53 | with: 54 | toolchain: stable 55 | components: rustfmt 56 | override: true 57 | - name: fmt 58 | run: cargo fmt -- --check 59 | 60 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | .idea 3 | 4 | /aur 5 | 6 | issue.md 7 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.17.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "anyhow" 22 | version = "1.0.69" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800" 25 | dependencies = [ 26 | "backtrace", 27 | ] 28 | 29 | [[package]] 30 | name = "atty" 31 | version = "0.2.14" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 34 | dependencies = [ 35 | "hermit-abi", 36 | "libc", 37 | "winapi", 38 | ] 39 | 40 | [[package]] 41 | name = "autocfg" 42 | version = "1.1.0" 43 | source = "registry+https://github.com/rust-lang/crates.io-index" 44 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 45 | 46 | [[package]] 47 | name = "backtrace" 48 | version = "0.3.66" 49 | source = "registry+https://github.com/rust-lang/crates.io-index" 50 | checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7" 51 | dependencies = [ 52 | "addr2line", 53 | "cc", 54 | "cfg-if", 55 | "libc", 56 | "miniz_oxide", 57 | "object", 58 | "rustc-demangle", 59 | ] 60 | 61 | [[package]] 62 | name = "base64" 63 | version = "0.13.0" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" 66 | 67 | [[package]] 68 | name = "bitflags" 69 | version = "1.3.2" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 72 | 73 | [[package]] 74 | name = "cassowary" 75 | version = "0.3.0" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" 78 | 79 | [[package]] 80 | name = "cc" 81 | version = "1.0.73" 82 | source = "registry+https://github.com/rust-lang/crates.io-index" 83 | checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" 84 | 85 | [[package]] 86 | name = "cfg-if" 87 | version = "1.0.0" 88 | source = "registry+https://github.com/rust-lang/crates.io-index" 89 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 90 | 91 | [[package]] 92 | name = "clap" 93 | version = "3.2.23" 94 | source = "registry+https://github.com/rust-lang/crates.io-index" 95 | checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" 96 | dependencies = [ 97 | "atty", 98 | "bitflags", 99 | "clap_lex", 100 | "indexmap", 101 | "strsim", 102 | "termcolor", 103 | "textwrap", 104 | ] 105 | 106 | [[package]] 107 | name = "clap_lex" 108 | version = "0.2.4" 109 | source = "registry+https://github.com/rust-lang/crates.io-index" 110 | checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" 111 | dependencies = [ 112 | "os_str_bytes", 113 | ] 114 | 115 | [[package]] 116 | name = "crossterm" 117 | version = "0.25.0" 118 | source = "registry+https://github.com/rust-lang/crates.io-index" 119 | checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67" 120 | dependencies = [ 121 | "bitflags", 122 | "crossterm_winapi", 123 | "libc", 124 | "mio", 125 | "parking_lot", 126 | "signal-hook", 127 | "signal-hook-mio", 128 | "winapi", 129 | ] 130 | 131 | [[package]] 132 | name = "crossterm" 133 | version = "0.26.1" 134 | source = "registry+https://github.com/rust-lang/crates.io-index" 135 | checksum = "a84cda67535339806297f1b331d6dd6320470d2a0fe65381e79ee9e156dd3d13" 136 | dependencies = [ 137 | "bitflags", 138 | "crossterm_winapi", 139 | "libc", 140 | "mio", 141 | "parking_lot", 142 | "signal-hook", 143 | "signal-hook-mio", 144 | "winapi", 145 | ] 146 | 147 | [[package]] 148 | name = "crossterm_winapi" 149 | version = "0.9.0" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c" 152 | dependencies = [ 153 | "winapi", 154 | ] 155 | 156 | [[package]] 157 | name = "dirs" 158 | version = "4.0.0" 159 | source = "registry+https://github.com/rust-lang/crates.io-index" 160 | checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" 161 | dependencies = [ 162 | "dirs-sys", 163 | ] 164 | 165 | [[package]] 166 | name = "dirs-sys" 167 | version = "0.3.7" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" 170 | dependencies = [ 171 | "libc", 172 | "redox_users", 173 | "winapi", 174 | ] 175 | 176 | [[package]] 177 | name = "getrandom" 178 | version = "0.2.6" 179 | source = "registry+https://github.com/rust-lang/crates.io-index" 180 | checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" 181 | dependencies = [ 182 | "cfg-if", 183 | "libc", 184 | "wasi 0.10.2+wasi-snapshot-preview1", 185 | ] 186 | 187 | [[package]] 188 | name = "gimli" 189 | version = "0.26.2" 190 | source = "registry+https://github.com/rust-lang/crates.io-index" 191 | checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" 192 | 193 | [[package]] 194 | name = "git-version" 195 | version = "0.3.5" 196 | source = "registry+https://github.com/rust-lang/crates.io-index" 197 | checksum = "f6b0decc02f4636b9ccad390dcbe77b722a77efedfa393caf8379a51d5c61899" 198 | dependencies = [ 199 | "git-version-macro", 200 | "proc-macro-hack", 201 | ] 202 | 203 | [[package]] 204 | name = "git-version-macro" 205 | version = "0.3.5" 206 | source = "registry+https://github.com/rust-lang/crates.io-index" 207 | checksum = "fe69f1cbdb6e28af2bac214e943b99ce8a0a06b447d15d3e61161b0423139f3f" 208 | dependencies = [ 209 | "proc-macro-hack", 210 | "proc-macro2", 211 | "quote", 212 | "syn", 213 | ] 214 | 215 | [[package]] 216 | name = "glob" 217 | version = "0.3.1" 218 | source = "registry+https://github.com/rust-lang/crates.io-index" 219 | checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" 220 | 221 | [[package]] 222 | name = "hashbrown" 223 | version = "0.12.3" 224 | source = "registry+https://github.com/rust-lang/crates.io-index" 225 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 226 | 227 | [[package]] 228 | name = "hermit-abi" 229 | version = "0.1.19" 230 | source = "registry+https://github.com/rust-lang/crates.io-index" 231 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 232 | dependencies = [ 233 | "libc", 234 | ] 235 | 236 | [[package]] 237 | name = "indexmap" 238 | version = "1.9.1" 239 | source = "registry+https://github.com/rust-lang/crates.io-index" 240 | checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" 241 | dependencies = [ 242 | "autocfg", 243 | "hashbrown", 244 | ] 245 | 246 | [[package]] 247 | name = "itoa" 248 | version = "1.0.1" 249 | source = "registry+https://github.com/rust-lang/crates.io-index" 250 | checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" 251 | 252 | [[package]] 253 | name = "leftwm-config" 254 | version = "0.1.0" 255 | dependencies = [ 256 | "anyhow", 257 | "clap", 258 | "crossterm 0.26.1", 259 | "git-version", 260 | "glob", 261 | "log", 262 | "ron", 263 | "serde", 264 | "serde_json", 265 | "thiserror", 266 | "toml", 267 | "tui", 268 | "xdg", 269 | ] 270 | 271 | [[package]] 272 | name = "libc" 273 | version = "0.2.139" 274 | source = "registry+https://github.com/rust-lang/crates.io-index" 275 | checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" 276 | 277 | [[package]] 278 | name = "lock_api" 279 | version = "0.4.7" 280 | source = "registry+https://github.com/rust-lang/crates.io-index" 281 | checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" 282 | dependencies = [ 283 | "autocfg", 284 | "scopeguard", 285 | ] 286 | 287 | [[package]] 288 | name = "log" 289 | version = "0.4.17" 290 | source = "registry+https://github.com/rust-lang/crates.io-index" 291 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" 292 | dependencies = [ 293 | "cfg-if", 294 | ] 295 | 296 | [[package]] 297 | name = "memchr" 298 | version = "2.5.0" 299 | source = "registry+https://github.com/rust-lang/crates.io-index" 300 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 301 | 302 | [[package]] 303 | name = "miniz_oxide" 304 | version = "0.5.4" 305 | source = "registry+https://github.com/rust-lang/crates.io-index" 306 | checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" 307 | dependencies = [ 308 | "adler", 309 | ] 310 | 311 | [[package]] 312 | name = "mio" 313 | version = "0.8.4" 314 | source = "registry+https://github.com/rust-lang/crates.io-index" 315 | checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" 316 | dependencies = [ 317 | "libc", 318 | "log", 319 | "wasi 0.11.0+wasi-snapshot-preview1", 320 | "windows-sys", 321 | ] 322 | 323 | [[package]] 324 | name = "object" 325 | version = "0.29.0" 326 | source = "registry+https://github.com/rust-lang/crates.io-index" 327 | checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" 328 | dependencies = [ 329 | "memchr", 330 | ] 331 | 332 | [[package]] 333 | name = "os_str_bytes" 334 | version = "6.3.0" 335 | source = "registry+https://github.com/rust-lang/crates.io-index" 336 | checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff" 337 | 338 | [[package]] 339 | name = "parking_lot" 340 | version = "0.12.1" 341 | source = "registry+https://github.com/rust-lang/crates.io-index" 342 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" 343 | dependencies = [ 344 | "lock_api", 345 | "parking_lot_core", 346 | ] 347 | 348 | [[package]] 349 | name = "parking_lot_core" 350 | version = "0.9.3" 351 | source = "registry+https://github.com/rust-lang/crates.io-index" 352 | checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" 353 | dependencies = [ 354 | "cfg-if", 355 | "libc", 356 | "redox_syscall", 357 | "smallvec", 358 | "windows-sys", 359 | ] 360 | 361 | [[package]] 362 | name = "proc-macro-hack" 363 | version = "0.5.19" 364 | source = "registry+https://github.com/rust-lang/crates.io-index" 365 | checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" 366 | 367 | [[package]] 368 | name = "proc-macro2" 369 | version = "1.0.51" 370 | source = "registry+https://github.com/rust-lang/crates.io-index" 371 | checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" 372 | dependencies = [ 373 | "unicode-ident", 374 | ] 375 | 376 | [[package]] 377 | name = "quote" 378 | version = "1.0.17" 379 | source = "registry+https://github.com/rust-lang/crates.io-index" 380 | checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58" 381 | dependencies = [ 382 | "proc-macro2", 383 | ] 384 | 385 | [[package]] 386 | name = "redox_syscall" 387 | version = "0.2.13" 388 | source = "registry+https://github.com/rust-lang/crates.io-index" 389 | checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" 390 | dependencies = [ 391 | "bitflags", 392 | ] 393 | 394 | [[package]] 395 | name = "redox_users" 396 | version = "0.4.3" 397 | source = "registry+https://github.com/rust-lang/crates.io-index" 398 | checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" 399 | dependencies = [ 400 | "getrandom", 401 | "redox_syscall", 402 | "thiserror", 403 | ] 404 | 405 | [[package]] 406 | name = "ron" 407 | version = "0.8.0" 408 | source = "registry+https://github.com/rust-lang/crates.io-index" 409 | checksum = "300a51053b1cb55c80b7a9fde4120726ddf25ca241a1cbb926626f62fb136bff" 410 | dependencies = [ 411 | "base64", 412 | "bitflags", 413 | "serde", 414 | ] 415 | 416 | [[package]] 417 | name = "rustc-demangle" 418 | version = "0.1.21" 419 | source = "registry+https://github.com/rust-lang/crates.io-index" 420 | checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" 421 | 422 | [[package]] 423 | name = "ryu" 424 | version = "1.0.9" 425 | source = "registry+https://github.com/rust-lang/crates.io-index" 426 | checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" 427 | 428 | [[package]] 429 | name = "scopeguard" 430 | version = "1.1.0" 431 | source = "registry+https://github.com/rust-lang/crates.io-index" 432 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 433 | 434 | [[package]] 435 | name = "serde" 436 | version = "1.0.152" 437 | source = "registry+https://github.com/rust-lang/crates.io-index" 438 | checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" 439 | dependencies = [ 440 | "serde_derive", 441 | ] 442 | 443 | [[package]] 444 | name = "serde_derive" 445 | version = "1.0.152" 446 | source = "registry+https://github.com/rust-lang/crates.io-index" 447 | checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" 448 | dependencies = [ 449 | "proc-macro2", 450 | "quote", 451 | "syn", 452 | ] 453 | 454 | [[package]] 455 | name = "serde_json" 456 | version = "1.0.94" 457 | source = "registry+https://github.com/rust-lang/crates.io-index" 458 | checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea" 459 | dependencies = [ 460 | "itoa", 461 | "ryu", 462 | "serde", 463 | ] 464 | 465 | [[package]] 466 | name = "serde_spanned" 467 | version = "0.6.1" 468 | source = "registry+https://github.com/rust-lang/crates.io-index" 469 | checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4" 470 | dependencies = [ 471 | "serde", 472 | ] 473 | 474 | [[package]] 475 | name = "signal-hook" 476 | version = "0.3.13" 477 | source = "registry+https://github.com/rust-lang/crates.io-index" 478 | checksum = "647c97df271007dcea485bb74ffdb57f2e683f1306c854f468a0c244badabf2d" 479 | dependencies = [ 480 | "libc", 481 | "signal-hook-registry", 482 | ] 483 | 484 | [[package]] 485 | name = "signal-hook-mio" 486 | version = "0.2.3" 487 | source = "registry+https://github.com/rust-lang/crates.io-index" 488 | checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" 489 | dependencies = [ 490 | "libc", 491 | "mio", 492 | "signal-hook", 493 | ] 494 | 495 | [[package]] 496 | name = "signal-hook-registry" 497 | version = "1.4.0" 498 | source = "registry+https://github.com/rust-lang/crates.io-index" 499 | checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" 500 | dependencies = [ 501 | "libc", 502 | ] 503 | 504 | [[package]] 505 | name = "smallvec" 506 | version = "1.8.0" 507 | source = "registry+https://github.com/rust-lang/crates.io-index" 508 | checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" 509 | 510 | [[package]] 511 | name = "strsim" 512 | version = "0.10.0" 513 | source = "registry+https://github.com/rust-lang/crates.io-index" 514 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 515 | 516 | [[package]] 517 | name = "syn" 518 | version = "1.0.109" 519 | source = "registry+https://github.com/rust-lang/crates.io-index" 520 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 521 | dependencies = [ 522 | "proc-macro2", 523 | "quote", 524 | "unicode-ident", 525 | ] 526 | 527 | [[package]] 528 | name = "termcolor" 529 | version = "1.1.3" 530 | source = "registry+https://github.com/rust-lang/crates.io-index" 531 | checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" 532 | dependencies = [ 533 | "winapi-util", 534 | ] 535 | 536 | [[package]] 537 | name = "textwrap" 538 | version = "0.16.0" 539 | source = "registry+https://github.com/rust-lang/crates.io-index" 540 | checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" 541 | 542 | [[package]] 543 | name = "thiserror" 544 | version = "1.0.39" 545 | source = "registry+https://github.com/rust-lang/crates.io-index" 546 | checksum = "a5ab016db510546d856297882807df8da66a16fb8c4101cb8b30054b0d5b2d9c" 547 | dependencies = [ 548 | "thiserror-impl", 549 | ] 550 | 551 | [[package]] 552 | name = "thiserror-impl" 553 | version = "1.0.39" 554 | source = "registry+https://github.com/rust-lang/crates.io-index" 555 | checksum = "5420d42e90af0c38c3290abcca25b9b3bdf379fc9f55c528f53a269d9c9a267e" 556 | dependencies = [ 557 | "proc-macro2", 558 | "quote", 559 | "syn", 560 | ] 561 | 562 | [[package]] 563 | name = "toml" 564 | version = "0.7.2" 565 | source = "registry+https://github.com/rust-lang/crates.io-index" 566 | checksum = "f7afcae9e3f0fe2c370fd4657108972cbb2fa9db1b9f84849cefd80741b01cb6" 567 | dependencies = [ 568 | "serde", 569 | "serde_spanned", 570 | "toml_datetime", 571 | "toml_edit", 572 | ] 573 | 574 | [[package]] 575 | name = "toml_datetime" 576 | version = "0.6.1" 577 | source = "registry+https://github.com/rust-lang/crates.io-index" 578 | checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" 579 | dependencies = [ 580 | "serde", 581 | ] 582 | 583 | [[package]] 584 | name = "toml_edit" 585 | version = "0.19.4" 586 | source = "registry+https://github.com/rust-lang/crates.io-index" 587 | checksum = "9a1eb0622d28f4b9c90adc4ea4b2b46b47663fde9ac5fafcb14a1369d5508825" 588 | dependencies = [ 589 | "indexmap", 590 | "serde", 591 | "serde_spanned", 592 | "toml_datetime", 593 | "winnow", 594 | ] 595 | 596 | [[package]] 597 | name = "tui" 598 | version = "0.19.0" 599 | source = "registry+https://github.com/rust-lang/crates.io-index" 600 | checksum = "ccdd26cbd674007e649a272da4475fb666d3aa0ad0531da7136db6fab0e5bad1" 601 | dependencies = [ 602 | "bitflags", 603 | "cassowary", 604 | "crossterm 0.25.0", 605 | "unicode-segmentation", 606 | "unicode-width", 607 | ] 608 | 609 | [[package]] 610 | name = "unicode-ident" 611 | version = "1.0.8" 612 | source = "registry+https://github.com/rust-lang/crates.io-index" 613 | checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" 614 | 615 | [[package]] 616 | name = "unicode-segmentation" 617 | version = "1.9.0" 618 | source = "registry+https://github.com/rust-lang/crates.io-index" 619 | checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" 620 | 621 | [[package]] 622 | name = "unicode-width" 623 | version = "0.1.9" 624 | source = "registry+https://github.com/rust-lang/crates.io-index" 625 | checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" 626 | 627 | [[package]] 628 | name = "wasi" 629 | version = "0.10.2+wasi-snapshot-preview1" 630 | source = "registry+https://github.com/rust-lang/crates.io-index" 631 | checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" 632 | 633 | [[package]] 634 | name = "wasi" 635 | version = "0.11.0+wasi-snapshot-preview1" 636 | source = "registry+https://github.com/rust-lang/crates.io-index" 637 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 638 | 639 | [[package]] 640 | name = "winapi" 641 | version = "0.3.9" 642 | source = "registry+https://github.com/rust-lang/crates.io-index" 643 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 644 | dependencies = [ 645 | "winapi-i686-pc-windows-gnu", 646 | "winapi-x86_64-pc-windows-gnu", 647 | ] 648 | 649 | [[package]] 650 | name = "winapi-i686-pc-windows-gnu" 651 | version = "0.4.0" 652 | source = "registry+https://github.com/rust-lang/crates.io-index" 653 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 654 | 655 | [[package]] 656 | name = "winapi-util" 657 | version = "0.1.5" 658 | source = "registry+https://github.com/rust-lang/crates.io-index" 659 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 660 | dependencies = [ 661 | "winapi", 662 | ] 663 | 664 | [[package]] 665 | name = "winapi-x86_64-pc-windows-gnu" 666 | version = "0.4.0" 667 | source = "registry+https://github.com/rust-lang/crates.io-index" 668 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 669 | 670 | [[package]] 671 | name = "windows-sys" 672 | version = "0.36.1" 673 | source = "registry+https://github.com/rust-lang/crates.io-index" 674 | checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" 675 | dependencies = [ 676 | "windows_aarch64_msvc", 677 | "windows_i686_gnu", 678 | "windows_i686_msvc", 679 | "windows_x86_64_gnu", 680 | "windows_x86_64_msvc", 681 | ] 682 | 683 | [[package]] 684 | name = "windows_aarch64_msvc" 685 | version = "0.36.1" 686 | source = "registry+https://github.com/rust-lang/crates.io-index" 687 | checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" 688 | 689 | [[package]] 690 | name = "windows_i686_gnu" 691 | version = "0.36.1" 692 | source = "registry+https://github.com/rust-lang/crates.io-index" 693 | checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" 694 | 695 | [[package]] 696 | name = "windows_i686_msvc" 697 | version = "0.36.1" 698 | source = "registry+https://github.com/rust-lang/crates.io-index" 699 | checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" 700 | 701 | [[package]] 702 | name = "windows_x86_64_gnu" 703 | version = "0.36.1" 704 | source = "registry+https://github.com/rust-lang/crates.io-index" 705 | checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" 706 | 707 | [[package]] 708 | name = "windows_x86_64_msvc" 709 | version = "0.36.1" 710 | source = "registry+https://github.com/rust-lang/crates.io-index" 711 | checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" 712 | 713 | [[package]] 714 | name = "winnow" 715 | version = "0.3.5" 716 | source = "registry+https://github.com/rust-lang/crates.io-index" 717 | checksum = "ee7b2c67f962bf5042bfd8b6a916178df33a26eec343ae064cb8e069f638fa6f" 718 | dependencies = [ 719 | "memchr", 720 | ] 721 | 722 | [[package]] 723 | name = "xdg" 724 | version = "2.4.1" 725 | source = "registry+https://github.com/rust-lang/crates.io-index" 726 | checksum = "0c4583db5cbd4c4c0303df2d15af80f0539db703fa1c68802d4cbbd2dd0f88f6" 727 | dependencies = [ 728 | "dirs", 729 | ] 730 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "leftwm-config" 3 | version = "0.1.0" 4 | authors = ["BlackDragon2447 "] 5 | edition = "2021" 6 | license = "MIT" 7 | readme = "README.md" 8 | #description = "A window manager for Adventurers" 9 | 10 | [dependencies] 11 | anyhow = {version="1.0.69", features=["backtrace"]} 12 | clap = "3.2.22" 13 | # clap = "4.1.0" 14 | xdg = "2.4.1" 15 | serde = { version = "1.0.152", features = ["derive", "rc"] } 16 | ron = "0.8.0" 17 | serde_json = "1.0.94" 18 | log = "0.4.17" 19 | git-version = "0.3.5" 20 | thiserror = "1.0.39" 21 | tui = "0.19.0" 22 | crossterm = "0.26.1" 23 | glob = "0.3.1" 24 | toml = "0.7.2" 25 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2021, leftwm 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LeftWM Config 2 | 3 | This is a little satellite utility to LeftWM. 4 | 5 | It serves these main purposes: 6 | - create a default config file in `$HOME/.config/leftwm/config.ron` 7 | - migrate legacy `toml` config files to the new stander `ron` 8 | - edit the config with a TUI 9 | 10 | For usage please refer to `leftwm-config --help` for now. 11 | 12 | *Note: this tool is BETA software, so expect some kinks and wrinkles here and there.* 13 | 14 | To install... 15 | 16 | ``` 17 | git clone https://github.com/leftwm/leftwm-config.git && 18 | cd leftwm-config && 19 | cargo build --release && 20 | sudo ln -s "$(pwd)"/target/release/leftwm-config /usr/bin/leftwm-config ## Dev Install 21 | sudo cp "$(pwd)"/target/release/leftwm-config /usr/bin/leftwm-config ## Normal Install 22 | ``` 23 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | #[cfg(debug_assertions)] 3 | println!("cargo:warning=leftwm-config is being build in debug mode, if build in debug mode leftwm-config will work with a `test_config.ron` (or .toml) file, build in release mode to work with `config.ron`"); 4 | } 5 | -------------------------------------------------------------------------------- /src/config/check.rs: -------------------------------------------------------------------------------- 1 | use crate::config; 2 | use crate::config::Config; 3 | use crate::config::{all_ids_some, all_ids_unique, get_workspace_ids}; 4 | use anyhow::bail; 5 | use anyhow::{Error, Result}; 6 | use std::collections::HashSet; 7 | use std::process::{Command, Stdio}; 8 | use std::{env, fs}; 9 | 10 | pub fn check_config(path: Option<&str>, verbose: bool) -> Result<()> { 11 | println!( 12 | "\x1b[0;94m::\x1b[0m LeftWM Config version: {}", 13 | std::env::var("CARGO_PKG_VERSON").unwrap_or("unknown".to_string()) 14 | ); 15 | println!( 16 | "\x1b[0;94m::\x1b[0m LeftWM git hash: {}", 17 | option_env!("GIT_HASH").unwrap_or(git_version::git_version!(fallback = "unknown")) 18 | ); 19 | println!("\x1b[0;94m::\x1b[0m Loading configuration . . ."); 20 | match config::filehandler::load_from_file(path, verbose) { 21 | Ok(config) => { 22 | println!("\x1b[0;92m -> Configuration loaded OK \x1b[0m"); 23 | if verbose { 24 | dbg!(&config); 25 | } 26 | config.check_mousekey(verbose); 27 | config.check_workspace_ids(verbose); 28 | config.check_keybinds(verbose); 29 | } 30 | Err(e) => { 31 | println!("Configuration failed. Reason: {:?}", e); 32 | bail!("Configuration failed. Reason: {:?}", e); 33 | } 34 | } 35 | println!("\x1b[0;94m::\x1b[0m Checking environment . . ."); 36 | check_elogind(verbose)?; 37 | 38 | Ok(()) 39 | } 40 | 41 | impl Config { 42 | pub fn check_mousekey(&self, verbose: bool) { 43 | if verbose { 44 | println!("Checking if mousekey is set."); 45 | } 46 | if let Some(mousekey) = &self.mousekey { 47 | if verbose { 48 | println!("Mousekey is set."); 49 | } 50 | if mousekey.is_empty() { 51 | println!("Your mousekey is set to nothing, this will cause windows to move/resize with just a mouse press."); 52 | return; 53 | } 54 | if verbose { 55 | println!("Mousekey is okay."); 56 | } 57 | } 58 | } 59 | 60 | /// Checks defined workspaces to ensure no ID collisions occur. 61 | pub fn check_workspace_ids(&self, verbose: bool) { 62 | if let Some(wss) = self.workspaces.as_ref() { 63 | if verbose { 64 | println!("Checking config for valid workspace definitions."); 65 | } 66 | let ids = get_workspace_ids(wss); 67 | if ids.iter().any(std::option::Option::is_some) { 68 | if all_ids_some(&ids) { 69 | if !all_ids_unique(&ids) { 70 | println!("Your config.toml contains duplicate workspace IDs. Please assign unique IDs to workspaces. The default config will be used instead."); 71 | } 72 | } else { 73 | println!("Your config.toml specifies an ID for some but not all workspaces. This can lead to ID collisions and is not allowed. The default config will be used instead."); 74 | } 75 | } 76 | } 77 | } 78 | 79 | /// Check all keybinds to ensure that required values are provided 80 | /// Checks to see if value is provided (if required) 81 | /// Checks to see if keys are valid against Xkeysym 82 | /// Ideally, we will pass this to the command handler with a dummy config 83 | pub fn check_keybinds(&self, verbose: bool) { 84 | let mut returns = Vec::new(); 85 | println!("\x1b[0;94m::\x1b[0m Checking keybinds . . ."); 86 | let mut bindings = HashSet::new(); 87 | for keybind in &self.keybind { 88 | if verbose { 89 | println!("Keybind: {:?} {}", keybind, keybind.value.is_empty()); 90 | } 91 | if let Err(err) = keybind.try_convert_to_core_keybind(self) { 92 | returns.push((Some(keybind.clone()), err.to_string())); 93 | } 94 | if crate::utils::xkeysym_lookup::into_keysym(&keybind.key).is_none() { 95 | returns.push(( 96 | Some(keybind.clone()), 97 | format!("Key `{}` is not valid", keybind.key), 98 | )); 99 | } 100 | 101 | let mut modkey = keybind.modifier.as_ref().unwrap_or(&"None".into()).clone(); 102 | for m in &modkey.clone() { 103 | if m != "modkey" 104 | && m != "mousekey" 105 | && crate::utils::xkeysym_lookup::into_mod(&m) == 0 106 | { 107 | returns.push(( 108 | Some(keybind.clone()), 109 | format!("Modifier `{}` is not valid", m), 110 | )); 111 | } 112 | } 113 | 114 | modkey.sort_unstable(); 115 | if let Some(conflict_key) = bindings.replace((modkey.clone(), &keybind.key)) { 116 | returns.push(( 117 | None, 118 | format!( 119 | "\x1b[0m\x1b[1mMultiple commands bound to key combination {} + {}:\ 120 | \n\x1b[1;91m -> {:?}\ 121 | \n -> {:?}\ 122 | \n\x1b[0mHelp: change one of the keybindings to something else.\n", 123 | modkey, keybind.key, conflict_key, keybind.command, 124 | ), 125 | )); 126 | } 127 | } 128 | if returns.is_empty() { 129 | println!("\x1b[0;92m -> All keybinds OK\x1b[0m"); 130 | } else { 131 | for error in returns { 132 | match error.0 { 133 | Some(binding) => { 134 | println!( 135 | "\x1b[1;91mERROR: {} for keybind {:?}\x1b[0m", 136 | error.1, binding 137 | ); 138 | } 139 | None => { 140 | println!("\x1b[1;91mERROR: {} \x1b[0m", error.1); 141 | } 142 | } 143 | } 144 | } 145 | } 146 | } 147 | 148 | fn check_elogind(verbose: bool) -> Result<()> { 149 | // We assume that if it is in the path it's all good 150 | // We also cross-reference the ENV variable 151 | match ( 152 | std::env::var("XDG_RUNTIME_DIR"), 153 | is_program_in_path("loginctl"), 154 | ) { 155 | (Ok(val), true) => { 156 | if verbose { 157 | println!(":: XDG_RUNTIME_DIR: {}, LOGINCTL OKAY", val); 158 | } 159 | 160 | println!("\x1b[0;92m -> Environment OK \x1b[0m"); 161 | 162 | Ok(()) 163 | } 164 | (Ok(val), false) => { 165 | if verbose { 166 | println!(":: XDG_RUNTIME_DIR: {}, LOGINCTL not installed", val); 167 | } 168 | 169 | println!("\x1b[0;92m -> Environment OK (has XDG_RUNTIME_DIR) \x1b[0m"); 170 | 171 | Ok(()) 172 | } 173 | (Err(e), false) => { 174 | if verbose { 175 | println!(":: XDG_RUNTIME_DIR_ERROR: {:?}, LOGINCTL BAD", e); 176 | } 177 | 178 | bail!( 179 | "Elogind not installed/operating and no alternative XDG_RUNTIME_DIR is set. \ 180 | See https://github.com/leftwm/leftwm/wiki/XDG_RUNTIME_DIR for more information." 181 | ); 182 | } 183 | (Err(e), true) => { 184 | if verbose { 185 | println!(":: XDG_RUNTIME_DIR: {:?}, LOGINCTL OKAY", e); 186 | } 187 | println!( 188 | "\x1b[1;93mWARN: Elogind/systemd installed but XDG_RUNTIME_DIR not set.\nThis may be because elogind isn't started. \x1b[0m", 189 | ); 190 | Ok(()) 191 | } 192 | } 193 | } 194 | 195 | #[must_use] 196 | fn is_program_in_path(program: &str) -> bool { 197 | if let Ok(path) = env::var("PATH") { 198 | for p in path.split(':') { 199 | let p_str = format!("{}/{}", p, program); 200 | if fs::metadata(p_str).is_ok() { 201 | return true; 202 | } 203 | } 204 | } 205 | false 206 | } 207 | -------------------------------------------------------------------------------- /src/config/command.rs: -------------------------------------------------------------------------------- 1 | use crate::config::values::WindowHandle; 2 | use crate::config::Layout; 3 | use serde::{Deserialize, Serialize}; 4 | 5 | #[allow(clippy::module_name_repetitions)] 6 | #[derive(Debug, Serialize, Default, Deserialize, Clone, PartialEq, Eq, Hash)] 7 | pub enum BaseCommand { 8 | #[default] 9 | Execute, 10 | CloseWindow, 11 | SwapTags, 12 | SoftReload, 13 | HardReload, 14 | ToggleScratchPad, 15 | ToggleFullScreen, 16 | ToggleSticky, 17 | GotoTag, 18 | ReturnToLastTag, 19 | FloatingToTile, 20 | TileToFloating, 21 | ToggleFloating, 22 | MoveWindowUp, 23 | MoveWindowDown, 24 | MoveWindowTop, 25 | FocusNextTag, 26 | FocusPreviousTag, 27 | FocusWindow, 28 | FocusWindowUp, 29 | FocusWindowDown, 30 | FocusWindowTop, 31 | FocusWorkspaceNext, 32 | FocusWorkspacePrevious, 33 | MoveToTag, 34 | MoveToLastWorkspace, 35 | MoveWindowToNextWorkspace, 36 | MoveWindowToPreviousWorkspace, 37 | MouseMoveWindow, 38 | NextLayout, 39 | PreviousLayout, 40 | SetLayout, 41 | RotateTag, 42 | IncreaseMainWidth, 43 | DecreaseMainWidth, 44 | SetMarginMultiplier, 45 | // Custom commands 46 | UnloadTheme, 47 | LoadTheme, 48 | CloseAllOtherWindows, 49 | } 50 | 51 | impl BaseCommand { 52 | pub fn needs_value(&self) -> bool { 53 | match self { 54 | BaseCommand::Execute => true, 55 | BaseCommand::CloseWindow => false, 56 | BaseCommand::SwapTags => false, 57 | BaseCommand::SoftReload => false, 58 | BaseCommand::HardReload => false, 59 | BaseCommand::ToggleScratchPad => true, 60 | BaseCommand::ToggleFullScreen => false, 61 | BaseCommand::ToggleSticky => false, 62 | BaseCommand::GotoTag => true, 63 | BaseCommand::ReturnToLastTag => false, 64 | BaseCommand::FloatingToTile => false, 65 | BaseCommand::TileToFloating => false, 66 | BaseCommand::ToggleFloating => false, 67 | BaseCommand::MoveWindowUp => false, 68 | BaseCommand::MoveWindowDown => false, 69 | BaseCommand::MoveWindowTop => false, 70 | BaseCommand::FocusNextTag => false, 71 | BaseCommand::FocusPreviousTag => false, 72 | BaseCommand::FocusWindow => false, 73 | BaseCommand::FocusWindowUp => false, 74 | BaseCommand::FocusWindowDown => false, 75 | BaseCommand::FocusWindowTop => false, 76 | BaseCommand::FocusWorkspaceNext => false, 77 | BaseCommand::FocusWorkspacePrevious => false, 78 | BaseCommand::MoveToTag => true, 79 | BaseCommand::MoveToLastWorkspace => false, 80 | BaseCommand::MoveWindowToNextWorkspace => false, 81 | BaseCommand::MoveWindowToPreviousWorkspace => false, 82 | BaseCommand::MouseMoveWindow => false, 83 | BaseCommand::NextLayout => false, 84 | BaseCommand::PreviousLayout => false, 85 | BaseCommand::SetLayout => true, 86 | BaseCommand::RotateTag => false, 87 | BaseCommand::IncreaseMainWidth => true, 88 | BaseCommand::DecreaseMainWidth => true, 89 | BaseCommand::SetMarginMultiplier => true, 90 | // 91 | BaseCommand::UnloadTheme => true, 92 | BaseCommand::LoadTheme => true, 93 | BaseCommand::CloseAllOtherWindows => false, 94 | } 95 | } 96 | } 97 | 98 | pub type TagId = usize; 99 | 100 | #[allow(dead_code)] 101 | pub enum CoreCommand { 102 | Execute(String), 103 | CloseWindow, 104 | SwapScreens, 105 | SoftReload, 106 | HardReload, 107 | ToggleScratchPad(String), 108 | ToggleFullScreen, 109 | ToggleSticky, 110 | GoToTag { 111 | tag: TagId, 112 | swap: bool, 113 | }, 114 | ReturnToLastTag, 115 | FloatingToTile, 116 | TileToFloating, 117 | ToggleFloating, 118 | MoveWindowUp, 119 | MoveWindowDown, 120 | MoveWindowTop { 121 | swap: bool, 122 | }, 123 | FocusNextTag, 124 | FocusPreviousTag, 125 | FocusWindow(String), 126 | FocusWindowUp, 127 | FocusWindowDown, 128 | FocusWindowTop { 129 | swap: bool, 130 | }, 131 | FocusWorkspaceNext, 132 | FocusWorkspacePrevious, 133 | SendWindowToTag { 134 | window: Option, 135 | tag: TagId, 136 | }, 137 | MoveWindowToLastWorkspace, 138 | MoveWindowToNextWorkspace, 139 | MoveWindowToPreviousWorkspace, 140 | MouseMoveWindow, 141 | NextLayout, 142 | PreviousLayout, 143 | SetLayout(Layout), 144 | RotateTag, 145 | IncreaseMainWidth(i8), 146 | DecreaseMainWidth(i8), 147 | SetMarginMultiplier(f32), 148 | SendWorkspaceToTag(usize, usize), 149 | CloseAllOtherWindows, 150 | Other(String), 151 | } 152 | -------------------------------------------------------------------------------- /src/config/filehandler.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | use std::fs::File; 3 | use std::io::Write; 4 | use std::path::{Path, PathBuf}; 5 | 6 | use anyhow::Result; 7 | use xdg::BaseDirectories; 8 | 9 | use crate::config::Config; 10 | 11 | #[must_use] 12 | pub fn load() -> Config { 13 | load_from_file(None, false) 14 | .map_err(|err| eprintln!("ERROR LOADING CONFIG: {:?}", err)) 15 | .unwrap_or_default() 16 | } 17 | 18 | /// Loads configuration from either specified file (preferred) or default. 19 | /// # Errors 20 | /// 21 | /// Errors if file cannot be read. Indicates filesystem error 22 | /// (inadequate permissions, disk full, etc.) 23 | /// If a path is specified and does not exist, returns `LeftError`. 24 | pub fn load_from_file(fspath: Option<&str>, verbose: bool) -> Result { 25 | let config_filename = if let Some(fspath) = fspath { 26 | println!("\x1b[1;35mNote: Using file {} \x1b[0m", fspath); 27 | PathBuf::from(fspath) 28 | } else { 29 | let ron_file = BaseDirectories::with_prefix("leftwm")? 30 | .place_config_file(crate::CONFIG_NAME.to_string() + ".ron")?; 31 | let toml_file = BaseDirectories::with_prefix("leftwm")? 32 | .place_config_file(crate::CONFIG_NAME.to_string() + ".toml")?; 33 | if Path::new(&ron_file).exists() { 34 | ron_file 35 | } else if Path::new(&toml_file).exists() { 36 | println!( 37 | "\x1b[1;93mWARN: TOML as config format is about to be deprecated. 38 | Please consider migrating to RON manually or by using `leftwm-check -m`.\x1b[0m" 39 | ); 40 | toml_file 41 | } else { 42 | let config = Config::default(); 43 | write_to_file(&ron_file, &config)?; 44 | return Ok(config); 45 | } 46 | }; 47 | if verbose { 48 | dbg!(&config_filename); 49 | } 50 | let contents = fs::read_to_string(&config_filename)?; 51 | if verbose { 52 | dbg!(&contents); 53 | } 54 | if config_filename.as_path().extension() == Some(std::ffi::OsStr::new("ron")) { 55 | let config = ron::from_str(&contents)?; 56 | Ok(config) 57 | } else { 58 | let config = toml::from_str(&contents)?; 59 | Ok(config) 60 | } 61 | } 62 | 63 | pub fn get_config_file() -> Result { 64 | let ron_file = BaseDirectories::with_prefix("leftwm")? 65 | .place_config_file(crate::CONFIG_NAME.to_string() + ".ron")?; 66 | let toml_file = BaseDirectories::with_prefix("leftwm")? 67 | .place_config_file(crate::CONFIG_NAME.to_string() + ".toml")?; 68 | if Path::new(&ron_file).exists() { 69 | Ok(ron_file) 70 | } else if Path::new(&toml_file).exists() { 71 | println!( 72 | "\x1b[1;93mWARN: TOML as config format is about to be deprecated. 73 | Please consider migrating to RON manually or by using `leftwm-config --migrate`.\x1b[0m" 74 | ); 75 | Ok(toml_file) 76 | } else { 77 | let config = Config::default(); 78 | write_to_file(&ron_file, &config)?; 79 | Ok(ron_file) 80 | } 81 | } 82 | 83 | pub fn save_to_file(config: &Config) -> Result<()> { 84 | write_to_file( 85 | &BaseDirectories::with_prefix("leftwm")? 86 | .place_config_file(crate::CONFIG_NAME.to_string() + ".ron")?, 87 | config, 88 | ) 89 | } 90 | 91 | pub fn write_to_file(ron_file: &PathBuf, config: &Config) -> Result<(), anyhow::Error> { 92 | let ron_pretty_conf = ron::ser::PrettyConfig::new() 93 | .depth_limit(2) 94 | .extensions(ron::extensions::Extensions::IMPLICIT_SOME); 95 | let ron = ron::ser::to_string_pretty(&config, ron_pretty_conf)?; 96 | let comment_header = String::from( 97 | r#"// _ ___ ___ _ 98 | // | | / __)_ / __|_) 99 | // | | ____| |__| |_ _ _ _ ____ ____ ___ ____ | |__ _ ____ ____ ___ ____ 100 | // | |/ _ ) __) _) | | | \ / ___) _ \| _ \| __) |/ _ | / ___) _ \| _ \ 101 | // | ( (/ /| | | |_| | | | | | | ( (__| |_| | | | | | | ( ( | |_| | | |_| | | | | 102 | // |_|\____)_| \___)____|_|_|_| \____)___/|_| |_|_| |_|\_|| (_)_| \___/|_| |_| 103 | // A WindowManager for Adventurers (____/ 104 | // For info about configuration please visit https://github.com/leftwm/leftwm/wiki 105 | "#, 106 | ); 107 | let ron_with_header = comment_header + &ron; 108 | let mut file = File::create(ron_file)?; 109 | file.write_all(ron_with_header.as_bytes())?; 110 | Ok(()) 111 | } 112 | 113 | pub fn generate_new_config() -> Result<()> { 114 | let file = BaseDirectories::with_prefix("leftwm")? 115 | .place_config_file(crate::CONFIG_NAME.to_string() + ".ron")?; 116 | 117 | if file.exists() { 118 | println!( 119 | "\x1b[0;94m::\x1b[0m A config file already exists, do you want to override it? [y/N]" 120 | ); 121 | let mut line = String::new(); 122 | let _ = std::io::stdin() 123 | .read_line(&mut line) 124 | .expect("Failed to read line"); 125 | if line.contains('y') || line.contains('Y') { 126 | let config = Config::default(); 127 | let ron_pretty_conf = ron::ser::PrettyConfig::new() 128 | .depth_limit(2) 129 | .extensions(ron::extensions::Extensions::IMPLICIT_SOME); 130 | let text = ron::ser::to_string_pretty(&config, ron_pretty_conf)?; 131 | let mut file = File::create(&file)?; 132 | file.write_all(text.as_bytes())?; 133 | } 134 | } 135 | 136 | Ok(()) 137 | } 138 | -------------------------------------------------------------------------------- /src/config/keybind.rs: -------------------------------------------------------------------------------- 1 | use crate::config::command::{BaseCommand, CoreCommand}; 2 | use crate::config::layout::Layout; 3 | use crate::config::modifier::Modifier; 4 | use crate::config::Config; 5 | use anyhow::ensure; 6 | use anyhow::{Context, Result}; 7 | use serde::{Deserialize, Serialize}; 8 | use std::str::FromStr; 9 | 10 | #[derive(Serialize, Default, Deserialize, Debug, Clone)] 11 | pub struct Keybind { 12 | pub command: BaseCommand, 13 | #[serde(default)] 14 | pub value: String, 15 | pub modifier: Option, 16 | pub key: String, 17 | } 18 | 19 | pub struct CoreKeybind { 20 | pub command: CoreCommand, 21 | pub modifier: Vec, 22 | pub key: String, 23 | } 24 | 25 | macro_rules! ensure_non_empty { 26 | ($value:expr) => {{ 27 | ensure!(!$value.is_empty(), "value must not be empty"); 28 | $value 29 | }}; 30 | } 31 | 32 | impl Keybind { 33 | pub fn try_convert_to_core_keybind(&self, config: &Config) -> Result { 34 | let command = match &self.command { 35 | BaseCommand::Execute => CoreCommand::Execute(ensure_non_empty!(self.value.clone())), 36 | BaseCommand::CloseWindow => CoreCommand::CloseWindow, 37 | BaseCommand::SwapTags => CoreCommand::SwapScreens, 38 | BaseCommand::SoftReload => CoreCommand::SoftReload, 39 | BaseCommand::HardReload => CoreCommand::HardReload, 40 | BaseCommand::ToggleScratchPad => { 41 | CoreCommand::ToggleScratchPad(ensure_non_empty!(self.value.clone())) 42 | } 43 | BaseCommand::ToggleFullScreen => CoreCommand::ToggleFullScreen, 44 | BaseCommand::ToggleSticky => CoreCommand::ToggleSticky, 45 | BaseCommand::GotoTag => CoreCommand::GoToTag { 46 | tag: usize::from_str(&self.value).context("invalid index value for GotoTag")?, 47 | swap: !config.disable_current_tag_swap, 48 | }, 49 | BaseCommand::ReturnToLastTag => CoreCommand::ReturnToLastTag, 50 | BaseCommand::FloatingToTile => CoreCommand::FloatingToTile, 51 | BaseCommand::TileToFloating => CoreCommand::TileToFloating, 52 | BaseCommand::ToggleFloating => CoreCommand::ToggleFloating, 53 | BaseCommand::MoveWindowUp => CoreCommand::MoveWindowUp, 54 | BaseCommand::MoveWindowDown => CoreCommand::MoveWindowDown, 55 | BaseCommand::MoveWindowTop => CoreCommand::MoveWindowTop { 56 | swap: if self.value.is_empty() { 57 | true 58 | } else { 59 | bool::from_str(&self.value) 60 | .context("invalid boolean value for MoveWindowTop")? 61 | }, 62 | }, 63 | BaseCommand::FocusNextTag => CoreCommand::FocusNextTag, 64 | BaseCommand::FocusPreviousTag => CoreCommand::FocusPreviousTag, 65 | BaseCommand::FocusWindow => CoreCommand::FocusWindow(self.value.clone()), 66 | BaseCommand::FocusWindowUp => CoreCommand::FocusWindowUp, 67 | BaseCommand::FocusWindowDown => CoreCommand::FocusWindowDown, 68 | BaseCommand::FocusWindowTop => CoreCommand::FocusWindowTop { 69 | swap: if self.value.is_empty() { 70 | false 71 | } else { 72 | bool::from_str(&self.value) 73 | .context("invalid boolean value for FocusWindowTop")? 74 | }, 75 | }, 76 | BaseCommand::FocusWorkspaceNext => CoreCommand::FocusWorkspaceNext, 77 | BaseCommand::FocusWorkspacePrevious => CoreCommand::FocusWorkspacePrevious, 78 | BaseCommand::MoveToTag => CoreCommand::SendWindowToTag { 79 | window: None, 80 | tag: usize::from_str(&self.value) 81 | .context("invalid index value for SendWindowToTag")?, 82 | }, 83 | BaseCommand::MoveToLastWorkspace => CoreCommand::MoveWindowToLastWorkspace, 84 | BaseCommand::MoveWindowToNextWorkspace => CoreCommand::MoveWindowToNextWorkspace, 85 | BaseCommand::MoveWindowToPreviousWorkspace => { 86 | CoreCommand::MoveWindowToPreviousWorkspace 87 | } 88 | BaseCommand::MouseMoveWindow => CoreCommand::MouseMoveWindow, 89 | BaseCommand::NextLayout => CoreCommand::NextLayout, 90 | BaseCommand::PreviousLayout => CoreCommand::PreviousLayout, 91 | BaseCommand::SetLayout => CoreCommand::SetLayout( 92 | Layout::from_str(&self.value) 93 | .context("could not parse layout for command SetLayout")?, 94 | ), 95 | BaseCommand::RotateTag => CoreCommand::RotateTag, 96 | BaseCommand::IncreaseMainWidth => CoreCommand::IncreaseMainWidth( 97 | i8::from_str(&self.value).context("invalid width value for IncreaseMainWidth")?, 98 | ), 99 | BaseCommand::DecreaseMainWidth => CoreCommand::DecreaseMainWidth( 100 | i8::from_str(&self.value).context("invalid width value for DecreaseMainWidth")?, 101 | ), 102 | BaseCommand::SetMarginMultiplier => CoreCommand::SetMarginMultiplier( 103 | f32::from_str(&self.value) 104 | .context("invalid margin multiplier for SetMarginMultiplier")?, 105 | ), 106 | BaseCommand::UnloadTheme => CoreCommand::Other("UnloadTheme".into()), 107 | BaseCommand::LoadTheme => CoreCommand::Other(format!( 108 | "LoadTheme {}", 109 | ensure_non_empty!(self.value.clone()) 110 | )), 111 | BaseCommand::CloseAllOtherWindows => CoreCommand::CloseAllOtherWindows, 112 | }; 113 | 114 | Ok(CoreKeybind { 115 | command, 116 | modifier: self 117 | .modifier 118 | .as_ref() 119 | .unwrap_or(&"None".into()) 120 | .clone() 121 | .into(), 122 | key: self.key.clone(), 123 | }) 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/config/layout.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use std::str::FromStr; 3 | use thiserror::Error; 4 | 5 | #[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)] 6 | pub enum Layout { 7 | MainAndVertStack, 8 | MainAndHorizontalStack, 9 | MainAndDeck, 10 | GridHorizontal, 11 | EvenHorizontal, 12 | EvenVertical, 13 | Fibonacci, 14 | LeftMain, 15 | CenterMain, 16 | CenterMainBalanced, 17 | CenterMainFluid, 18 | Monocle, 19 | RightWiderLeftStack, 20 | LeftWiderRightStack, 21 | } 22 | 23 | pub const LAYOUTS: &[Layout] = &[ 24 | Layout::MainAndVertStack, 25 | Layout::MainAndHorizontalStack, 26 | Layout::MainAndDeck, 27 | Layout::GridHorizontal, 28 | Layout::EvenHorizontal, 29 | Layout::EvenVertical, 30 | Layout::Fibonacci, 31 | Layout::LeftMain, 32 | Layout::CenterMain, 33 | Layout::CenterMainBalanced, 34 | Layout::CenterMainFluid, 35 | Layout::Monocle, 36 | Layout::RightWiderLeftStack, 37 | Layout::LeftWiderRightStack, 38 | ]; 39 | 40 | impl Default for Layout { 41 | fn default() -> Self { 42 | Self::MainAndVertStack 43 | } 44 | } 45 | 46 | #[derive(Debug, Error)] 47 | #[error("Could not parse layout: {0}")] 48 | pub struct ParseLayoutError(String); 49 | 50 | impl FromStr for Layout { 51 | type Err = ParseLayoutError; 52 | 53 | fn from_str(s: &str) -> Result { 54 | match s { 55 | "MainAndVertStack" => Ok(Self::MainAndVertStack), 56 | "MainAndHorizontalStack" => Ok(Self::MainAndHorizontalStack), 57 | "MainAndDeck" => Ok(Self::MainAndDeck), 58 | "GridHorizontal" => Ok(Self::GridHorizontal), 59 | "EvenHorizontal" => Ok(Self::EvenHorizontal), 60 | "EvenVertical" => Ok(Self::EvenVertical), 61 | "Fibonacci" => Ok(Self::Fibonacci), 62 | "LeftMain" => Ok(Self::LeftMain), 63 | "CenterMain" => Ok(Self::CenterMain), 64 | "CenterMainBalanced" => Ok(Self::CenterMainBalanced), 65 | "CenterMainFluid" => Ok(Self::CenterMainFluid), 66 | "Monocle" => Ok(Self::Monocle), 67 | "RightWiderLeftStack" => Ok(Self::RightWiderLeftStack), 68 | "LeftWiderRightStack" => Ok(Self::LeftWiderRightStack), 69 | _ => Err(ParseLayoutError(s.to_string())), 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/config/mod.rs: -------------------------------------------------------------------------------- 1 | use std::{env, fs}; 2 | 3 | pub use check::check_config; 4 | use layout::Layout; 5 | use serde::{Deserialize, Serialize}; 6 | 7 | use crate::config::command::BaseCommand; 8 | use crate::config::keybind::Keybind; 9 | use crate::config::modifier::Modifier; 10 | use crate::config::structs::{ScratchPad, WindowHook, Workspace}; 11 | use crate::config::values::{FocusBehaviour, InsertBehavior, LayoutMode, Size}; 12 | 13 | mod check; 14 | pub mod command; 15 | pub mod filehandler; 16 | pub mod keybind; 17 | pub mod layout; 18 | pub mod modifier; 19 | pub mod structs; 20 | pub mod values; 21 | 22 | #[derive(Copy, Clone)] 23 | #[allow(dead_code)] 24 | pub enum Language { 25 | Ron, 26 | Unsupported, 27 | } 28 | 29 | #[derive(Serialize, Deserialize, Debug)] 30 | #[serde(default)] 31 | pub struct Config { 32 | pub modkey: String, 33 | pub mousekey: Option, 34 | pub tags: Option>, 35 | pub max_window_width: Option, 36 | pub layouts: Vec, 37 | pub layout_mode: LayoutMode, 38 | pub insert_behavior: InsertBehavior, 39 | pub scratchpad: Option>, 40 | pub window_rules: Option>, 41 | //of you are on tag "1" and you goto tag "1" this takes you to the previous tag 42 | pub disable_current_tag_swap: bool, 43 | pub disable_tile_drag: bool, 44 | pub focus_behaviour: FocusBehaviour, 45 | pub focus_new_windows: bool, 46 | pub keybind: Vec, 47 | pub workspaces: Option>, 48 | } 49 | 50 | fn default_terminal<'s>() -> &'s str { 51 | // order from least common to most common. 52 | // the thinking is if a machine has an uncommon terminal installed, it is intentional 53 | let terms = &[ 54 | "alacritty", 55 | "termite", 56 | "kitty", 57 | "urxvt", 58 | "rxvt", 59 | "st", 60 | "roxterm", 61 | "eterm", 62 | "xterm", 63 | "terminator", 64 | "terminology", 65 | "gnome-terminal", 66 | "xfce4-terminal", 67 | "konsole", 68 | "uxterm", 69 | "guake", // at the bottom because of odd behaviour. guake wants F12 and should really be 70 | // started using autostart instead of LeftWM keybind. 71 | ]; 72 | 73 | // If no terminal found in path, default to a good one 74 | terms 75 | .iter() 76 | .find(|terminal| is_program_in_path(terminal)) 77 | .unwrap_or(&"termite") 78 | } 79 | 80 | #[must_use] 81 | pub fn is_program_in_path(program: &str) -> bool { 82 | if let Ok(path) = env::var("PATH") { 83 | for p in path.split(':') { 84 | let p_str = format!("{}/{}", p, program); 85 | if fs::metadata(p_str).is_ok() { 86 | return true; 87 | } 88 | } 89 | } 90 | false 91 | } 92 | 93 | impl Default for Config { 94 | // We allow this because this function would be difficult to reduce. If someone would like to 95 | // move the commands builder out, perhaps make a macro, this function could be reduced in size 96 | // considerably. 97 | #[allow(clippy::too_many_lines)] 98 | fn default() -> Self { 99 | const WORKSPACES_NUM: usize = 10; 100 | let mut commands = vec![ 101 | // Mod + p => Open dmenu 102 | Keybind { 103 | command: BaseCommand::Execute, 104 | value: "dmenu_run".to_owned(), 105 | modifier: Some(vec!["modkey".to_owned()].into()), 106 | key: "p".to_owned(), 107 | }, 108 | // Mod + Shift + Enter => Open A Shell 109 | Keybind { 110 | command: BaseCommand::Execute, 111 | value: default_terminal().to_owned(), 112 | modifier: Some(vec!["modkey".to_owned(), "Shift".to_owned()].into()), 113 | key: "Return".to_owned(), 114 | }, 115 | // Mod + Shift + q => kill focused window 116 | Keybind { 117 | command: BaseCommand::CloseWindow, 118 | value: String::default(), 119 | modifier: Some(vec!["modkey".to_owned(), "Shift".to_owned()].into()), 120 | key: "q".to_owned(), 121 | }, 122 | // Mod + Shift + r => soft reload leftwm 123 | Keybind { 124 | command: BaseCommand::SoftReload, 125 | value: String::default(), 126 | modifier: Some(vec!["modkey".to_owned(), "Shift".to_owned()].into()), 127 | key: "r".to_owned(), 128 | }, 129 | // Mod + Shift + x => exit leftwm 130 | Keybind { 131 | command: BaseCommand::Execute, 132 | value: exit_strategy().to_owned(), 133 | modifier: Some(vec!["modkey".to_owned(), "Shift".to_owned()].into()), 134 | key: "x".to_owned(), 135 | }, 136 | // Mod + Ctrl + l => lock the screen 137 | Keybind { 138 | command: BaseCommand::Execute, 139 | value: "slock".to_owned(), 140 | modifier: Some(vec!["modkey".to_owned(), "Control".to_owned()].into()), 141 | key: "l".to_owned(), 142 | }, 143 | // Mod + Shift + w => swap the tags on the last to active workspaces 144 | Keybind { 145 | command: BaseCommand::MoveToLastWorkspace, 146 | value: String::default(), 147 | modifier: Some(vec!["modkey".to_owned(), "Shift".to_owned()].into()), 148 | key: "w".to_owned(), 149 | }, 150 | // Mod + w => move the active window to the previous workspace 151 | Keybind { 152 | command: BaseCommand::SwapTags, 153 | value: String::default(), 154 | modifier: Some(vec!["modkey".to_owned()].into()), 155 | key: "w".to_owned(), 156 | }, 157 | Keybind { 158 | command: BaseCommand::MoveWindowUp, 159 | value: String::default(), 160 | modifier: Some(vec!["modkey".to_owned(), "Shift".to_owned()].into()), 161 | key: "k".to_owned(), 162 | }, 163 | Keybind { 164 | command: BaseCommand::MoveWindowDown, 165 | value: String::default(), 166 | modifier: Some(vec!["modkey".to_owned(), "Shift".to_owned()].into()), 167 | key: "j".to_owned(), 168 | }, 169 | Keybind { 170 | command: BaseCommand::MoveWindowTop, 171 | value: String::default(), 172 | modifier: Some(vec!["modkey".to_owned()].into()), 173 | key: "Return".to_owned(), 174 | }, 175 | Keybind { 176 | command: BaseCommand::FocusWindowUp, 177 | value: String::default(), 178 | modifier: Some(vec!["modkey".to_owned()].into()), 179 | key: "k".to_owned(), 180 | }, 181 | Keybind { 182 | command: BaseCommand::FocusWindowDown, 183 | value: String::default(), 184 | modifier: Some(vec!["modkey".to_owned()].into()), 185 | key: "j".to_owned(), 186 | }, 187 | Keybind { 188 | command: BaseCommand::NextLayout, 189 | value: String::default(), 190 | modifier: Some(vec!["modkey".to_owned(), "Control".to_owned()].into()), 191 | key: "k".to_owned(), 192 | }, 193 | Keybind { 194 | command: BaseCommand::PreviousLayout, 195 | value: String::default(), 196 | modifier: Some(vec!["modkey".to_owned(), "Control".to_owned()].into()), 197 | key: "j".to_owned(), 198 | }, 199 | Keybind { 200 | command: BaseCommand::FocusWorkspaceNext, 201 | value: String::default(), 202 | modifier: Some(vec!["modkey".to_owned()].into()), 203 | key: "l".to_owned(), 204 | }, 205 | Keybind { 206 | command: BaseCommand::FocusWorkspacePrevious, 207 | value: String::default(), 208 | modifier: Some(vec!["modkey".to_owned()].into()), 209 | key: "h".to_owned(), 210 | }, 211 | Keybind { 212 | command: BaseCommand::MoveWindowUp, 213 | value: String::default(), 214 | modifier: Some(vec!["modkey".to_owned(), "Shift".to_owned()].into()), 215 | key: "Up".to_owned(), 216 | }, 217 | Keybind { 218 | command: BaseCommand::MoveWindowDown, 219 | value: String::default(), 220 | modifier: Some(vec!["modkey".to_owned(), "Shift".to_owned()].into()), 221 | key: "Down".to_owned(), 222 | }, 223 | Keybind { 224 | command: BaseCommand::FocusWindowUp, 225 | value: String::default(), 226 | modifier: Some(vec!["modkey".to_owned()].into()), 227 | key: "Up".to_owned(), 228 | }, 229 | Keybind { 230 | command: BaseCommand::FocusWindowDown, 231 | value: String::default(), 232 | modifier: Some(vec!["modkey".to_owned()].into()), 233 | key: "Down".to_owned(), 234 | }, 235 | Keybind { 236 | command: BaseCommand::NextLayout, 237 | value: String::default(), 238 | modifier: Some(vec!["modkey".to_owned(), "Control".to_owned()].into()), 239 | key: "Up".to_owned(), 240 | }, 241 | Keybind { 242 | command: BaseCommand::PreviousLayout, 243 | value: String::default(), 244 | modifier: Some(vec!["modkey".to_owned(), "Control".to_owned()].into()), 245 | key: "Down".to_owned(), 246 | }, 247 | Keybind { 248 | command: BaseCommand::FocusWorkspaceNext, 249 | value: String::default(), 250 | modifier: Some(vec!["modkey".to_owned()].into()), 251 | key: "Right".to_owned(), 252 | }, 253 | Keybind { 254 | command: BaseCommand::FocusWorkspacePrevious, 255 | value: String::default(), 256 | modifier: Some(vec!["modkey".to_owned()].into()), 257 | key: "Left".to_owned(), 258 | }, 259 | ]; 260 | 261 | // add "goto workspace" 262 | for i in 1..WORKSPACES_NUM { 263 | commands.push(Keybind { 264 | command: BaseCommand::GotoTag, 265 | value: i.to_string(), 266 | modifier: Some(vec!["modkey".to_owned()].into()), 267 | key: i.to_string(), 268 | }); 269 | } 270 | 271 | // and "move to workspace" 272 | for i in 1..WORKSPACES_NUM { 273 | commands.push(Keybind { 274 | command: BaseCommand::MoveToTag, 275 | value: i.to_string(), 276 | modifier: Some(vec!["modkey".to_owned(), "Shift".to_owned()].into()), 277 | key: i.to_string(), 278 | }); 279 | } 280 | 281 | let tags = vec!["1", "2", "3", "4", "5", "6", "7", "8", "9"] 282 | .iter() 283 | .map(|s| (*s).to_string()) 284 | .collect(); 285 | 286 | Self { 287 | workspaces: Some(vec![]), 288 | tags: Some(tags), 289 | layouts: vec![], 290 | layout_mode: LayoutMode::Workspace, 291 | // TODO: add sane default for scratchpad config. 292 | // Currently default values are set in sane_dimension fn. 293 | scratchpad: Some(vec![]), 294 | window_rules: Some(vec![]), 295 | disable_current_tag_swap: false, 296 | disable_tile_drag: false, 297 | focus_behaviour: FocusBehaviour::Sloppy, // default behaviour: mouse move auto-focuses window 298 | focus_new_windows: true, // default behaviour: focuses windows on creation 299 | insert_behavior: InsertBehavior::default(), 300 | modkey: "Mod4".to_owned(), //win key 301 | mousekey: Some("Mod4".into()), //win key 302 | keybind: commands, 303 | max_window_width: None, 304 | } 305 | } 306 | } 307 | 308 | fn exit_strategy<'s>() -> &'s str { 309 | if is_program_in_path("loginctl") { 310 | return "loginctl kill-session $XDG_SESSION_ID"; 311 | } 312 | "pkill leftwm" 313 | } 314 | 315 | #[allow(dead_code)] 316 | #[must_use] 317 | pub fn check_workspace_ids(config: &Config) -> bool { 318 | config.workspaces.clone().map_or(true, |wss| { 319 | let ids = get_workspace_ids(&wss); 320 | if ids.iter().any(Option::is_some) { 321 | all_ids_some(&ids) && all_ids_unique(&ids) 322 | } else { 323 | true 324 | } 325 | }) 326 | } 327 | 328 | #[must_use] 329 | pub fn get_workspace_ids(wss: &[Workspace]) -> Vec> { 330 | wss.iter().map(|ws| ws.id).collect() 331 | } 332 | 333 | pub fn all_ids_some(ids: &[Option]) -> bool { 334 | ids.iter().all(Option::is_some) 335 | } 336 | 337 | #[must_use] 338 | pub fn all_ids_unique(ids: &[Option]) -> bool { 339 | let mut sorted = ids.to_vec(); 340 | sorted.sort(); 341 | sorted.dedup(); 342 | ids.len() == sorted.len() 343 | } 344 | -------------------------------------------------------------------------------- /src/config/modifier.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | #[derive(Serialize, Deserialize, Debug, Clone, Hash, Eq, PartialEq)] 4 | #[serde(untagged)] 5 | pub enum Modifier { 6 | Single(String), 7 | List(Vec), 8 | } 9 | 10 | impl Modifier { 11 | pub fn is_empty(&self) -> bool { 12 | match self { 13 | Modifier::Single(single) => single.is_empty(), 14 | Modifier::List(list) => list.is_empty(), 15 | } 16 | } 17 | } 18 | 19 | impl std::convert::From for Vec { 20 | fn from(m: Modifier) -> Self { 21 | match m { 22 | Modifier::Single(modifier) => vec![modifier], 23 | Modifier::List(modifiers) => modifiers, 24 | } 25 | } 26 | } 27 | 28 | impl IntoIterator for &Modifier { 29 | type Item = String; 30 | type IntoIter = std::vec::IntoIter; 31 | 32 | fn into_iter(self) -> Self::IntoIter { 33 | let ms = match self { 34 | Modifier::Single(m) => vec![m.clone()], 35 | Modifier::List(ms) => ms.clone(), 36 | }; 37 | ms.into_iter() 38 | } 39 | } 40 | 41 | impl std::convert::From> for Modifier { 42 | fn from(l: Vec) -> Self { 43 | Self::List(l) 44 | } 45 | } 46 | 47 | impl std::convert::From<&str> for Modifier { 48 | fn from(m: &str) -> Self { 49 | Self::Single(m.to_owned()) 50 | } 51 | } 52 | 53 | impl std::fmt::Display for Modifier { 54 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 55 | match self { 56 | Self::Single(modifier) => write!(f, "{}", modifier), 57 | Self::List(modifiers) => write!(f, "{}", modifiers.join("+")), 58 | } 59 | } 60 | } 61 | 62 | impl Modifier { 63 | pub fn sort_unstable(&mut self) { 64 | match self { 65 | Self::Single(_) => {} 66 | Self::List(modifiers) => modifiers.sort_unstable(), 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/config/structs.rs: -------------------------------------------------------------------------------- 1 | use crate::config::layout::Layout; 2 | use crate::config::values::Size; 3 | use serde::{Deserialize, Serialize}; 4 | 5 | #[derive(Serialize, Default, Deserialize, Debug, Clone, PartialEq)] 6 | pub struct Workspace { 7 | pub x: i32, 8 | pub y: i32, 9 | pub height: i32, 10 | pub width: i32, 11 | pub id: Option, 12 | pub max_window_width: Option, 13 | pub layouts: Option>, 14 | } 15 | 16 | #[derive(Serialize, Default, Deserialize, Debug, Clone, PartialEq)] 17 | pub struct ScratchPad { 18 | pub name: String, 19 | pub value: String, 20 | // relative x of scratchpad, 25 means 25% of workspace x 21 | pub x: Option, 22 | // relative y of scratchpad, 25 means 25% of workspace y 23 | pub y: Option, 24 | // relative height of scratchpad, 50 means 50% of workspace height 25 | pub height: Option, 26 | // relative width of scratchpad, 50 means 50% of workspace width 27 | pub width: Option, 28 | } 29 | 30 | /// Selecting by `WM_CLASS` and/or window title, allow the user to define if a 31 | /// window should spawn on a specified tag and/or its floating state. 32 | /// 33 | /// # Example 34 | /// 35 | /// In `config.toml` 36 | /// 37 | /// ```toml 38 | /// [[window_config_by_class]] 39 | /// wm_class = "krita" 40 | /// spawn_on_tag = 3 41 | /// spawn_floating = false 42 | /// ``` 43 | /// 44 | /// windows whose `WM_CLASS` is "krita" will spawn on tag 3 (1-indexed) and not floating. 45 | #[derive(Serialize, Deserialize, Default, Debug, Clone)] 46 | pub struct WindowHook { 47 | /// `WM_CLASS` in X11 48 | pub window_class: Option, 49 | /// `_NET_WM_NAME` in X11 50 | pub window_title: Option, 51 | pub spawn_on_tag: Option, 52 | pub spawn_floating: Option, 53 | } 54 | -------------------------------------------------------------------------------- /src/config/values.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use std::os::raw::c_ulong; 3 | 4 | #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Copy)] 5 | #[serde(untagged)] 6 | pub enum Size { 7 | Pixel(i32), 8 | Ratio(f32), 9 | } 10 | 11 | #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)] 12 | pub enum LayoutMode { 13 | Tag, 14 | Workspace, 15 | } 16 | 17 | #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Default)] 18 | pub enum InsertBehavior { 19 | Top, 20 | #[default] 21 | Bottom, 22 | BeforeCurrent, 23 | AfterCurrent, 24 | } 25 | 26 | #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] 27 | pub enum FocusBehaviour { 28 | Sloppy, 29 | ClickTo, 30 | Driven, 31 | } 32 | 33 | pub type Window = c_ulong; 34 | type MockHandle = i32; 35 | 36 | #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)] 37 | pub enum WindowHandle { 38 | MockHandle(MockHandle), 39 | XlibHandle(Window), 40 | } 41 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #![allow( 2 | clippy::module_name_repetitions, 3 | clippy::too_many_lines, 4 | //a lot of unimplemented arms 5 | clippy::match_same_arms, 6 | )] 7 | 8 | extern crate core; 9 | 10 | mod config; 11 | mod tui; 12 | mod utils; 13 | 14 | use crate::config::check_config; 15 | use crate::config::filehandler::{load_from_file, write_to_file}; 16 | use anyhow::Result; 17 | use clap::{App, Arg}; 18 | use std::path::Path; 19 | use std::process::Command; 20 | use std::{env, fs, io}; 21 | use xdg::BaseDirectories; 22 | 23 | #[cfg(debug_assertions)] 24 | const CONFIG_NAME: &str = "test_config"; 25 | #[cfg(not(debug_assertions))] 26 | const CONFIG_NAME: &str = "config"; 27 | 28 | fn main() -> Result<()> { 29 | let matches = App::new("LeftWM Command") 30 | .author("BlackDragon2447 ") 31 | .version(env!("CARGO_PKG_VERSION")) 32 | .about("a tool for managing your LeftWM config") 33 | .arg( 34 | Arg::with_name("New") 35 | .short('n') 36 | .long("new") 37 | .help("Generate a new config file"), 38 | ) 39 | .arg( 40 | Arg::with_name("Editor") 41 | .short('e') 42 | .long("editor") 43 | .help("Open the current config file in the default editor (default)"), 44 | ) 45 | .arg( 46 | Arg::with_name("TUI") 47 | .short('t') 48 | .long("tui") 49 | .help("Open the current config file in the TUI"), 50 | ) 51 | .arg( 52 | Arg::with_name("Check") 53 | .short('c') 54 | .long("check") 55 | .help("Check if the current config is valid"), 56 | ) 57 | .arg( 58 | Arg::with_name("Verbose") 59 | .short('v') 60 | .long("verbose") 61 | .help("Outputs received configuration file."), 62 | ) 63 | .arg( 64 | Arg::with_name("Migrate") 65 | .long("migrate") 66 | .help("Migrate an old .toml config to the RON format."), 67 | ) 68 | .get_matches(); 69 | 70 | let verbose = matches.occurrences_of("Verbose") >= 1; 71 | 72 | if matches.is_present("Migrate") { 73 | println!("\x1b[0;94m::\x1b[0m Migrating configuration . . ."); 74 | let path = BaseDirectories::with_prefix("leftwm")?; 75 | let ron_file = path.place_config_file(crate::CONFIG_NAME.to_string() + ".ron")?; 76 | let toml_file = path.place_config_file(crate::CONFIG_NAME.to_string() + ".toml")?; 77 | 78 | let config = load_from_file(toml_file.as_os_str().to_str(), verbose)?; 79 | 80 | write_to_file(&ron_file, &config)?; 81 | 82 | return Ok(()); 83 | } else if matches.is_present("Editor") { 84 | run_editor(config::filehandler::get_config_file()?.as_path())?; 85 | } else if matches.is_present("TUI") { 86 | crate::tui::run()?; 87 | } else if matches.is_present("New") { 88 | config::filehandler::generate_new_config()?; 89 | } else if matches.is_present("Check") { 90 | check_config(None, verbose)?; 91 | } else { 92 | run_editor(config::filehandler::get_config_file()?.as_path())?; 93 | } 94 | 95 | Ok(()) 96 | } 97 | 98 | fn run_editor(file: &Path) -> Result<()> { 99 | let editor = env::var("EDITOR")?; 100 | 101 | let tmp_file = Path::new("/tmp/leftwm-config.ron"); 102 | fs::copy(file, tmp_file)?; 103 | 104 | let run_internal = || -> Result<()> { 105 | let mut process = Command::new(&editor).arg(tmp_file.as_os_str()).spawn()?; 106 | if process.wait()?.success() { 107 | Ok(()) 108 | } else { 109 | Err(anyhow::Error::msg(format!("Failed to run {}", &editor))) 110 | }?; 111 | Ok(()) 112 | }; 113 | 114 | run_internal()?; 115 | 116 | while check_config(Some("/tmp/leftwm-config.ron"), false).is_err() { 117 | println!("Do you want to reopen your editor? [Y/n] "); 118 | 119 | let mut buffer = String::new(); 120 | io::stdin().read_line(&mut buffer)?; 121 | 122 | if let Some("y" | "Y") = buffer.get(0..1) { 123 | run_internal()?; 124 | } else if let Some("n" | "N") = buffer.get(0..1) { 125 | break; 126 | } else { 127 | run_internal()?; 128 | } 129 | } 130 | 131 | fs::copy(tmp_file, file)?; 132 | 133 | Ok(()) 134 | } 135 | -------------------------------------------------------------------------------- /src/tui/mod.rs: -------------------------------------------------------------------------------- 1 | use std::io::{self, Stdout}; 2 | 3 | use anyhow::Result; 4 | use crossterm::event::{DisableMouseCapture, EnableMouseCapture}; 5 | use crossterm::execute; 6 | use crossterm::terminal::{ 7 | disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen, 8 | }; 9 | use tui::layout::{Alignment, Constraint, Direction, Layout}; 10 | use tui::style::{Color, Modifier, Style}; 11 | use tui::text::{Span, Spans}; 12 | use tui::widgets::{BorderType, List, ListItem, ListState}; 13 | use tui::{ 14 | backend::CrosstermBackend, 15 | widgets::{Block, Borders, Paragraph, Wrap}, 16 | Terminal, 17 | }; 18 | 19 | use crate::config::filehandler::load; 20 | use crate::config::modifier::Modifier as KeyModifier; 21 | use crate::config::values::{FocusBehaviour, InsertBehavior, LayoutMode}; 22 | use crate::config::Config; 23 | use crate::utils; 24 | use crate::utils::TryUnwrap; 25 | 26 | mod key_handler; 27 | mod popups; 28 | 29 | #[derive(Clone)] 30 | pub enum PopupState { 31 | None, 32 | List(ListState), 33 | MultiList(MultiselectListState), 34 | String(String), 35 | Int { 36 | current: isize, 37 | min: isize, 38 | max: isize, 39 | }, 40 | } 41 | 42 | #[derive(Clone)] 43 | pub struct MultiselectListState { 44 | pub liststate: ListState, 45 | pub selected: Vec, 46 | } 47 | 48 | #[allow(dead_code)] 49 | pub enum Window { 50 | Home, 51 | Workspaces { index: usize, empty: bool }, 52 | Tags { index: usize, empty: bool }, 53 | WindowRules { index: usize, empty: bool }, 54 | Scratchpads { index: usize, empty: bool }, 55 | KeyBinds { index: usize, empty: bool }, 56 | } 57 | 58 | impl Window { 59 | fn try_increment_index(&mut self) { 60 | match self { 61 | Window::Home => {} 62 | Window::Workspaces { index, .. } 63 | | Window::Tags { index, .. } 64 | | Window::WindowRules { index, .. } 65 | | Window::Scratchpads { index, .. } 66 | | Window::KeyBinds { index, .. } => { 67 | *index += 1; 68 | } 69 | } 70 | } 71 | 72 | fn try_decrement_index(&mut self) { 73 | match self { 74 | Window::Home => {} 75 | Window::Workspaces { index, .. } 76 | | Window::Tags { index, .. } 77 | | Window::WindowRules { index, .. } 78 | | Window::Scratchpads { index, .. } 79 | | Window::KeyBinds { index, .. } => { 80 | *index -= 1; 81 | } 82 | } 83 | } 84 | 85 | fn try_set_index(&mut self, new_index: usize) { 86 | match self { 87 | Window::Home => {} 88 | Window::Workspaces { index, .. } 89 | | Window::Tags { index, .. } 90 | | Window::WindowRules { index, .. } 91 | | Window::Scratchpads { index, .. } 92 | | Window::KeyBinds { index, .. } => { 93 | *index = new_index; 94 | } 95 | } 96 | } 97 | } 98 | 99 | struct App<'a> { 100 | config_list: Vec>, 101 | config_list_state: ListState, 102 | current_popup: Option, 103 | current_window: Window, 104 | current_popup_state: PopupState, 105 | current_config: Config, 106 | alive: Result<()>, 107 | } 108 | 109 | pub fn run() -> Result<()> { 110 | enable_raw_mode()?; 111 | let mut stdout = io::stdout(); 112 | execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?; 113 | let backend = CrosstermBackend::new(stdout); 114 | let mut terminal = Terminal::new(backend)?; 115 | 116 | let mut state = ListState::default(); 117 | state.select(Some(0)); 118 | 119 | let app = App { 120 | config_list: vec![], 121 | config_list_state: state, 122 | current_popup: None, 123 | current_window: Window::Home, 124 | current_popup_state: PopupState::None, 125 | current_config: load(), 126 | alive: Ok(()), 127 | }; 128 | 129 | let app_result = app.run(&mut terminal); 130 | 131 | // restore terminal 132 | disable_raw_mode()?; 133 | execute!( 134 | terminal.backend_mut(), 135 | LeaveAlternateScreen, 136 | DisableMouseCapture 137 | )?; 138 | terminal.show_cursor()?; 139 | 140 | app_result 141 | } 142 | 143 | impl App<'_> { 144 | fn run(mut self, terminal: &mut Terminal>) -> Result<()> { 145 | while self.alive.is_ok() { 146 | terminal.draw(|f| { 147 | match self.format_config_list() { 148 | Err(e) => self.alive = Err(e), 149 | Ok(l) => self.config_list = l, 150 | } 151 | let size = f.size(); 152 | 153 | let chunks = Layout::default() 154 | .direction(Direction::Vertical) 155 | .constraints([Constraint::Percentage(95), Constraint::Percentage(5)].as_ref()) 156 | .split(size); 157 | 158 | let frame = Block::default() 159 | .borders(Borders::ALL) 160 | .border_style(Style::default().fg(Color::White)) 161 | .border_type(BorderType::Rounded) 162 | .style(Style::default().bg(Color::Black)) 163 | .title("LeftWM-Config"); 164 | 165 | let list = List::new(self.config_list.clone()) 166 | .block(Block::default().borders(Borders::NONE)) 167 | .style(Style::default().fg(Color::White)) 168 | .highlight_style(Style::default().add_modifier(Modifier::BOLD)) 169 | .highlight_symbol(">>"); 170 | 171 | let help_text = match self.current_window { 172 | Window::Workspaces { .. } => { 173 | let mut spans = vec![ 174 | Span::raw("Exit: q, "), 175 | Span::raw("Save: s, "), 176 | Span::raw("Delete Optional Value: Delete, "), 177 | Span::raw("Back: Backspace"), 178 | ]; 179 | 180 | if let Some(6) = self.current_popup { 181 | spans.push(Span::raw(", Space: Toggle item")); 182 | } 183 | 184 | vec![Spans::from(spans)] 185 | } 186 | Window::WindowRules { .. } | Window::Scratchpads { .. } => { 187 | vec![Spans::from(vec![ 188 | Span::raw("Exit: q, "), 189 | Span::raw("Save: s, "), 190 | Span::raw("Delete Optional Value: Delete, "), 191 | Span::raw("Back: Backspace"), 192 | ])] 193 | } 194 | Window::Tags { .. } => { 195 | vec![Spans::from(vec![ 196 | Span::raw("Exit: q, "), 197 | Span::raw("Save: s, "), 198 | Span::raw("Back: Backspace"), 199 | ])] 200 | } 201 | Window::KeyBinds { .. } => { 202 | let mut spans = vec![Span::raw("Exit: q, "), Span::raw("Save: s")]; 203 | 204 | if let Some(2) = self.current_popup { 205 | spans.push(Span::raw(", Space: Toggle item")); 206 | } 207 | 208 | vec![Spans::from(spans)] 209 | } 210 | Window::Home => { 211 | let mut spans = vec![Span::raw("Exit: q, "), Span::raw("Save: s")]; 212 | 213 | if let Some(9) = self.current_popup { 214 | spans.push(Span::raw(", Space: Toggle item")); 215 | } 216 | 217 | vec![Spans::from(spans)] 218 | } 219 | }; 220 | 221 | let help = Paragraph::new(help_text) 222 | .style(Style::default().fg(Color::White).bg(Color::Black)) 223 | .alignment(Alignment::Center) 224 | .wrap(Wrap { trim: true }); 225 | 226 | f.render_widget(frame, size); 227 | f.render_stateful_widget( 228 | list, 229 | utils::centered_rect(50, 50, *chunks.get(0).unwrap_or(&size)), 230 | &mut self.config_list_state, 231 | ); 232 | f.render_widget(help, *chunks.get(1).unwrap_or(&size)); 233 | 234 | if let Err(e) = match self.current_window { 235 | Window::Home => { 236 | if let Some(s) = self.current_popup { 237 | match s { 238 | 0 => popups::modkey( 239 | &self.current_config, 240 | &mut self.current_popup_state, 241 | f, 242 | false, 243 | ), 244 | 1 => popups::modkey( 245 | &self.current_config, 246 | &mut self.current_popup_state, 247 | f, 248 | true, 249 | ), 250 | 2 => popups::max_window_width(&mut self.current_popup_state, f), 251 | // 3, 4 and 5 dont need a popup 252 | 6 => popups::focus_behavior( 253 | &self.current_config, 254 | &mut self.current_popup_state, 255 | f, 256 | ), 257 | 7 => popups::insert_behavior( 258 | &self.current_config, 259 | &mut self.current_popup_state, 260 | f, 261 | ), 262 | 8 => popups::layout_mode( 263 | &self.current_config, 264 | &mut self.current_popup_state, 265 | f, 266 | ), 267 | 9 => popups::layouts(&mut self.current_popup_state, f), 268 | 15 => popups::saved(f), 269 | _ => Ok(()), 270 | } 271 | } else { 272 | Ok(()) 273 | } 274 | } 275 | Window::Workspaces { .. } => { 276 | if let Some(s) = self.current_popup { 277 | match s { 278 | 0 => popups::text_input( 279 | &mut self.current_popup_state, 280 | "X".to_string(), 281 | f, 282 | ), 283 | 1 => popups::text_input( 284 | &mut self.current_popup_state, 285 | "Y".to_string(), 286 | f, 287 | ), 288 | 2 => popups::text_input( 289 | &mut self.current_popup_state, 290 | "Widht".to_string(), 291 | f, 292 | ), 293 | 3 => popups::text_input( 294 | &mut self.current_popup_state, 295 | "Height".to_string(), 296 | f, 297 | ), 298 | 4 => popups::text_input( 299 | &mut self.current_popup_state, 300 | "Id".to_string(), 301 | f, 302 | ), 303 | 5 => popups::text_input( 304 | &mut self.current_popup_state, 305 | "Max window width".to_string(), 306 | f, 307 | ), 308 | 6 => popups::layouts(&mut self.current_popup_state, f), 309 | 15 => popups::saved(f), 310 | _ => Ok(()), 311 | } 312 | } else { 313 | Ok(()) 314 | } 315 | } 316 | Window::Tags { .. } => { 317 | if let Some(15) = self.current_popup { 318 | popups::saved(f) 319 | } else if self.current_popup.is_some() { 320 | popups::text_input(&mut self.current_popup_state, "Name".to_string(), f) 321 | } else { 322 | Ok(()) 323 | } 324 | } 325 | Window::WindowRules { .. } => match self.current_popup { 326 | Some(0) => popups::text_input( 327 | &mut self.current_popup_state, 328 | "Title".to_string(), 329 | f, 330 | ), 331 | Some(1) => popups::text_input( 332 | &mut self.current_popup_state, 333 | "Class".to_string(), 334 | f, 335 | ), 336 | Some(2) => popups::counter( 337 | &mut self.current_popup_state, 338 | "Spawn on tag".to_string(), 339 | f, 340 | ), 341 | Some(15) => popups::saved(f), 342 | _ => Ok(()), 343 | }, 344 | Window::Scratchpads { .. } => match self.current_popup { 345 | Some(0) => { 346 | popups::text_input(&mut self.current_popup_state, "Name".to_string(), f) 347 | } 348 | Some(1) => popups::text_input( 349 | &mut self.current_popup_state, 350 | "Value".to_string(), 351 | f, 352 | ), 353 | Some(2) => { 354 | popups::text_input(&mut self.current_popup_state, "X".to_string(), f) 355 | } 356 | Some(3) => { 357 | popups::text_input(&mut self.current_popup_state, "Y".to_string(), f) 358 | } 359 | Some(4) => popups::text_input( 360 | &mut self.current_popup_state, 361 | "Width".to_string(), 362 | f, 363 | ), 364 | Some(5) => popups::text_input( 365 | &mut self.current_popup_state, 366 | "Height".to_string(), 367 | f, 368 | ), 369 | Some(15) => popups::saved(f), 370 | _ => Ok(()), 371 | }, 372 | Window::KeyBinds { index, .. } => match self.current_popup { 373 | Some(0) => popups::keybind_command( 374 | &self.current_config, 375 | index, 376 | &mut self.current_popup_state, 377 | f, 378 | ), 379 | Some(1) => popups::text_input( 380 | &mut self.current_popup_state, 381 | "Value".to_string(), 382 | f, 383 | ), 384 | Some(2) => popups::keybind_modkey(&mut self.current_popup_state, f), 385 | Some(3) => { 386 | popups::keybind_key(&mut self.current_popup_state, "Key".to_string(), f) 387 | } 388 | Some(15) => popups::saved(f), 389 | _ => Ok(()), 390 | }, 391 | } { 392 | self.alive = Err(e); 393 | } 394 | })?; 395 | 396 | if key_handler::handle_keys(&mut self)? { 397 | return Ok(()); 398 | } 399 | } 400 | 401 | match self.alive { 402 | Ok(_) => Ok(()), 403 | Err(e) => Err(e), 404 | } 405 | } 406 | 407 | fn format_config_list<'a>(&mut self) -> Result>> { 408 | Ok(match self.current_window { 409 | Window::Home => Vec::from([ 410 | ListItem::new(format!( 411 | "Modkey - {}", 412 | format_modkey_name(self.current_config.modkey.clone()) 413 | )), 414 | ListItem::new(format!( 415 | "Mousekey - {}", 416 | format_modkey_name( 417 | self.current_config 418 | .mousekey 419 | .clone() 420 | .unwrap_or_else(|| KeyModifier::Single("None".to_string())) 421 | .to_string() 422 | ) 423 | )), 424 | ListItem::new(match &self.current_config.max_window_width { 425 | Some(w) => format!("Max Window Width - {:?}", w), 426 | None => "Max Window Width - not set".to_string(), 427 | }), 428 | ListItem::new(format!( 429 | "Disable Current Tag Swap - {}", 430 | self.current_config.disable_current_tag_swap 431 | )), 432 | ListItem::new(format!( 433 | "Disable Tile Drag - {}", 434 | self.current_config.disable_tile_drag 435 | )), 436 | ListItem::new(format!( 437 | "Focus New Windows - {}", 438 | self.current_config.focus_new_windows 439 | )), 440 | ListItem::new(format!( 441 | "Focus Behavior - {}", 442 | match self.current_config.focus_behaviour { 443 | FocusBehaviour::Sloppy => "Sloppy".to_string(), 444 | FocusBehaviour::ClickTo => "Click To".to_string(), 445 | FocusBehaviour::Driven => "Driven".to_string(), 446 | } 447 | )), 448 | ListItem::new(format!( 449 | "Insert Behavior - {}", 450 | match self.current_config.insert_behavior { 451 | InsertBehavior::AfterCurrent => "Afer Current".to_string(), 452 | InsertBehavior::BeforeCurrent => "Before Current".to_string(), 453 | InsertBehavior::Bottom => "Bottom".to_string(), 454 | InsertBehavior::Top => "Top".to_string(), 455 | } 456 | )), 457 | ListItem::new(format!( 458 | "Layout Mode - {}", 459 | match self.current_config.layout_mode { 460 | LayoutMode::Tag => "Tag".to_string(), 461 | LayoutMode::Workspace => "Workspace".to_string(), 462 | } 463 | )), 464 | ListItem::new(format!( 465 | "Layouts - {} set", 466 | self.current_config.layouts.len() 467 | )), 468 | ListItem::new(match &self.current_config.workspaces { 469 | Some(v) => format!("Workspaces - {} set", v.len()), 470 | None => "Workspaces".to_string(), 471 | }), 472 | ListItem::new(match &self.current_config.tags { 473 | Some(v) => format!("Tags - {} set", v.len()), 474 | None => "Tags".to_string(), 475 | }), 476 | ListItem::new(match &self.current_config.window_rules { 477 | Some(v) => format!("Window Rules - {} set", v.len()), 478 | None => "Window Rules".to_string(), 479 | }), 480 | ListItem::new(match &self.current_config.scratchpad { 481 | Some(v) => format!("Scratchpads - {} set", v.len()), 482 | None => "Scratchpads".to_string(), 483 | }), 484 | ListItem::new(format!( 485 | "Keybinds - {} set", 486 | self.current_config.keybind.len() 487 | )), 488 | ]), 489 | Window::Workspaces { index, .. } => { 490 | let current_workspace = if let Some(w) = &self.current_config.workspaces { 491 | if self 492 | .current_config 493 | .workspaces 494 | .as_ref() 495 | .try_unwrap()? 496 | .is_empty() 497 | { 498 | None 499 | } else { 500 | w.get(index) 501 | } 502 | } else { 503 | None 504 | }; 505 | 506 | if let Some(c) = current_workspace { 507 | vec![ 508 | ListItem::new(format!( 509 | "{} out of {}", 510 | index + 1, 511 | self.current_config.workspaces.as_ref().try_unwrap()?.len() 512 | )), 513 | ListItem::new("--------------------------"), 514 | ListItem::new(format!("X - {}", c.x)), 515 | ListItem::new(format!("Y - {}", c.y)), 516 | ListItem::new(format!("Width - {}", c.width)), 517 | ListItem::new(format!("Height - {}", c.height)), 518 | ListItem::new(format!("Id - {:?}", c.id)), 519 | ListItem::new(format!("Max Window Width - {:?}", c.max_window_width)), 520 | ListItem::new(format!( 521 | "Layouts - {}", 522 | if c.layouts.is_some() { 523 | "Some(Open to see more)" 524 | } else { 525 | "None" 526 | } 527 | )), 528 | ListItem::new("--------------------------"), 529 | ListItem::new("Add new workspace"), 530 | ListItem::new("Delete this workspace"), 531 | ] 532 | } else { 533 | vec![ 534 | ListItem::new(format!( 535 | "None out of {}", 536 | self.current_config.workspaces.as_ref().try_unwrap()?.len() 537 | )), 538 | ListItem::new("--------------------------"), 539 | ListItem::new("Add new workspace"), 540 | ] 541 | } 542 | } 543 | Window::Tags { index, .. } => { 544 | let current_workspace = if let Some(w) = &self.current_config.tags { 545 | if self.current_config.tags.as_ref().try_unwrap()?.is_empty() { 546 | None 547 | } else { 548 | w.get(index) 549 | } 550 | } else { 551 | None 552 | }; 553 | 554 | if let Some(c) = current_workspace { 555 | vec![ 556 | ListItem::new(format!( 557 | "{} out of {}", 558 | index + 1, 559 | self.current_config.tags.as_ref().try_unwrap()?.len() 560 | )), 561 | ListItem::new("--------------------------"), 562 | ListItem::new(format!("Name - {}", c)), 563 | ListItem::new("--------------------------"), 564 | ListItem::new("Add new tag"), 565 | ListItem::new("Delete this tag"), 566 | ] 567 | } else { 568 | vec![ 569 | ListItem::new(format!( 570 | "None out of {}", 571 | self.current_config.tags.as_ref().try_unwrap()?.len() 572 | )), 573 | ListItem::new("--------------------------"), 574 | ListItem::new("Add new tag"), 575 | ] 576 | } 577 | } 578 | Window::WindowRules { index, empty } => { 579 | if empty { 580 | vec![ 581 | ListItem::new("None out of 0"), 582 | ListItem::new("--------------------------"), 583 | ListItem::new("Add new rule"), 584 | ] 585 | } else { 586 | let rule = self 587 | .current_config 588 | .window_rules 589 | .as_ref() 590 | .try_unwrap()? 591 | .get(index) 592 | .try_unwrap()?; 593 | 594 | let mut vec = vec![ 595 | ListItem::new(format!( 596 | "{} out of {}", 597 | index + 1, 598 | self.current_config 599 | .window_rules 600 | .as_ref() 601 | .try_unwrap()? 602 | .len() 603 | )), 604 | ListItem::new("--------------------------"), 605 | ListItem::new(format!("Title - {:?}", rule.window_title)), 606 | ListItem::new(format!("Class - {:?}", rule.window_class)), 607 | ListItem::new(format!("Spawn on tag - {:?}", rule.spawn_on_tag)), 608 | ListItem::new(format!( 609 | "Spawn floating - {}", 610 | rule.spawn_floating.unwrap_or(false) 611 | )), 612 | ListItem::new("--------------------------"), 613 | ]; 614 | 615 | if rule.window_class.is_none() && rule.window_title.is_none() { 616 | vec.push(ListItem::new("WARNING:").style(Style::default().fg(Color::Red))); 617 | vec.push( 618 | ListItem::new("Neither title nor class are set") 619 | .style(Style::default().fg(Color::Red)), 620 | ); 621 | vec.push( 622 | ListItem::new("This rule will be ignored") 623 | .style(Style::default().fg(Color::Red)), 624 | ); 625 | vec.push(ListItem::new("--------------------------")); 626 | } else if rule.window_class.is_some() && rule.window_title.is_some() { 627 | vec.push(ListItem::new("WARNING:").style(Style::default().fg(Color::Red))); 628 | vec.push( 629 | ListItem::new("Both the title and class are set") 630 | .style(Style::default().fg(Color::Red)), 631 | ); 632 | vec.push( 633 | ListItem::new("Class will be ignored") 634 | .style(Style::default().fg(Color::Red)), 635 | ); 636 | vec.push(ListItem::new("--------------------------")); 637 | } 638 | 639 | vec.push(ListItem::new("Add new rule")); 640 | vec.push(ListItem::new("Delete this rule")); 641 | 642 | vec 643 | } 644 | } 645 | Window::Scratchpads { index, empty } => { 646 | if empty { 647 | vec![ 648 | ListItem::new("None out of 0"), 649 | ListItem::new("--------------------------"), 650 | ListItem::new("Add new scratchpad"), 651 | ] 652 | } else { 653 | let scratchpad = self 654 | .current_config 655 | .scratchpad 656 | .as_ref() 657 | .try_unwrap()? 658 | .get(index) 659 | .try_unwrap()?; 660 | 661 | vec![ 662 | ListItem::new(format!( 663 | "{} out of {}", 664 | index + 1, 665 | self.current_config.scratchpad.as_ref().try_unwrap()?.len() 666 | )), 667 | ListItem::new("--------------------------"), 668 | ListItem::new(format!("Name - {}", scratchpad.name)), 669 | ListItem::new(format!("Value - {}", scratchpad.value)), 670 | ListItem::new(format!("X - {:?}", scratchpad.x)), 671 | ListItem::new(format!("Y - {:?}", scratchpad.y)), 672 | ListItem::new(format!("Width - {:?}", scratchpad.width)), 673 | ListItem::new(format!("Height - {:?}", scratchpad.height)), 674 | ListItem::new("--------------------------"), 675 | ListItem::new("Add new scratchpad"), 676 | ListItem::new("Delete this scratchpad"), 677 | ] 678 | } 679 | } 680 | Window::KeyBinds { index, empty } => { 681 | if empty { 682 | vec![ 683 | ListItem::new("None out of 0"), 684 | ListItem::new("--------------------------"), 685 | ListItem::new("Add new keybind"), 686 | ] 687 | } else { 688 | let keybind = self.current_config.keybind.get(index).try_unwrap()?; 689 | let mut vec = vec![ 690 | ListItem::new(format!( 691 | "{} out of {}", 692 | index + 1, 693 | self.current_config.keybind.len() 694 | )), 695 | ListItem::new("--------------------------"), 696 | ListItem::new(format!("Command - {:?}", keybind.command)), 697 | ]; 698 | 699 | if keybind.command.needs_value() { 700 | vec.push(ListItem::new(format!("Value - {}", keybind.value))); 701 | } 702 | 703 | vec.push(ListItem::new(format!( 704 | "Modifier - {}", 705 | if let Some(m) = &keybind.modifier { 706 | format!("{}", m) 707 | } else { 708 | "None".to_string() 709 | } 710 | ))); 711 | 712 | vec.push(ListItem::new(format!("Key - {}", keybind.key))); 713 | 714 | vec.push(ListItem::new("--------------------------")); 715 | vec.push(ListItem::new("Add new keybind")); 716 | vec.push(ListItem::new("Delete this keybind")); 717 | 718 | vec 719 | } 720 | } 721 | }) 722 | } 723 | } 724 | 725 | fn next(state: &mut ListState, len: usize) { 726 | let i = match state.selected() { 727 | Some(i) => { 728 | if i >= len - 1 { 729 | 0 730 | } else { 731 | i + 1 732 | } 733 | } 734 | None => 0, 735 | }; 736 | state.select(Some(i)); 737 | } 738 | 739 | fn previous(state: &mut ListState, len: usize) { 740 | let i = match state.selected() { 741 | Some(i) => { 742 | if i == 0 { 743 | len - 1 744 | } else { 745 | i - 1 746 | } 747 | } 748 | None => 0, 749 | }; 750 | state.select(Some(i)); 751 | } 752 | 753 | fn format_modkey_name(modkey: String) -> String { 754 | match modkey.as_str() { 755 | "Mod1" | "Alt" => "Alt".to_string(), 756 | "Mod4" | "Super" => "Super".to_string(), 757 | _ => modkey, 758 | } 759 | } 760 | -------------------------------------------------------------------------------- /src/tui/popups.rs: -------------------------------------------------------------------------------- 1 | use std::io::Stdout; 2 | use std::mem; 3 | 4 | use anyhow::{bail, Result}; 5 | use tui::backend::CrosstermBackend; 6 | use tui::layout::{Alignment, Constraint, Direction, Layout}; 7 | use tui::style::{Color, Modifier, Style}; 8 | use tui::text::{Span, Spans}; 9 | use tui::widgets::{Block, BorderType, Borders, Clear, List, ListItem, Paragraph, Wrap}; 10 | use tui::Frame; 11 | 12 | use crate::config::command::BaseCommand; 13 | use crate::config::modifier::Modifier as KeyModifier; 14 | use crate::config::modifier::Modifier::Single; 15 | use crate::config::values::{FocusBehaviour, InsertBehavior, LayoutMode}; 16 | use crate::config::Config; 17 | use crate::tui::PopupState; 18 | use crate::utils::xkeysym_lookup::into_keysym; 19 | use crate::utils::{centered_rect, TryUnwrap}; 20 | 21 | pub fn modkey( 22 | current_config: &Config, 23 | current_popup_state: &mut PopupState, 24 | f: &mut Frame>, 25 | is_mousekey: bool, 26 | ) -> Result<()> { 27 | let block = Block::default() 28 | .borders(Borders::ALL) 29 | .border_style(Style::default().fg(Color::White)) 30 | .border_type(BorderType::Rounded) 31 | .style(Style::default().bg(Color::Black)) 32 | .title(if is_mousekey { "Mousekey" } else { "Modkey" }); 33 | let area = centered_rect(60, 20, f.size()); 34 | f.render_widget(Clear, area); //this clears out the background 35 | f.render_widget(block, area); 36 | let modkey_list = if is_mousekey { 37 | [ 38 | if current_config.mousekey.is_none() { 39 | ListItem::new("None").style(Style::default().fg(Color::Green)) 40 | } else { 41 | ListItem::new("None") 42 | }, 43 | if check_modifier(¤t_config.mousekey, "Shift") { 44 | ListItem::new("Shift").style(Style::default().fg(Color::Green)) 45 | } else { 46 | ListItem::new("Shift") 47 | }, 48 | if check_modifier(¤t_config.mousekey, "Control") { 49 | ListItem::new("Control").style(Style::default().fg(Color::Green)) 50 | } else { 51 | ListItem::new("Control") 52 | }, 53 | if check_modifier(¤t_config.mousekey, "Mod1") 54 | || check_modifier(¤t_config.mousekey, "Alt") 55 | { 56 | ListItem::new("Alt").style(Style::default().fg(Color::Green)) 57 | } else { 58 | ListItem::new("Alt") 59 | }, 60 | if check_modifier(¤t_config.mousekey, "Mod3") { 61 | ListItem::new("Mod3").style(Style::default().fg(Color::Green)) 62 | } else { 63 | ListItem::new("Mod3") 64 | }, 65 | if check_modifier(¤t_config.mousekey, "Mod4") 66 | || check_modifier(¤t_config.mousekey, "Super") 67 | { 68 | ListItem::new("Super").style(Style::default().fg(Color::Green)) 69 | } else { 70 | ListItem::new("Super") 71 | }, 72 | if check_modifier(¤t_config.mousekey, "Mod5") { 73 | ListItem::new("Mod5").style(Style::default().fg(Color::Green)) 74 | } else { 75 | ListItem::new("Mod5") 76 | }, 77 | ] 78 | } else { 79 | [ 80 | if current_config.modkey == "None" { 81 | ListItem::new("None").style(Style::default().fg(Color::Green)) 82 | } else { 83 | ListItem::new("None") 84 | }, 85 | if current_config.modkey == "Shift" { 86 | ListItem::new("Shift").style(Style::default().fg(Color::Green)) 87 | } else { 88 | ListItem::new("Shift") 89 | }, 90 | if current_config.modkey == "Control" { 91 | ListItem::new("Control").style(Style::default().fg(Color::Green)) 92 | } else { 93 | ListItem::new("Control") 94 | }, 95 | if current_config.modkey == "Alt" || current_config.modkey == "Mod1" { 96 | ListItem::new("Alt").style(Style::default().fg(Color::Green)) 97 | } else { 98 | ListItem::new("Alt") 99 | }, 100 | if current_config.modkey == "Mod3" { 101 | ListItem::new("Mod3").style(Style::default().fg(Color::Green)) 102 | } else { 103 | ListItem::new("Mod3") 104 | }, 105 | if current_config.modkey == "Super" || current_config.modkey == "Mod4" { 106 | ListItem::new("Super").style(Style::default().fg(Color::Green)) 107 | } else { 108 | ListItem::new("Super") 109 | }, 110 | if current_config.modkey == "Mod5" { 111 | ListItem::new("Mod5").style(Style::default().fg(Color::Green)) 112 | } else { 113 | ListItem::new("Mod5") 114 | }, 115 | ] 116 | }; 117 | let list = List::new(modkey_list) 118 | .block(Block::default().borders(Borders::NONE)) 119 | .style(Style::default().fg(Color::White)) 120 | .highlight_style(Style::default().add_modifier(Modifier::BOLD)) 121 | .highlight_symbol(">>"); 122 | 123 | if let PopupState::List(e) = current_popup_state { 124 | f.render_stateful_widget(list, centered_rect(30, 50, area), e); 125 | } else { 126 | bail!("Invalid popup state"); 127 | } 128 | 129 | Ok(()) 130 | } 131 | 132 | fn check_modifier(modifier: &Option, name: &str) -> bool { 133 | if let Some(Single(s)) = modifier { 134 | name == s 135 | } else { 136 | false 137 | } 138 | } 139 | 140 | pub fn max_window_width( 141 | current_popup_state: &mut PopupState, 142 | f: &mut Frame>, 143 | ) -> Result<()> { 144 | let block = Block::default() 145 | .borders(Borders::ALL) 146 | .border_style(Style::default().fg(Color::White)) 147 | .border_type(BorderType::Rounded) 148 | .style(Style::default().bg(Color::Black)) 149 | .title("Max Window Width"); 150 | 151 | let area = centered_rect(60, 4, f.size()); 152 | 153 | let chunks = Layout::default() 154 | .direction(Direction::Vertical) 155 | .constraints( 156 | [ 157 | Constraint::Ratio(1, 3), 158 | Constraint::Ratio(1, 3), 159 | Constraint::Ratio(1, 3), 160 | ] 161 | .as_ref(), 162 | ) 163 | .split(area); 164 | 165 | let string = if let PopupState::String(s) = current_popup_state { 166 | s.clone() 167 | } else { 168 | bail!("Invalid popup state"); 169 | }; 170 | 171 | let text = vec![Spans::from(vec![Span::raw(string)])]; 172 | 173 | let text = Paragraph::new(text) 174 | .style(Style::default().fg(Color::White).bg(Color::Black)) 175 | .alignment(Alignment::Center) 176 | .wrap(Wrap { trim: true }); 177 | 178 | f.render_widget(Clear, area); //this clears out the background 179 | f.render_widget(block, area); 180 | f.render_widget(text, *chunks.get(1).unwrap_or(&area)); 181 | 182 | Ok(()) 183 | } 184 | 185 | pub fn focus_behavior( 186 | current_config: &Config, 187 | current_popup_state: &mut PopupState, 188 | f: &mut Frame>, 189 | ) -> Result<()> { 190 | let block = Block::default() 191 | .borders(Borders::ALL) 192 | .border_style(Style::default().fg(Color::White)) 193 | .border_type(BorderType::Rounded) 194 | .style(Style::default().bg(Color::Black)) 195 | .title("Focus Behavior"); 196 | let area = centered_rect(60, 20, f.size()); 197 | f.render_widget(Clear, area); //this clears out the background 198 | f.render_widget(block, area); 199 | let mode_list = [ 200 | { 201 | if current_config.focus_behaviour == FocusBehaviour::Sloppy { 202 | ListItem::new("Sloppy").style(Style::default().fg(Color::Green)) 203 | } else { 204 | ListItem::new("Sloppy") 205 | } 206 | }, 207 | { 208 | if current_config.focus_behaviour == FocusBehaviour::ClickTo { 209 | ListItem::new("Click To").style(Style::default().fg(Color::Green)) 210 | } else { 211 | ListItem::new("Click To") 212 | } 213 | }, 214 | { 215 | if current_config.focus_behaviour == FocusBehaviour::Driven { 216 | ListItem::new("Driven").style(Style::default().fg(Color::Green)) 217 | } else { 218 | ListItem::new("Driven") 219 | } 220 | }, 221 | ]; 222 | let list = List::new(mode_list) 223 | .block(Block::default().borders(Borders::NONE)) 224 | .style(Style::default().fg(Color::White)) 225 | .highlight_style(Style::default().add_modifier(Modifier::BOLD)) 226 | .highlight_symbol(">>"); 227 | 228 | if let PopupState::List(e) = current_popup_state { 229 | f.render_stateful_widget(list, centered_rect(30, 50, area), e); 230 | } else { 231 | bail!("Invalid popup state"); 232 | } 233 | 234 | Ok(()) 235 | } 236 | 237 | pub fn insert_behavior( 238 | current_config: &Config, 239 | current_popup_state: &mut PopupState, 240 | f: &mut Frame>, 241 | ) -> Result<()> { 242 | let block = Block::default() 243 | .borders(Borders::ALL) 244 | .border_style(Style::default().fg(Color::White)) 245 | .border_type(BorderType::Rounded) 246 | .style(Style::default().bg(Color::Black)) 247 | .title("Insert Behavior"); 248 | let area = centered_rect(60, 20, f.size()); 249 | let mode_list = [ 250 | { 251 | if current_config.insert_behavior == InsertBehavior::Top { 252 | ListItem::new("Top").style(Style::default().fg(Color::Green)) 253 | } else { 254 | ListItem::new("Top") 255 | } 256 | }, 257 | { 258 | if current_config.insert_behavior == InsertBehavior::Bottom { 259 | ListItem::new("Bottom").style(Style::default().fg(Color::Green)) 260 | } else { 261 | ListItem::new("Bottom") 262 | } 263 | }, 264 | { 265 | if current_config.insert_behavior == InsertBehavior::BeforeCurrent { 266 | ListItem::new("Before Current").style(Style::default().fg(Color::Green)) 267 | } else { 268 | ListItem::new("Before Current") 269 | } 270 | }, 271 | { 272 | if current_config.insert_behavior == InsertBehavior::AfterCurrent { 273 | ListItem::new("After Current").style(Style::default().fg(Color::Green)) 274 | } else { 275 | ListItem::new("After Current") 276 | } 277 | }, 278 | ]; 279 | let list = List::new(mode_list) 280 | .block(Block::default().borders(Borders::NONE)) 281 | .style(Style::default().fg(Color::White)) 282 | .highlight_style(Style::default().add_modifier(Modifier::BOLD)) 283 | .highlight_symbol(">>"); 284 | 285 | f.render_widget(Clear, area); //this clears out the background 286 | f.render_widget(block, area); 287 | 288 | if let PopupState::List(e) = current_popup_state { 289 | f.render_stateful_widget(list, centered_rect(30, 50, area), e); 290 | } else { 291 | bail!("Invalid popup state"); 292 | } 293 | 294 | Ok(()) 295 | } 296 | 297 | pub fn layout_mode( 298 | current_config: &Config, 299 | current_popup_state: &mut PopupState, 300 | f: &mut Frame>, 301 | ) -> Result<()> { 302 | let block = Block::default() 303 | .borders(Borders::ALL) 304 | .border_style(Style::default().fg(Color::White)) 305 | .border_type(BorderType::Rounded) 306 | .style(Style::default().bg(Color::Black)) 307 | .title("Layout Mode"); 308 | let area = centered_rect(60, 20, f.size()); 309 | let mode_list = [ 310 | { 311 | if current_config.layout_mode == LayoutMode::Tag { 312 | ListItem::new("Tag").style(Style::default().fg(Color::Green)) 313 | } else { 314 | ListItem::new("Tag") 315 | } 316 | }, 317 | { 318 | if current_config.layout_mode == LayoutMode::Workspace { 319 | ListItem::new("Workspace").style(Style::default().fg(Color::Green)) 320 | } else { 321 | ListItem::new("Workspace") 322 | } 323 | }, 324 | ]; 325 | let list = List::new(mode_list) 326 | .block(Block::default().borders(Borders::NONE)) 327 | .style(Style::default().fg(Color::White)) 328 | .highlight_style(Style::default().add_modifier(Modifier::BOLD)) 329 | .highlight_symbol(">>"); 330 | 331 | f.render_widget(Clear, area); //this clears out the background 332 | f.render_widget(block, area); 333 | 334 | if let PopupState::List(e) = current_popup_state { 335 | f.render_stateful_widget(list, centered_rect(30, 50, area), e); 336 | } else { 337 | bail!("Invalid popup state"); 338 | } 339 | 340 | Ok(()) 341 | } 342 | 343 | pub fn layouts( 344 | current_popup_state: &mut PopupState, 345 | f: &mut Frame>, 346 | ) -> Result<()> { 347 | let block = Block::default() 348 | .borders(Borders::ALL) 349 | .border_style(Style::default().fg(Color::White)) 350 | .border_type(BorderType::Rounded) 351 | .style(Style::default().bg(Color::Black)) 352 | .title("Layouts"); 353 | let area = centered_rect(60, 20, f.size()); 354 | 355 | let mut layout_list = vec![ 356 | ListItem::new("MainAndVertStack"), 357 | ListItem::new("MainAndHorizontalStack"), 358 | ListItem::new("MainAndDeck"), 359 | ListItem::new("GridHorizontal"), 360 | ListItem::new("EvenHorizontal"), 361 | ListItem::new("EvenVertical"), 362 | ListItem::new("Fibonacci"), 363 | ListItem::new("LeftMain"), 364 | ListItem::new("CenterMain"), 365 | ListItem::new("CenterMainBalanced"), 366 | ListItem::new("CenterMainFluid"), 367 | ListItem::new("Monocle"), 368 | ListItem::new("RightWiderLeftStack"), 369 | ListItem::new("LeftWiderRightStack"), 370 | ]; 371 | 372 | if let PopupState::MultiList(e) = current_popup_state { 373 | for i in &e.selected { 374 | // we allow this here because clippy thinks 375 | // we are initializing a new thing here (probably because of the _ => {..}) 376 | // while we are just using the let _ to get rid of the result of mem::replace() 377 | #[allow(let_underscore_drop)] 378 | let _ = match i { 379 | 0 => mem::replace::>( 380 | layout_list.get_mut(0).try_unwrap()?, 381 | ListItem::new("MainAndVertStack").style(Style::default().fg(Color::Green)), 382 | ), 383 | 1 => mem::replace::>( 384 | layout_list.get_mut(1).try_unwrap()?, 385 | ListItem::new("MainAndHorizontalStack") 386 | .style(Style::default().fg(Color::Green)), 387 | ), 388 | 2 => mem::replace::>( 389 | layout_list.get_mut(2).try_unwrap()?, 390 | ListItem::new("MainAndDeck").style(Style::default().fg(Color::Green)), 391 | ), 392 | 3 => mem::replace::>( 393 | layout_list.get_mut(3).try_unwrap()?, 394 | ListItem::new("GridHorizontal").style(Style::default().fg(Color::Green)), 395 | ), 396 | 4 => mem::replace::>( 397 | layout_list.get_mut(4).try_unwrap()?, 398 | ListItem::new("EvenHorizontal").style(Style::default().fg(Color::Green)), 399 | ), 400 | 5 => mem::replace::>( 401 | layout_list.get_mut(5).try_unwrap()?, 402 | ListItem::new("EvenVertical").style(Style::default().fg(Color::Green)), 403 | ), 404 | 6 => mem::replace::>( 405 | layout_list.get_mut(6).try_unwrap()?, 406 | ListItem::new("Fibonacci").style(Style::default().fg(Color::Green)), 407 | ), 408 | 7 => mem::replace::>( 409 | layout_list.get_mut(7).try_unwrap()?, 410 | ListItem::new("LeftMain").style(Style::default().fg(Color::Green)), 411 | ), 412 | 8 => mem::replace::>( 413 | layout_list.get_mut(8).try_unwrap()?, 414 | ListItem::new("CenterMain").style(Style::default().fg(Color::Green)), 415 | ), 416 | 9 => mem::replace::>( 417 | layout_list.get_mut(9).try_unwrap()?, 418 | ListItem::new("CenterMainBalanced").style(Style::default().fg(Color::Green)), 419 | ), 420 | 10 => mem::replace::>( 421 | layout_list.get_mut(10).try_unwrap()?, 422 | ListItem::new("CenterMainFluid").style(Style::default().fg(Color::Green)), 423 | ), 424 | 11 => mem::replace::>( 425 | layout_list.get_mut(11).try_unwrap()?, 426 | ListItem::new("Monocle").style(Style::default().fg(Color::Green)), 427 | ), 428 | 12 => mem::replace::>( 429 | layout_list.get_mut(12).try_unwrap()?, 430 | ListItem::new("RightWiderLeftStack").style(Style::default().fg(Color::Green)), 431 | ), 432 | 13 => mem::replace::>( 433 | layout_list.get_mut(13).try_unwrap()?, 434 | ListItem::new("LeftWiderRightStack").style(Style::default().fg(Color::Green)), 435 | ), 436 | _ => ListItem::new(""), 437 | }; 438 | } 439 | } else { 440 | bail!("Invalid popup state"); 441 | } 442 | let list = List::new(layout_list) 443 | .block(Block::default().borders(Borders::NONE)) 444 | .style(Style::default().fg(Color::White)) 445 | .highlight_style(Style::default().add_modifier(Modifier::BOLD)) 446 | .highlight_symbol(">>"); 447 | 448 | f.render_widget(Clear, area); //this clears out the background 449 | f.render_widget(block, area); 450 | 451 | if let PopupState::MultiList(e) = current_popup_state { 452 | f.render_stateful_widget(list, centered_rect(75, 70, area), &mut e.liststate); 453 | } else { 454 | bail!("Invalid popup state"); 455 | } 456 | 457 | Ok(()) 458 | } 459 | 460 | //we allow this case if it saves having an explicit `Ok(())` after every call to this function 461 | #[allow(clippy::unnecessary_wraps)] 462 | pub fn saved(f: &mut Frame>) -> Result<()> { 463 | let block = Block::default() 464 | .borders(Borders::ALL) 465 | .border_style(Style::default().fg(Color::White)) 466 | .border_type(BorderType::Rounded) 467 | .style(Style::default().bg(Color::Black)); 468 | let mut area = centered_rect(60, 4, f.size()); 469 | area.height = 3; 470 | 471 | let text = vec![Spans::from(Span::raw("Saved"))]; 472 | 473 | let message = Paragraph::new(text) 474 | .style(Style::default().fg(Color::White).bg(Color::Black)) 475 | .alignment(Alignment::Center) 476 | .wrap(Wrap { trim: true }); 477 | 478 | f.render_widget(Clear, area); //this clears out the background 479 | f.render_widget(block, area); 480 | area.y += 1; 481 | f.render_widget(message, area); 482 | 483 | Ok(()) 484 | } 485 | 486 | pub fn text_input( 487 | current_popup_state: &mut PopupState, 488 | name: String, 489 | f: &mut Frame>, 490 | ) -> Result<()> { 491 | let block = Block::default() 492 | .borders(Borders::ALL) 493 | .border_style(Style::default().fg(Color::White)) 494 | .border_type(BorderType::Rounded) 495 | .style(Style::default().bg(Color::Black)) 496 | .title(name); 497 | 498 | let area = centered_rect(60, 4, f.size()); 499 | 500 | let chunks = Layout::default() 501 | .direction(Direction::Vertical) 502 | .constraints( 503 | [ 504 | Constraint::Ratio(1, 3), 505 | Constraint::Ratio(1, 3), 506 | Constraint::Ratio(1, 3), 507 | ] 508 | .as_ref(), 509 | ) 510 | .split(area); 511 | 512 | let string = if let PopupState::String(s) = current_popup_state { 513 | s.clone() 514 | } else { 515 | bail!("Invalid popup state") 516 | }; 517 | 518 | let text_len = if string.len() % 2 == 0 { 519 | string.len() 520 | } else { 521 | string.len() + 1 522 | } as u16; 523 | 524 | let text = vec![Spans::from(vec![Span::raw(string)])]; 525 | 526 | let text = Paragraph::new(text) 527 | .style(Style::default().fg(Color::White).bg(Color::Black)) 528 | .alignment(Alignment::Center) 529 | .wrap(Wrap { trim: true }); 530 | 531 | f.render_widget(Clear, area); //this clears out the background 532 | f.render_widget(block, area); 533 | f.render_widget(text, *chunks.get(1).unwrap_or(&area)); 534 | 535 | f.set_cursor( 536 | area.x + area.width / 2 + text_len / 2, 537 | area.y + area.height / 2, 538 | ); 539 | 540 | Ok(()) 541 | } 542 | 543 | pub fn counter( 544 | current_popup_state: &mut PopupState, 545 | name: String, 546 | f: &mut Frame>, 547 | ) -> Result<()> { 548 | let block = Block::default() 549 | .borders(Borders::ALL) 550 | .border_style(Style::default().fg(Color::White)) 551 | .border_type(BorderType::Rounded) 552 | .style(Style::default().bg(Color::Black)) 553 | .title(name); 554 | 555 | let area = centered_rect(60, 4, f.size()); 556 | 557 | let chunks = Layout::default() 558 | .direction(Direction::Vertical) 559 | .constraints( 560 | [ 561 | Constraint::Ratio(1, 3), 562 | Constraint::Ratio(1, 3), 563 | Constraint::Ratio(1, 3), 564 | ] 565 | .as_ref(), 566 | ) 567 | .split(area); 568 | 569 | let string = if let PopupState::Int { current, min, max } = current_popup_state { 570 | if current <= min { 571 | format!(" {} >", (*current)) 572 | } else if current >= max { 573 | format!("< {} ", (*current)) 574 | } else { 575 | format!("< {} >", (*current)) 576 | } 577 | } else { 578 | bail!("Invalid popup state") 579 | }; 580 | 581 | let text = vec![Spans::from(vec![Span::raw(string)])]; 582 | 583 | let text = Paragraph::new(text) 584 | .style(Style::default().fg(Color::White).bg(Color::Black)) 585 | .alignment(Alignment::Center) 586 | .wrap(Wrap { trim: true }); 587 | 588 | f.render_widget(Clear, area); 589 | f.render_widget(block, area); 590 | f.render_widget(text, *chunks.get(1).unwrap_or(&area)); 591 | 592 | Ok(()) 593 | } 594 | 595 | pub fn keybind_command( 596 | current_config: &Config, 597 | index: usize, 598 | current_popup_state: &mut PopupState, 599 | f: &mut Frame>, 600 | ) -> Result<()> { 601 | let block = Block::default() 602 | .borders(Borders::ALL) 603 | .border_style(Style::default().fg(Color::White)) 604 | .border_type(BorderType::Rounded) 605 | .style(Style::default().bg(Color::Black)) 606 | .title("Command"); 607 | let area = centered_rect(60, 20, f.size()); 608 | let mut command_list = [ 609 | ListItem::new("Execute"), 610 | ListItem::new("CloseWindow"), 611 | ListItem::new("SwapTags"), 612 | ListItem::new("SoftReload"), 613 | ListItem::new("HardReload"), 614 | ListItem::new("ToggleScratchPad"), 615 | ListItem::new("ToggleFullScreen"), 616 | ListItem::new("ToggleSticky"), 617 | ListItem::new("GotoTag"), 618 | ListItem::new("ReturnToLastTag"), 619 | ListItem::new("FloatingToTile"), 620 | ListItem::new("TileToFloating"), 621 | ListItem::new("ToggleFloating"), 622 | ListItem::new("MoveWindowUp"), 623 | ListItem::new("MoveWindowDown"), 624 | ListItem::new("MoveWindowTop"), 625 | ListItem::new("FocusNextTag"), 626 | ListItem::new("FocusPreviousTag"), 627 | ListItem::new("FocusWindow"), 628 | ListItem::new("FocusWindowUp"), 629 | ListItem::new("FocusWindowDown"), 630 | ListItem::new("FocusWindowTop"), 631 | ListItem::new("FocusWorkspaceNext"), 632 | ListItem::new("FocusWorkspacePrevious"), 633 | ListItem::new("MoveToTag"), 634 | ListItem::new("MoveToLastWorkspace"), 635 | ListItem::new("MoveWindowToNextWorkspace"), 636 | ListItem::new("MoveWindowToPreviousWorkspace"), 637 | ListItem::new("MouseMoveWindow"), 638 | ListItem::new("NextLayout"), 639 | ListItem::new("PreviousLayout"), 640 | ListItem::new("SetLayout"), 641 | ListItem::new("RotateTag"), 642 | ListItem::new("IncreaseMainWidth"), 643 | ListItem::new("DecreaseMainWidth"), 644 | ListItem::new("SetMarginMultiplier"), 645 | ListItem::new("UnloadTheme"), 646 | ListItem::new("LoadTheme"), 647 | ListItem::new("CloseAllOtherWindows"), 648 | ]; 649 | 650 | match current_config.keybind.get(index).try_unwrap()?.command { 651 | BaseCommand::Execute => mem::replace::( 652 | &mut command_list[0], 653 | ListItem::new("Execute").style(Style::default().fg(Color::Green)), 654 | ), 655 | BaseCommand::CloseWindow => mem::replace::( 656 | &mut command_list[1], 657 | ListItem::new("CloseWindow").style(Style::default().fg(Color::Green)), 658 | ), 659 | BaseCommand::SwapTags => mem::replace::( 660 | &mut command_list[2], 661 | ListItem::new("SwapTags").style(Style::default().fg(Color::Green)), 662 | ), 663 | BaseCommand::SoftReload => mem::replace::( 664 | &mut command_list[3], 665 | ListItem::new("SoftReload").style(Style::default().fg(Color::Green)), 666 | ), 667 | BaseCommand::HardReload => mem::replace::( 668 | &mut command_list[4], 669 | ListItem::new("HardReload").style(Style::default().fg(Color::Green)), 670 | ), 671 | BaseCommand::ToggleScratchPad => mem::replace::( 672 | &mut command_list[5], 673 | ListItem::new("ToggleScratchPad").style(Style::default().fg(Color::Green)), 674 | ), 675 | BaseCommand::ToggleFullScreen => mem::replace::( 676 | &mut command_list[6], 677 | ListItem::new("ToggleFullScreen").style(Style::default().fg(Color::Green)), 678 | ), 679 | BaseCommand::ToggleSticky => mem::replace::( 680 | &mut command_list[7], 681 | ListItem::new("ToggleSticky").style(Style::default().fg(Color::Green)), 682 | ), 683 | BaseCommand::GotoTag => mem::replace::( 684 | &mut command_list[8], 685 | ListItem::new("GotoTag").style(Style::default().fg(Color::Green)), 686 | ), 687 | BaseCommand::ReturnToLastTag => mem::replace::( 688 | &mut command_list[9], 689 | ListItem::new("ReturnToLastTag").style(Style::default().fg(Color::Green)), 690 | ), 691 | BaseCommand::FloatingToTile => mem::replace::( 692 | &mut command_list[10], 693 | ListItem::new("FloatingToTile").style(Style::default().fg(Color::Green)), 694 | ), 695 | BaseCommand::TileToFloating => mem::replace::( 696 | &mut command_list[11], 697 | ListItem::new("TileToFloating").style(Style::default().fg(Color::Green)), 698 | ), 699 | BaseCommand::ToggleFloating => mem::replace::( 700 | &mut command_list[12], 701 | ListItem::new("ToggleFloating").style(Style::default().fg(Color::Green)), 702 | ), 703 | BaseCommand::MoveWindowUp => mem::replace::( 704 | &mut command_list[13], 705 | ListItem::new("MoveWindowUp").style(Style::default().fg(Color::Green)), 706 | ), 707 | BaseCommand::MoveWindowDown => mem::replace::( 708 | &mut command_list[14], 709 | ListItem::new("MoveWindowDown").style(Style::default().fg(Color::Green)), 710 | ), 711 | BaseCommand::MoveWindowTop => mem::replace::( 712 | &mut command_list[15], 713 | ListItem::new("MoveWindowTop ").style(Style::default().fg(Color::Green)), 714 | ), 715 | BaseCommand::FocusNextTag => mem::replace::( 716 | &mut command_list[16], 717 | ListItem::new("FocusNextTag ").style(Style::default().fg(Color::Green)), 718 | ), 719 | BaseCommand::FocusPreviousTag => mem::replace::( 720 | &mut command_list[17], 721 | ListItem::new("FocusPreviousTag").style(Style::default().fg(Color::Green)), 722 | ), 723 | BaseCommand::FocusWindow => mem::replace::( 724 | &mut command_list[18], 725 | ListItem::new("FocusWindow").style(Style::default().fg(Color::Green)), 726 | ), 727 | BaseCommand::FocusWindowUp => mem::replace::( 728 | &mut command_list[19], 729 | ListItem::new("FocusWindowUp").style(Style::default().fg(Color::Green)), 730 | ), 731 | BaseCommand::FocusWindowDown => mem::replace::( 732 | &mut command_list[20], 733 | ListItem::new("FocusWindowDown").style(Style::default().fg(Color::Green)), 734 | ), 735 | BaseCommand::FocusWindowTop => mem::replace::( 736 | &mut command_list[21], 737 | ListItem::new("FocusWindowTop ").style(Style::default().fg(Color::Green)), 738 | ), 739 | BaseCommand::FocusWorkspaceNext => mem::replace::( 740 | &mut command_list[22], 741 | ListItem::new("FocusWorkspaceNext").style(Style::default().fg(Color::Green)), 742 | ), 743 | BaseCommand::FocusWorkspacePrevious => mem::replace::( 744 | &mut command_list[23], 745 | ListItem::new("FocusWorkspacePrevious").style(Style::default().fg(Color::Green)), 746 | ), 747 | BaseCommand::MoveToTag => mem::replace::( 748 | &mut command_list[24], 749 | ListItem::new("MoveToTag").style(Style::default().fg(Color::Green)), 750 | ), 751 | BaseCommand::MoveToLastWorkspace => mem::replace::( 752 | &mut command_list[25], 753 | ListItem::new("MoveToLastWorkspace").style(Style::default().fg(Color::Green)), 754 | ), 755 | BaseCommand::MoveWindowToNextWorkspace => mem::replace::( 756 | &mut command_list[26], 757 | ListItem::new("MoveWindowToNextWorkspace ").style(Style::default().fg(Color::Green)), 758 | ), 759 | BaseCommand::MoveWindowToPreviousWorkspace => mem::replace::( 760 | &mut command_list[27], 761 | ListItem::new("MoveWindowToPreviousWorkspace").style(Style::default().fg(Color::Green)), 762 | ), 763 | BaseCommand::MouseMoveWindow => mem::replace::( 764 | &mut command_list[28], 765 | ListItem::new("MouseMoveWindow").style(Style::default().fg(Color::Green)), 766 | ), 767 | BaseCommand::NextLayout => mem::replace::( 768 | &mut command_list[29], 769 | ListItem::new("NextLayout").style(Style::default().fg(Color::Green)), 770 | ), 771 | BaseCommand::PreviousLayout => mem::replace::( 772 | &mut command_list[30], 773 | ListItem::new("PreviousLayout").style(Style::default().fg(Color::Green)), 774 | ), 775 | BaseCommand::SetLayout => mem::replace::( 776 | &mut command_list[31], 777 | ListItem::new("SetLayout").style(Style::default().fg(Color::Green)), 778 | ), 779 | BaseCommand::RotateTag => mem::replace::( 780 | &mut command_list[32], 781 | ListItem::new("RotateTag").style(Style::default().fg(Color::Green)), 782 | ), 783 | BaseCommand::IncreaseMainWidth => mem::replace::( 784 | &mut command_list[33], 785 | ListItem::new("IncreaseMainWidth").style(Style::default().fg(Color::Green)), 786 | ), 787 | BaseCommand::DecreaseMainWidth => mem::replace::( 788 | &mut command_list[34], 789 | ListItem::new("DecreaseMainWidth").style(Style::default().fg(Color::Green)), 790 | ), 791 | BaseCommand::SetMarginMultiplier => mem::replace::( 792 | &mut command_list[35], 793 | ListItem::new("SetMarginMultiplier").style(Style::default().fg(Color::Green)), 794 | ), 795 | BaseCommand::UnloadTheme => mem::replace::( 796 | &mut command_list[36], 797 | ListItem::new("UnloadTheme").style(Style::default().fg(Color::Green)), 798 | ), 799 | BaseCommand::LoadTheme => mem::replace::( 800 | &mut command_list[37], 801 | ListItem::new("LoadTheme").style(Style::default().fg(Color::Green)), 802 | ), 803 | BaseCommand::CloseAllOtherWindows => mem::replace::( 804 | &mut command_list[38], 805 | ListItem::new("CloseAllOtherWindows").style(Style::default().fg(Color::Green)), 806 | ), 807 | }; 808 | 809 | let list = List::new(command_list) 810 | .block(Block::default().borders(Borders::NONE)) 811 | .style(Style::default().fg(Color::White)) 812 | .highlight_style(Style::default().add_modifier(Modifier::BOLD)) 813 | .highlight_symbol(">>"); 814 | 815 | f.render_widget(Clear, area); //this clears out the background 816 | f.render_widget(block, area); 817 | 818 | if let PopupState::List(e) = current_popup_state { 819 | f.render_stateful_widget(list, centered_rect(60, 50, area), e); 820 | } else { 821 | bail!("Invalid popup state"); 822 | } 823 | 824 | Ok(()) 825 | } 826 | 827 | pub fn keybind_modkey( 828 | current_popup_state: &mut PopupState, 829 | f: &mut Frame>, 830 | ) -> Result<()> { 831 | let block = Block::default() 832 | .borders(Borders::ALL) 833 | .border_style(Style::default().fg(Color::White)) 834 | .border_type(BorderType::Rounded) 835 | .style(Style::default().bg(Color::Black)) 836 | .title("Modifier"); 837 | let area = centered_rect(60, 20, f.size()); 838 | f.render_widget(Clear, area); //this clears out the background 839 | f.render_widget(block, area); 840 | let state = if let PopupState::MultiList(s) = current_popup_state { 841 | s 842 | } else { 843 | bail!("Invalid popup state") 844 | }; 845 | let modkey_list = [ 846 | if state.selected.contains(&0) { 847 | ListItem::new("None").style(Style::default().fg(Color::Green)) 848 | } else { 849 | ListItem::new("None") 850 | }, 851 | if state.selected.contains(&1) { 852 | ListItem::new("Shift").style(Style::default().fg(Color::Green)) 853 | } else { 854 | ListItem::new("Shift") 855 | }, 856 | if state.selected.contains(&2) { 857 | ListItem::new("Control").style(Style::default().fg(Color::Green)) 858 | } else { 859 | ListItem::new("Control") 860 | }, 861 | if state.selected.contains(&3) { 862 | ListItem::new("Alt").style(Style::default().fg(Color::Green)) 863 | } else { 864 | ListItem::new("Alt") 865 | }, 866 | if state.selected.contains(&4) { 867 | ListItem::new("Mod3").style(Style::default().fg(Color::Green)) 868 | } else { 869 | ListItem::new("Mod3") 870 | }, 871 | if state.selected.contains(&5) { 872 | ListItem::new("Super").style(Style::default().fg(Color::Green)) 873 | } else { 874 | ListItem::new("Super") 875 | }, 876 | if state.selected.contains(&6) { 877 | ListItem::new("Mod5").style(Style::default().fg(Color::Green)) 878 | } else { 879 | ListItem::new("Mod5") 880 | }, 881 | if state.selected.contains(&7) { 882 | ListItem::new("modkey").style(Style::default().fg(Color::Green)) 883 | } else { 884 | ListItem::new("modkey") 885 | }, 886 | ]; 887 | let list = List::new(modkey_list) 888 | .block(Block::default().borders(Borders::NONE)) 889 | .style(Style::default().fg(Color::White)) 890 | .highlight_style(Style::default().add_modifier(Modifier::BOLD)) 891 | .highlight_symbol(">>"); 892 | 893 | f.render_stateful_widget(list, centered_rect(30, 50, area), &mut state.liststate); 894 | 895 | Ok(()) 896 | } 897 | 898 | pub fn keybind_key( 899 | current_popup_state: &mut PopupState, 900 | name: String, 901 | f: &mut Frame>, 902 | ) -> Result<()> { 903 | let block = Block::default() 904 | .borders(Borders::ALL) 905 | .border_style(Style::default().fg(Color::White)) 906 | .border_type(BorderType::Rounded) 907 | .style(Style::default().bg(Color::Black)) 908 | .title(name); 909 | 910 | let mut area = centered_rect(60, 4, f.size()); 911 | 912 | area.y -= area.height / 2; 913 | 914 | let chunks = Layout::default() 915 | .direction(Direction::Vertical) 916 | .constraints( 917 | [ 918 | Constraint::Ratio(1, 3), 919 | Constraint::Ratio(1, 3), 920 | Constraint::Ratio(1, 3), 921 | ] 922 | .as_ref(), 923 | ) 924 | .split(area); 925 | 926 | let string = if let PopupState::String(s) = current_popup_state { 927 | s.clone() 928 | } else { 929 | bail!("Invalid popup state") 930 | }; 931 | 932 | let text_len = if string.len() % 2 == 0 { 933 | string.len() 934 | } else { 935 | string.len() + 1 936 | } as u16; 937 | 938 | let text = vec![Spans::from(vec![Span::raw(string)])]; 939 | 940 | let text = Paragraph::new(text) 941 | .style(Style::default().fg(Color::White).bg(Color::Black)) 942 | .alignment(Alignment::Center) 943 | .wrap(Wrap { trim: true }); 944 | 945 | f.render_widget(Clear, area); //this clears out the background 946 | f.render_widget(block, area); 947 | f.render_widget(text, *chunks.get(1).unwrap_or(&area)); 948 | 949 | f.set_cursor( 950 | area.x + area.width / 2 + text_len / 2, 951 | area.y + area.height / 2, 952 | ); 953 | 954 | let mut block = Block::default() 955 | .borders(Borders::ALL) 956 | .border_type(BorderType::Rounded) 957 | .style(Style::default().bg(Color::Black)); 958 | 959 | let mut indicator_area = centered_rect(60, 4, f.size()); 960 | indicator_area.y += area.height; 961 | 962 | let chunks_indicator = Layout::default() 963 | .direction(Direction::Vertical) 964 | .constraints( 965 | [ 966 | Constraint::Ratio(1, 3), 967 | Constraint::Ratio(1, 3), 968 | Constraint::Ratio(1, 3), 969 | ] 970 | .as_ref(), 971 | ) 972 | .split(indicator_area); 973 | 974 | let indicator = if let PopupState::String(s) = current_popup_state { 975 | if into_keysym(s.as_str()).is_some() { 976 | let text = vec![Spans::from(vec![Span::raw("Key Ok")])]; 977 | block = block.border_style(Style::default().fg(Color::Green)); 978 | Paragraph::new(text) 979 | .style(Style::default().fg(Color::Green).bg(Color::Black)) 980 | .alignment(Alignment::Center) 981 | .wrap(Wrap { trim: true }) 982 | } else { 983 | let text = vec![Spans::from(vec![Span::raw("Key Doesn't Exist!")])]; 984 | block = block.border_style(Style::default().fg(Color::Red)); 985 | Paragraph::new(text) 986 | .style(Style::default().fg(Color::Red).bg(Color::Black)) 987 | .alignment(Alignment::Center) 988 | .wrap(Wrap { trim: true }) 989 | } 990 | } else { 991 | bail!("Invalid popup state") 992 | }; 993 | 994 | f.render_widget(Clear, indicator_area); //this clears out the background 995 | f.render_widget(block, indicator_area); 996 | f.render_widget( 997 | indicator, 998 | *chunks_indicator.get(1).unwrap_or(&indicator_area), 999 | ); 1000 | 1001 | Ok(()) 1002 | } 1003 | -------------------------------------------------------------------------------- /src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | use ::tui::layout::{Constraint, Direction, Layout, Rect}; 2 | use anyhow::{bail, Context, Result}; 3 | 4 | mod x11_keys; 5 | pub(crate) mod xkeysym_lookup; 6 | 7 | pub(crate) fn centered_rect(percent_x: u16, percent_y: u16, r: Rect) -> Rect { 8 | let popup_layout = Layout::default() 9 | .direction(Direction::Vertical) 10 | .constraints( 11 | [ 12 | Constraint::Percentage((100 - percent_y) / 2), 13 | Constraint::Min(3), 14 | Constraint::Percentage((100 - percent_y) / 2), 15 | ] 16 | .as_ref(), 17 | ) 18 | .split(r); 19 | 20 | Layout::default() 21 | .direction(Direction::Horizontal) 22 | .constraints( 23 | [ 24 | Constraint::Percentage((100 - percent_x) / 2), 25 | Constraint::Percentage(percent_x), 26 | Constraint::Percentage((100 - percent_x) / 2), 27 | ] 28 | .as_ref(), 29 | ) 30 | .split(popup_layout[1])[1] 31 | } 32 | 33 | //used to transform an option into a result to be able to easily 34 | // propagate the fact that is was empty instead of panicking 35 | pub trait TryUnwrap { 36 | fn try_unwrap(self) -> Result; 37 | } 38 | 39 | impl TryUnwrap for Option { 40 | fn try_unwrap(self) -> Result { 41 | self.context("called `Option::unwrap()` on a `None` value") 42 | } 43 | } 44 | 45 | pub trait TryRemove { 46 | fn try_remove(&mut self, index: usize) -> Result; 47 | } 48 | 49 | impl TryRemove for Vec { 50 | fn try_remove(&mut self, index: usize) -> Result { 51 | if index < self.len() { 52 | Ok(self.remove(index)) 53 | } else { 54 | bail!("Index out of bounds") 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/utils/x11_keys.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_upper_case_globals)] 2 | #![allow(unused)] 3 | #![allow(clippy::unreadable_literal)] 4 | // x11-rs: Rust bindings for X11 libraries 5 | // The X11 libraries are available under the MIT license. 6 | // These bindings are public domain. 7 | 8 | use std::os::raw::c_uint; 9 | 10 | pub const XK_BackSpace: c_uint = 0xFF08; 11 | pub const XK_Tab: c_uint = 0xFF09; 12 | pub const XK_Linefeed: c_uint = 0xFF0A; 13 | pub const XK_Clear: c_uint = 0xFF0B; 14 | pub const XK_Return: c_uint = 0xFF0D; 15 | pub const XK_Pause: c_uint = 0xFF13; 16 | pub const XK_Scroll_Lock: c_uint = 0xFF14; 17 | pub const XK_Sys_Req: c_uint = 0xFF15; 18 | pub const XK_Escape: c_uint = 0xFF1B; 19 | pub const XK_Delete: c_uint = 0xFFFF; 20 | pub const XK_Multi_key: c_uint = 0xFF20; 21 | pub const XK_Kanji: c_uint = 0xFF21; 22 | pub const XK_Muhenkan: c_uint = 0xFF22; 23 | pub const XK_Henkan_Mode: c_uint = 0xFF23; 24 | pub const XK_Henkan: c_uint = 0xFF23; 25 | pub const XK_Romaji: c_uint = 0xFF24; 26 | pub const XK_Hiragana: c_uint = 0xFF25; 27 | pub const XK_Katakana: c_uint = 0xFF26; 28 | pub const XK_Hiragana_Katakana: c_uint = 0xFF27; 29 | pub const XK_Zenkaku: c_uint = 0xFF28; 30 | pub const XK_Hankaku: c_uint = 0xFF29; 31 | pub const XK_Zenkaku_Hankaku: c_uint = 0xFF2A; 32 | pub const XK_Touroku: c_uint = 0xFF2B; 33 | pub const XK_Massyo: c_uint = 0xFF2C; 34 | pub const XK_Kana_Lock: c_uint = 0xFF2D; 35 | pub const XK_Kana_Shift: c_uint = 0xFF2E; 36 | pub const XK_Eisu_Shift: c_uint = 0xFF2F; 37 | pub const XK_Eisu_toggle: c_uint = 0xFF30; 38 | pub const XK_Home: c_uint = 0xFF50; 39 | pub const XK_Left: c_uint = 0xFF51; 40 | pub const XK_Up: c_uint = 0xFF52; 41 | pub const XK_Right: c_uint = 0xFF53; 42 | pub const XK_Down: c_uint = 0xFF54; 43 | pub const XK_Prior: c_uint = 0xFF55; 44 | pub const XK_Page_Up: c_uint = 0xFF55; 45 | pub const XK_Next: c_uint = 0xFF56; 46 | pub const XK_Page_Down: c_uint = 0xFF56; 47 | pub const XK_End: c_uint = 0xFF57; 48 | pub const XK_Begin: c_uint = 0xFF58; 49 | pub const XK_Win_L: c_uint = 0xFF5B; 50 | pub const XK_Win_R: c_uint = 0xFF5C; 51 | pub const XK_App: c_uint = 0xFF5D; 52 | pub const XK_Select: c_uint = 0xFF60; 53 | pub const XK_Print: c_uint = 0xFF61; 54 | pub const XK_Execute: c_uint = 0xFF62; 55 | pub const XK_Insert: c_uint = 0xFF63; 56 | pub const XK_Undo: c_uint = 0xFF65; 57 | pub const XK_Redo: c_uint = 0xFF66; 58 | pub const XK_Menu: c_uint = 0xFF67; 59 | pub const XK_Find: c_uint = 0xFF68; 60 | pub const XK_Cancel: c_uint = 0xFF69; 61 | pub const XK_Help: c_uint = 0xFF6A; 62 | pub const XK_Break: c_uint = 0xFF6B; 63 | pub const XK_Mode_switch: c_uint = 0xFF7E; 64 | pub const XK_script_switch: c_uint = 0xFF7E; 65 | pub const XK_Num_Lock: c_uint = 0xFF7F; 66 | pub const XK_KP_Space: c_uint = 0xFF80; 67 | pub const XK_KP_Tab: c_uint = 0xFF89; 68 | pub const XK_KP_Enter: c_uint = 0xFF8D; 69 | pub const XK_KP_F1: c_uint = 0xFF91; 70 | pub const XK_KP_F2: c_uint = 0xFF92; 71 | pub const XK_KP_F3: c_uint = 0xFF93; 72 | pub const XK_KP_F4: c_uint = 0xFF94; 73 | pub const XK_KP_Home: c_uint = 0xFF95; 74 | pub const XK_KP_Left: c_uint = 0xFF96; 75 | pub const XK_KP_Up: c_uint = 0xFF97; 76 | pub const XK_KP_Right: c_uint = 0xFF98; 77 | pub const XK_KP_Down: c_uint = 0xFF99; 78 | pub const XK_KP_Prior: c_uint = 0xFF9A; 79 | pub const XK_KP_Page_Up: c_uint = 0xFF9A; 80 | pub const XK_KP_Next: c_uint = 0xFF9B; 81 | pub const XK_KP_Page_Down: c_uint = 0xFF9B; 82 | pub const XK_KP_End: c_uint = 0xFF9C; 83 | pub const XK_KP_Begin: c_uint = 0xFF9D; 84 | pub const XK_KP_Insert: c_uint = 0xFF9E; 85 | pub const XK_KP_Delete: c_uint = 0xFF9F; 86 | pub const XK_KP_Equal: c_uint = 0xFFBD; 87 | pub const XK_KP_Multiply: c_uint = 0xFFAA; 88 | pub const XK_KP_Add: c_uint = 0xFFAB; 89 | pub const XK_KP_Separator: c_uint = 0xFFAC; 90 | pub const XK_KP_Subtract: c_uint = 0xFFAD; 91 | pub const XK_KP_Decimal: c_uint = 0xFFAE; 92 | pub const XK_KP_Divide: c_uint = 0xFFAF; 93 | pub const XK_KP_0: c_uint = 0xFFB0; 94 | pub const XK_KP_1: c_uint = 0xFFB1; 95 | pub const XK_KP_2: c_uint = 0xFFB2; 96 | pub const XK_KP_3: c_uint = 0xFFB3; 97 | pub const XK_KP_4: c_uint = 0xFFB4; 98 | pub const XK_KP_5: c_uint = 0xFFB5; 99 | pub const XK_KP_6: c_uint = 0xFFB6; 100 | pub const XK_KP_7: c_uint = 0xFFB7; 101 | pub const XK_KP_8: c_uint = 0xFFB8; 102 | pub const XK_KP_9: c_uint = 0xFFB9; 103 | pub const XK_F1: c_uint = 0xFFBE; 104 | pub const XK_F2: c_uint = 0xFFBF; 105 | pub const XK_F3: c_uint = 0xFFC0; 106 | pub const XK_F4: c_uint = 0xFFC1; 107 | pub const XK_F5: c_uint = 0xFFC2; 108 | pub const XK_F6: c_uint = 0xFFC3; 109 | pub const XK_F7: c_uint = 0xFFC4; 110 | pub const XK_F8: c_uint = 0xFFC5; 111 | pub const XK_F9: c_uint = 0xFFC6; 112 | pub const XK_F10: c_uint = 0xFFC7; 113 | pub const XK_F11: c_uint = 0xFFC8; 114 | pub const XK_L1: c_uint = 0xFFC8; 115 | pub const XK_F12: c_uint = 0xFFC9; 116 | pub const XK_L2: c_uint = 0xFFC9; 117 | pub const XK_F13: c_uint = 0xFFCA; 118 | pub const XK_L3: c_uint = 0xFFCA; 119 | pub const XK_F14: c_uint = 0xFFCB; 120 | pub const XK_L4: c_uint = 0xFFCB; 121 | pub const XK_F15: c_uint = 0xFFCC; 122 | pub const XK_L5: c_uint = 0xFFCC; 123 | pub const XK_F16: c_uint = 0xFFCD; 124 | pub const XK_L6: c_uint = 0xFFCD; 125 | pub const XK_F17: c_uint = 0xFFCE; 126 | pub const XK_L7: c_uint = 0xFFCE; 127 | pub const XK_F18: c_uint = 0xFFCF; 128 | pub const XK_L8: c_uint = 0xFFCF; 129 | pub const XK_F19: c_uint = 0xFFD0; 130 | pub const XK_L9: c_uint = 0xFFD0; 131 | pub const XK_F20: c_uint = 0xFFD1; 132 | pub const XK_L10: c_uint = 0xFFD1; 133 | pub const XK_F21: c_uint = 0xFFD2; 134 | pub const XK_R1: c_uint = 0xFFD2; 135 | pub const XK_F22: c_uint = 0xFFD3; 136 | pub const XK_R2: c_uint = 0xFFD3; 137 | pub const XK_F23: c_uint = 0xFFD4; 138 | pub const XK_R3: c_uint = 0xFFD4; 139 | pub const XK_F24: c_uint = 0xFFD5; 140 | pub const XK_R4: c_uint = 0xFFD5; 141 | pub const XK_F25: c_uint = 0xFFD6; 142 | pub const XK_R5: c_uint = 0xFFD6; 143 | pub const XK_F26: c_uint = 0xFFD7; 144 | pub const XK_R6: c_uint = 0xFFD7; 145 | pub const XK_F27: c_uint = 0xFFD8; 146 | pub const XK_R7: c_uint = 0xFFD8; 147 | pub const XK_F28: c_uint = 0xFFD9; 148 | pub const XK_R8: c_uint = 0xFFD9; 149 | pub const XK_F29: c_uint = 0xFFDA; 150 | pub const XK_R9: c_uint = 0xFFDA; 151 | pub const XK_F30: c_uint = 0xFFDB; 152 | pub const XK_R10: c_uint = 0xFFDB; 153 | pub const XK_F31: c_uint = 0xFFDC; 154 | pub const XK_R11: c_uint = 0xFFDC; 155 | pub const XK_F32: c_uint = 0xFFDD; 156 | pub const XK_R12: c_uint = 0xFFDD; 157 | pub const XK_F33: c_uint = 0xFFDE; 158 | pub const XK_R13: c_uint = 0xFFDE; 159 | pub const XK_F34: c_uint = 0xFFDF; 160 | pub const XK_R14: c_uint = 0xFFDF; 161 | pub const XK_F35: c_uint = 0xFFE0; 162 | pub const XK_R15: c_uint = 0xFFE0; 163 | pub const XK_Shift_L: c_uint = 0xFFE1; 164 | pub const XK_Shift_R: c_uint = 0xFFE2; 165 | pub const XK_Control_L: c_uint = 0xFFE3; 166 | pub const XK_Control_R: c_uint = 0xFFE4; 167 | pub const XK_Caps_Lock: c_uint = 0xFFE5; 168 | pub const XK_Shift_Lock: c_uint = 0xFFE6; 169 | pub const XK_Meta_L: c_uint = 0xFFE7; 170 | pub const XK_Meta_R: c_uint = 0xFFE8; 171 | pub const XK_Alt_L: c_uint = 0xFFE9; 172 | pub const XK_Alt_R: c_uint = 0xFFEA; 173 | pub const XK_Super_L: c_uint = 0xFFEB; 174 | pub const XK_Super_R: c_uint = 0xFFEC; 175 | pub const XK_Hyper_L: c_uint = 0xFFED; 176 | pub const XK_Hyper_R: c_uint = 0xFFEE; 177 | pub const XK_space: c_uint = 0x020; 178 | pub const XK_exclam: c_uint = 0x021; 179 | pub const XK_quotedbl: c_uint = 0x022; 180 | pub const XK_numbersign: c_uint = 0x023; 181 | pub const XK_dollar: c_uint = 0x024; 182 | pub const XK_percent: c_uint = 0x025; 183 | pub const XK_ampersand: c_uint = 0x026; 184 | pub const XK_apostrophe: c_uint = 0x027; 185 | pub const XK_quoteright: c_uint = 0x027; 186 | pub const XK_parenleft: c_uint = 0x028; 187 | pub const XK_parenright: c_uint = 0x029; 188 | pub const XK_asterisk: c_uint = 0x02a; 189 | pub const XK_plus: c_uint = 0x02b; 190 | pub const XK_comma: c_uint = 0x02c; 191 | pub const XK_minus: c_uint = 0x02d; 192 | pub const XK_period: c_uint = 0x02e; 193 | pub const XK_slash: c_uint = 0x02f; 194 | pub const XK_0: c_uint = 0x030; 195 | pub const XK_1: c_uint = 0x031; 196 | pub const XK_2: c_uint = 0x032; 197 | pub const XK_3: c_uint = 0x033; 198 | pub const XK_4: c_uint = 0x034; 199 | pub const XK_5: c_uint = 0x035; 200 | pub const XK_6: c_uint = 0x036; 201 | pub const XK_7: c_uint = 0x037; 202 | pub const XK_8: c_uint = 0x038; 203 | pub const XK_9: c_uint = 0x039; 204 | pub const XK_colon: c_uint = 0x03a; 205 | pub const XK_semicolon: c_uint = 0x03b; 206 | pub const XK_less: c_uint = 0x03c; 207 | pub const XK_equal: c_uint = 0x03d; 208 | pub const XK_greater: c_uint = 0x03e; 209 | pub const XK_question: c_uint = 0x03f; 210 | pub const XK_at: c_uint = 0x040; 211 | pub const XK_A: c_uint = 0x041; 212 | pub const XK_B: c_uint = 0x042; 213 | pub const XK_C: c_uint = 0x043; 214 | pub const XK_D: c_uint = 0x044; 215 | pub const XK_E: c_uint = 0x045; 216 | pub const XK_F: c_uint = 0x046; 217 | pub const XK_G: c_uint = 0x047; 218 | pub const XK_H: c_uint = 0x048; 219 | pub const XK_I: c_uint = 0x049; 220 | pub const XK_J: c_uint = 0x04a; 221 | pub const XK_K: c_uint = 0x04b; 222 | pub const XK_L: c_uint = 0x04c; 223 | pub const XK_M: c_uint = 0x04d; 224 | pub const XK_N: c_uint = 0x04e; 225 | pub const XK_O: c_uint = 0x04f; 226 | pub const XK_P: c_uint = 0x050; 227 | pub const XK_Q: c_uint = 0x051; 228 | pub const XK_R: c_uint = 0x052; 229 | pub const XK_S: c_uint = 0x053; 230 | pub const XK_T: c_uint = 0x054; 231 | pub const XK_U: c_uint = 0x055; 232 | pub const XK_V: c_uint = 0x056; 233 | pub const XK_W: c_uint = 0x057; 234 | pub const XK_X: c_uint = 0x058; 235 | pub const XK_Y: c_uint = 0x059; 236 | pub const XK_Z: c_uint = 0x05a; 237 | pub const XK_bracketleft: c_uint = 0x05b; 238 | pub const XK_backslash: c_uint = 0x05c; 239 | pub const XK_bracketright: c_uint = 0x05d; 240 | pub const XK_asciicircum: c_uint = 0x05e; 241 | pub const XK_underscore: c_uint = 0x05f; 242 | pub const XK_grave: c_uint = 0x060; 243 | pub const XK_quoteleft: c_uint = 0x060; 244 | pub const XK_a: c_uint = 0x061; 245 | pub const XK_b: c_uint = 0x062; 246 | pub const XK_c: c_uint = 0x063; 247 | pub const XK_d: c_uint = 0x064; 248 | pub const XK_e: c_uint = 0x065; 249 | pub const XK_f: c_uint = 0x066; 250 | pub const XK_g: c_uint = 0x067; 251 | pub const XK_h: c_uint = 0x068; 252 | pub const XK_i: c_uint = 0x069; 253 | pub const XK_j: c_uint = 0x06a; 254 | pub const XK_k: c_uint = 0x06b; 255 | pub const XK_l: c_uint = 0x06c; 256 | pub const XK_m: c_uint = 0x06d; 257 | pub const XK_n: c_uint = 0x06e; 258 | pub const XK_o: c_uint = 0x06f; 259 | pub const XK_p: c_uint = 0x070; 260 | pub const XK_q: c_uint = 0x071; 261 | pub const XK_r: c_uint = 0x072; 262 | pub const XK_s: c_uint = 0x073; 263 | pub const XK_t: c_uint = 0x074; 264 | pub const XK_u: c_uint = 0x075; 265 | pub const XK_v: c_uint = 0x076; 266 | pub const XK_w: c_uint = 0x077; 267 | pub const XK_x: c_uint = 0x078; 268 | pub const XK_y: c_uint = 0x079; 269 | pub const XK_z: c_uint = 0x07a; 270 | pub const XK_braceleft: c_uint = 0x07b; 271 | pub const XK_bar: c_uint = 0x07c; 272 | pub const XK_braceright: c_uint = 0x07d; 273 | pub const XK_asciitilde: c_uint = 0x07e; 274 | pub const XK_nobreakspace: c_uint = 0x0a0; 275 | pub const XK_exclamdown: c_uint = 0x0a1; 276 | pub const XK_cent: c_uint = 0x0a2; 277 | pub const XK_sterling: c_uint = 0x0a3; 278 | pub const XK_currency: c_uint = 0x0a4; 279 | pub const XK_yen: c_uint = 0x0a5; 280 | pub const XK_brokenbar: c_uint = 0x0a6; 281 | pub const XK_section: c_uint = 0x0a7; 282 | pub const XK_diaeresis: c_uint = 0x0a8; 283 | pub const XK_copyright: c_uint = 0x0a9; 284 | pub const XK_ordfeminine: c_uint = 0x0aa; 285 | pub const XK_guillemotleft: c_uint = 0x0ab; 286 | pub const XK_notsign: c_uint = 0x0ac; 287 | pub const XK_hyphen: c_uint = 0x0ad; 288 | pub const XK_registered: c_uint = 0x0ae; 289 | pub const XK_macron: c_uint = 0x0af; 290 | pub const XK_degree: c_uint = 0x0b0; 291 | pub const XK_plusminus: c_uint = 0x0b1; 292 | pub const XK_twosuperior: c_uint = 0x0b2; 293 | pub const XK_threesuperior: c_uint = 0x0b3; 294 | pub const XK_acute: c_uint = 0x0b4; 295 | pub const XK_mu: c_uint = 0x0b5; 296 | pub const XK_paragraph: c_uint = 0x0b6; 297 | pub const XK_periodcentered: c_uint = 0x0b7; 298 | pub const XK_cedilla: c_uint = 0x0b8; 299 | pub const XK_onesuperior: c_uint = 0x0b9; 300 | pub const XK_masculine: c_uint = 0x0ba; 301 | pub const XK_guillemotright: c_uint = 0x0bb; 302 | pub const XK_onequarter: c_uint = 0x0bc; 303 | pub const XK_onehalf: c_uint = 0x0bd; 304 | pub const XK_threequarters: c_uint = 0x0be; 305 | pub const XK_questiondown: c_uint = 0x0bf; 306 | pub const XK_Agrave: c_uint = 0x0c0; 307 | pub const XK_Aacute: c_uint = 0x0c1; 308 | pub const XK_Acircumflex: c_uint = 0x0c2; 309 | pub const XK_Atilde: c_uint = 0x0c3; 310 | pub const XK_Adiaeresis: c_uint = 0x0c4; 311 | pub const XK_Aring: c_uint = 0x0c5; 312 | pub const XK_AE: c_uint = 0x0c6; 313 | pub const XK_Ccedilla: c_uint = 0x0c7; 314 | pub const XK_Egrave: c_uint = 0x0c8; 315 | pub const XK_Eacute: c_uint = 0x0c9; 316 | pub const XK_Ecircumflex: c_uint = 0x0ca; 317 | pub const XK_Ediaeresis: c_uint = 0x0cb; 318 | pub const XK_Igrave: c_uint = 0x0cc; 319 | pub const XK_Iacute: c_uint = 0x0cd; 320 | pub const XK_Icircumflex: c_uint = 0x0ce; 321 | pub const XK_Idiaeresis: c_uint = 0x0cf; 322 | pub const XK_ETH: c_uint = 0x0d0; 323 | pub const XK_Eth: c_uint = 0x0d0; 324 | pub const XK_Ntilde: c_uint = 0x0d1; 325 | pub const XK_Ograve: c_uint = 0x0d2; 326 | pub const XK_Oacute: c_uint = 0x0d3; 327 | pub const XK_Ocircumflex: c_uint = 0x0d4; 328 | pub const XK_Otilde: c_uint = 0x0d5; 329 | pub const XK_Odiaeresis: c_uint = 0x0d6; 330 | pub const XK_multiply: c_uint = 0x0d7; 331 | pub const XK_Ooblique: c_uint = 0x0d8; 332 | pub const XK_Ugrave: c_uint = 0x0d9; 333 | pub const XK_Uacute: c_uint = 0x0da; 334 | pub const XK_Ucircumflex: c_uint = 0x0db; 335 | pub const XK_Udiaeresis: c_uint = 0x0dc; 336 | pub const XK_Yacute: c_uint = 0x0dd; 337 | pub const XK_THORN: c_uint = 0x0de; 338 | pub const XK_Thorn: c_uint = 0x0de; 339 | pub const XK_ssharp: c_uint = 0x0df; 340 | pub const XK_agrave: c_uint = 0x0e0; 341 | pub const XK_aacute: c_uint = 0x0e1; 342 | pub const XK_acircumflex: c_uint = 0x0e2; 343 | pub const XK_atilde: c_uint = 0x0e3; 344 | pub const XK_adiaeresis: c_uint = 0x0e4; 345 | pub const XK_aring: c_uint = 0x0e5; 346 | pub const XK_ae: c_uint = 0x0e6; 347 | pub const XK_ccedilla: c_uint = 0x0e7; 348 | pub const XK_egrave: c_uint = 0x0e8; 349 | pub const XK_eacute: c_uint = 0x0e9; 350 | pub const XK_ecircumflex: c_uint = 0x0ea; 351 | pub const XK_ediaeresis: c_uint = 0x0eb; 352 | pub const XK_igrave: c_uint = 0x0ec; 353 | pub const XK_iacute: c_uint = 0x0ed; 354 | pub const XK_icircumflex: c_uint = 0x0ee; 355 | pub const XK_idiaeresis: c_uint = 0x0ef; 356 | pub const XK_eth: c_uint = 0x0f0; 357 | pub const XK_ntilde: c_uint = 0x0f1; 358 | pub const XK_ograve: c_uint = 0x0f2; 359 | pub const XK_oacute: c_uint = 0x0f3; 360 | pub const XK_ocircumflex: c_uint = 0x0f4; 361 | pub const XK_otilde: c_uint = 0x0f5; 362 | pub const XK_odiaeresis: c_uint = 0x0f6; 363 | pub const XK_division: c_uint = 0x0f7; 364 | pub const XK_oslash: c_uint = 0x0f8; 365 | pub const XK_ugrave: c_uint = 0x0f9; 366 | pub const XK_uacute: c_uint = 0x0fa; 367 | pub const XK_ucircumflex: c_uint = 0x0fb; 368 | pub const XK_udiaeresis: c_uint = 0x0fc; 369 | pub const XK_yacute: c_uint = 0x0fd; 370 | pub const XK_thorn: c_uint = 0x0fe; 371 | pub const XK_ydiaeresis: c_uint = 0x0ff; 372 | pub const XK_Aogonek: c_uint = 0x1a1; 373 | pub const XK_breve: c_uint = 0x1a2; 374 | pub const XK_Lstroke: c_uint = 0x1a3; 375 | pub const XK_Lcaron: c_uint = 0x1a5; 376 | pub const XK_Sacute: c_uint = 0x1a6; 377 | pub const XK_Scaron: c_uint = 0x1a9; 378 | pub const XK_Scedilla: c_uint = 0x1aa; 379 | pub const XK_Tcaron: c_uint = 0x1ab; 380 | pub const XK_Zacute: c_uint = 0x1ac; 381 | pub const XK_Zcaron: c_uint = 0x1ae; 382 | pub const XK_Zabovedot: c_uint = 0x1af; 383 | pub const XK_aogonek: c_uint = 0x1b1; 384 | pub const XK_ogonek: c_uint = 0x1b2; 385 | pub const XK_lstroke: c_uint = 0x1b3; 386 | pub const XK_lcaron: c_uint = 0x1b5; 387 | pub const XK_sacute: c_uint = 0x1b6; 388 | pub const XK_caron: c_uint = 0x1b7; 389 | pub const XK_scaron: c_uint = 0x1b9; 390 | pub const XK_scedilla: c_uint = 0x1ba; 391 | pub const XK_tcaron: c_uint = 0x1bb; 392 | pub const XK_zacute: c_uint = 0x1bc; 393 | pub const XK_doubleacute: c_uint = 0x1bd; 394 | pub const XK_zcaron: c_uint = 0x1be; 395 | pub const XK_zabovedot: c_uint = 0x1bf; 396 | pub const XK_Racute: c_uint = 0x1c0; 397 | pub const XK_Abreve: c_uint = 0x1c3; 398 | pub const XK_Lacute: c_uint = 0x1c5; 399 | pub const XK_Cacute: c_uint = 0x1c6; 400 | pub const XK_Ccaron: c_uint = 0x1c8; 401 | pub const XK_Eogonek: c_uint = 0x1ca; 402 | pub const XK_Ecaron: c_uint = 0x1cc; 403 | pub const XK_Dcaron: c_uint = 0x1cf; 404 | pub const XK_Dstroke: c_uint = 0x1d0; 405 | pub const XK_Nacute: c_uint = 0x1d1; 406 | pub const XK_Ncaron: c_uint = 0x1d2; 407 | pub const XK_Odoubleacute: c_uint = 0x1d5; 408 | pub const XK_Rcaron: c_uint = 0x1d8; 409 | pub const XK_Uring: c_uint = 0x1d9; 410 | pub const XK_Udoubleacute: c_uint = 0x1db; 411 | pub const XK_Tcedilla: c_uint = 0x1de; 412 | pub const XK_racute: c_uint = 0x1e0; 413 | pub const XK_abreve: c_uint = 0x1e3; 414 | pub const XK_lacute: c_uint = 0x1e5; 415 | pub const XK_cacute: c_uint = 0x1e6; 416 | pub const XK_ccaron: c_uint = 0x1e8; 417 | pub const XK_eogonek: c_uint = 0x1ea; 418 | pub const XK_ecaron: c_uint = 0x1ec; 419 | pub const XK_dcaron: c_uint = 0x1ef; 420 | pub const XK_dstroke: c_uint = 0x1f0; 421 | pub const XK_nacute: c_uint = 0x1f1; 422 | pub const XK_ncaron: c_uint = 0x1f2; 423 | pub const XK_odoubleacute: c_uint = 0x1f5; 424 | pub const XK_udoubleacute: c_uint = 0x1fb; 425 | pub const XK_rcaron: c_uint = 0x1f8; 426 | pub const XK_uring: c_uint = 0x1f9; 427 | pub const XK_tcedilla: c_uint = 0x1fe; 428 | pub const XK_abovedot: c_uint = 0x1ff; 429 | pub const XK_Hstroke: c_uint = 0x2a1; 430 | pub const XK_Hcircumflex: c_uint = 0x2a6; 431 | pub const XK_Iabovedot: c_uint = 0x2a9; 432 | pub const XK_Gbreve: c_uint = 0x2ab; 433 | pub const XK_Jcircumflex: c_uint = 0x2ac; 434 | pub const XK_hstroke: c_uint = 0x2b1; 435 | pub const XK_hcircumflex: c_uint = 0x2b6; 436 | pub const XK_idotless: c_uint = 0x2b9; 437 | pub const XK_gbreve: c_uint = 0x2bb; 438 | pub const XK_jcircumflex: c_uint = 0x2bc; 439 | pub const XK_Cabovedot: c_uint = 0x2c5; 440 | pub const XK_Ccircumflex: c_uint = 0x2c6; 441 | pub const XK_Gabovedot: c_uint = 0x2d5; 442 | pub const XK_Gcircumflex: c_uint = 0x2d8; 443 | pub const XK_Ubreve: c_uint = 0x2dd; 444 | pub const XK_Scircumflex: c_uint = 0x2de; 445 | pub const XK_cabovedot: c_uint = 0x2e5; 446 | pub const XK_ccircumflex: c_uint = 0x2e6; 447 | pub const XK_gabovedot: c_uint = 0x2f5; 448 | pub const XK_gcircumflex: c_uint = 0x2f8; 449 | pub const XK_ubreve: c_uint = 0x2fd; 450 | pub const XK_scircumflex: c_uint = 0x2fe; 451 | pub const XK_kra: c_uint = 0x3a2; 452 | pub const XK_kappa: c_uint = 0x3a2; 453 | pub const XK_Rcedilla: c_uint = 0x3a3; 454 | pub const XK_Itilde: c_uint = 0x3a5; 455 | pub const XK_Lcedilla: c_uint = 0x3a6; 456 | pub const XK_Emacron: c_uint = 0x3aa; 457 | pub const XK_Gcedilla: c_uint = 0x3ab; 458 | pub const XK_Tslash: c_uint = 0x3ac; 459 | pub const XK_rcedilla: c_uint = 0x3b3; 460 | pub const XK_itilde: c_uint = 0x3b5; 461 | pub const XK_lcedilla: c_uint = 0x3b6; 462 | pub const XK_emacron: c_uint = 0x3ba; 463 | pub const XK_gcedilla: c_uint = 0x3bb; 464 | pub const XK_tslash: c_uint = 0x3bc; 465 | pub const XK_ENG: c_uint = 0x3bd; 466 | pub const XK_eng: c_uint = 0x3bf; 467 | pub const XK_Amacron: c_uint = 0x3c0; 468 | pub const XK_Iogonek: c_uint = 0x3c7; 469 | pub const XK_Eabovedot: c_uint = 0x3cc; 470 | pub const XK_Imacron: c_uint = 0x3cf; 471 | pub const XK_Ncedilla: c_uint = 0x3d1; 472 | pub const XK_Omacron: c_uint = 0x3d2; 473 | pub const XK_Kcedilla: c_uint = 0x3d3; 474 | pub const XK_Uogonek: c_uint = 0x3d9; 475 | pub const XK_Utilde: c_uint = 0x3dd; 476 | pub const XK_Umacron: c_uint = 0x3de; 477 | pub const XK_amacron: c_uint = 0x3e0; 478 | pub const XK_iogonek: c_uint = 0x3e7; 479 | pub const XK_eabovedot: c_uint = 0x3ec; 480 | pub const XK_imacron: c_uint = 0x3ef; 481 | pub const XK_ncedilla: c_uint = 0x3f1; 482 | pub const XK_omacron: c_uint = 0x3f2; 483 | pub const XK_kcedilla: c_uint = 0x3f3; 484 | pub const XK_uogonek: c_uint = 0x3f9; 485 | pub const XK_utilde: c_uint = 0x3fd; 486 | pub const XK_umacron: c_uint = 0x3fe; 487 | pub const XK_overline: c_uint = 0x47e; 488 | pub const XK_kana_fullstop: c_uint = 0x4a1; 489 | pub const XK_kana_openingbracket: c_uint = 0x4a2; 490 | pub const XK_kana_closingbracket: c_uint = 0x4a3; 491 | pub const XK_kana_comma: c_uint = 0x4a4; 492 | pub const XK_kana_conjunctive: c_uint = 0x4a5; 493 | pub const XK_kana_middledot: c_uint = 0x4a5; 494 | pub const XK_kana_WO: c_uint = 0x4a6; 495 | pub const XK_kana_a: c_uint = 0x4a7; 496 | pub const XK_kana_i: c_uint = 0x4a8; 497 | pub const XK_kana_u: c_uint = 0x4a9; 498 | pub const XK_kana_e: c_uint = 0x4aa; 499 | pub const XK_kana_o: c_uint = 0x4ab; 500 | pub const XK_kana_ya: c_uint = 0x4ac; 501 | pub const XK_kana_yu: c_uint = 0x4ad; 502 | pub const XK_kana_yo: c_uint = 0x4ae; 503 | pub const XK_kana_tsu: c_uint = 0x4af; 504 | pub const XK_kana_tu: c_uint = 0x4af; 505 | pub const XK_prolongedsound: c_uint = 0x4b0; 506 | pub const XK_kana_A: c_uint = 0x4b1; 507 | pub const XK_kana_I: c_uint = 0x4b2; 508 | pub const XK_kana_U: c_uint = 0x4b3; 509 | pub const XK_kana_E: c_uint = 0x4b4; 510 | pub const XK_kana_O: c_uint = 0x4b5; 511 | pub const XK_kana_KA: c_uint = 0x4b6; 512 | pub const XK_kana_KI: c_uint = 0x4b7; 513 | pub const XK_kana_KU: c_uint = 0x4b8; 514 | pub const XK_kana_KE: c_uint = 0x4b9; 515 | pub const XK_kana_KO: c_uint = 0x4ba; 516 | pub const XK_kana_SA: c_uint = 0x4bb; 517 | pub const XK_kana_SHI: c_uint = 0x4bc; 518 | pub const XK_kana_SU: c_uint = 0x4bd; 519 | pub const XK_kana_SE: c_uint = 0x4be; 520 | pub const XK_kana_SO: c_uint = 0x4bf; 521 | pub const XK_kana_TA: c_uint = 0x4c0; 522 | pub const XK_kana_CHI: c_uint = 0x4c1; 523 | pub const XK_kana_TI: c_uint = 0x4c1; 524 | pub const XK_kana_TSU: c_uint = 0x4c2; 525 | pub const XK_kana_TU: c_uint = 0x4c2; 526 | pub const XK_kana_TE: c_uint = 0x4c3; 527 | pub const XK_kana_TO: c_uint = 0x4c4; 528 | pub const XK_kana_NA: c_uint = 0x4c5; 529 | pub const XK_kana_NI: c_uint = 0x4c6; 530 | pub const XK_kana_NU: c_uint = 0x4c7; 531 | pub const XK_kana_NE: c_uint = 0x4c8; 532 | pub const XK_kana_NO: c_uint = 0x4c9; 533 | pub const XK_kana_HA: c_uint = 0x4ca; 534 | pub const XK_kana_HI: c_uint = 0x4cb; 535 | pub const XK_kana_FU: c_uint = 0x4cc; 536 | pub const XK_kana_HU: c_uint = 0x4cc; 537 | pub const XK_kana_HE: c_uint = 0x4cd; 538 | pub const XK_kana_HO: c_uint = 0x4ce; 539 | pub const XK_kana_MA: c_uint = 0x4cf; 540 | pub const XK_kana_MI: c_uint = 0x4d0; 541 | pub const XK_kana_MU: c_uint = 0x4d1; 542 | pub const XK_kana_ME: c_uint = 0x4d2; 543 | pub const XK_kana_MO: c_uint = 0x4d3; 544 | pub const XK_kana_YA: c_uint = 0x4d4; 545 | pub const XK_kana_YU: c_uint = 0x4d5; 546 | pub const XK_kana_YO: c_uint = 0x4d6; 547 | pub const XK_kana_RA: c_uint = 0x4d7; 548 | pub const XK_kana_RI: c_uint = 0x4d8; 549 | pub const XK_kana_RU: c_uint = 0x4d9; 550 | pub const XK_kana_RE: c_uint = 0x4da; 551 | pub const XK_kana_RO: c_uint = 0x4db; 552 | pub const XK_kana_WA: c_uint = 0x4dc; 553 | pub const XK_kana_N: c_uint = 0x4dd; 554 | pub const XK_voicedsound: c_uint = 0x4de; 555 | pub const XK_semivoicedsound: c_uint = 0x4df; 556 | pub const XK_kana_switch: c_uint = 0xFF7E; 557 | pub const XK_Arabic_comma: c_uint = 0x5ac; 558 | pub const XK_Arabic_semicolon: c_uint = 0x5bb; 559 | pub const XK_Arabic_question_mark: c_uint = 0x5bf; 560 | pub const XK_Arabic_hamza: c_uint = 0x5c1; 561 | pub const XK_Arabic_maddaonalef: c_uint = 0x5c2; 562 | pub const XK_Arabic_hamzaonalef: c_uint = 0x5c3; 563 | pub const XK_Arabic_hamzaonwaw: c_uint = 0x5c4; 564 | pub const XK_Arabic_hamzaunderalef: c_uint = 0x5c5; 565 | pub const XK_Arabic_hamzaonyeh: c_uint = 0x5c6; 566 | pub const XK_Arabic_alef: c_uint = 0x5c7; 567 | pub const XK_Arabic_beh: c_uint = 0x5c8; 568 | pub const XK_Arabic_tehmarbuta: c_uint = 0x5c9; 569 | pub const XK_Arabic_teh: c_uint = 0x5ca; 570 | pub const XK_Arabic_theh: c_uint = 0x5cb; 571 | pub const XK_Arabic_jeem: c_uint = 0x5cc; 572 | pub const XK_Arabic_hah: c_uint = 0x5cd; 573 | pub const XK_Arabic_khah: c_uint = 0x5ce; 574 | pub const XK_Arabic_dal: c_uint = 0x5cf; 575 | pub const XK_Arabic_thal: c_uint = 0x5d0; 576 | pub const XK_Arabic_ra: c_uint = 0x5d1; 577 | pub const XK_Arabic_zain: c_uint = 0x5d2; 578 | pub const XK_Arabic_seen: c_uint = 0x5d3; 579 | pub const XK_Arabic_sheen: c_uint = 0x5d4; 580 | pub const XK_Arabic_sad: c_uint = 0x5d5; 581 | pub const XK_Arabic_dad: c_uint = 0x5d6; 582 | pub const XK_Arabic_tah: c_uint = 0x5d7; 583 | pub const XK_Arabic_zah: c_uint = 0x5d8; 584 | pub const XK_Arabic_ain: c_uint = 0x5d9; 585 | pub const XK_Arabic_ghain: c_uint = 0x5da; 586 | pub const XK_Arabic_tatweel: c_uint = 0x5e0; 587 | pub const XK_Arabic_feh: c_uint = 0x5e1; 588 | pub const XK_Arabic_qaf: c_uint = 0x5e2; 589 | pub const XK_Arabic_kaf: c_uint = 0x5e3; 590 | pub const XK_Arabic_lam: c_uint = 0x5e4; 591 | pub const XK_Arabic_meem: c_uint = 0x5e5; 592 | pub const XK_Arabic_noon: c_uint = 0x5e6; 593 | pub const XK_Arabic_ha: c_uint = 0x5e7; 594 | pub const XK_Arabic_heh: c_uint = 0x5e7; 595 | pub const XK_Arabic_waw: c_uint = 0x5e8; 596 | pub const XK_Arabic_alefmaksura: c_uint = 0x5e9; 597 | pub const XK_Arabic_yeh: c_uint = 0x5ea; 598 | pub const XK_Arabic_fathatan: c_uint = 0x5eb; 599 | pub const XK_Arabic_dammatan: c_uint = 0x5ec; 600 | pub const XK_Arabic_kasratan: c_uint = 0x5ed; 601 | pub const XK_Arabic_fatha: c_uint = 0x5ee; 602 | pub const XK_Arabic_damma: c_uint = 0x5ef; 603 | pub const XK_Arabic_kasra: c_uint = 0x5f0; 604 | pub const XK_Arabic_shadda: c_uint = 0x5f1; 605 | pub const XK_Arabic_sukun: c_uint = 0x5f2; 606 | pub const XK_Arabic_switch: c_uint = 0xFF7E; 607 | pub const XK_Serbian_dje: c_uint = 0x6a1; 608 | pub const XK_Macedonia_gje: c_uint = 0x6a2; 609 | pub const XK_Cyrillic_io: c_uint = 0x6a3; 610 | pub const XK_Ukrainian_ie: c_uint = 0x6a4; 611 | pub const XK_Ukranian_je: c_uint = 0x6a4; 612 | pub const XK_Macedonia_dse: c_uint = 0x6a5; 613 | pub const XK_Ukrainian_i: c_uint = 0x6a6; 614 | pub const XK_Ukranian_i: c_uint = 0x6a6; 615 | pub const XK_Ukrainian_yi: c_uint = 0x6a7; 616 | pub const XK_Ukranian_yi: c_uint = 0x6a7; 617 | pub const XK_Cyrillic_je: c_uint = 0x6a8; 618 | pub const XK_Serbian_je: c_uint = 0x6a8; 619 | pub const XK_Cyrillic_lje: c_uint = 0x6a9; 620 | pub const XK_Serbian_lje: c_uint = 0x6a9; 621 | pub const XK_Cyrillic_nje: c_uint = 0x6aa; 622 | pub const XK_Serbian_nje: c_uint = 0x6aa; 623 | pub const XK_Serbian_tshe: c_uint = 0x6ab; 624 | pub const XK_Macedonia_kje: c_uint = 0x6ac; 625 | pub const XK_Byelorussian_shortu: c_uint = 0x6ae; 626 | pub const XK_Cyrillic_dzhe: c_uint = 0x6af; 627 | pub const XK_Serbian_dze: c_uint = 0x6af; 628 | pub const XK_numerosign: c_uint = 0x6b0; 629 | pub const XK_Serbian_DJE: c_uint = 0x6b1; 630 | pub const XK_Macedonia_GJE: c_uint = 0x6b2; 631 | pub const XK_Cyrillic_IO: c_uint = 0x6b3; 632 | pub const XK_Ukrainian_IE: c_uint = 0x6b4; 633 | pub const XK_Ukranian_JE: c_uint = 0x6b4; 634 | pub const XK_Macedonia_DSE: c_uint = 0x6b5; 635 | pub const XK_Ukrainian_I: c_uint = 0x6b6; 636 | pub const XK_Ukranian_I: c_uint = 0x6b6; 637 | pub const XK_Ukrainian_YI: c_uint = 0x6b7; 638 | pub const XK_Ukranian_YI: c_uint = 0x6b7; 639 | pub const XK_Cyrillic_JE: c_uint = 0x6b8; 640 | pub const XK_Serbian_JE: c_uint = 0x6b8; 641 | pub const XK_Cyrillic_LJE: c_uint = 0x6b9; 642 | pub const XK_Serbian_LJE: c_uint = 0x6b9; 643 | pub const XK_Cyrillic_NJE: c_uint = 0x6ba; 644 | pub const XK_Serbian_NJE: c_uint = 0x6ba; 645 | pub const XK_Serbian_TSHE: c_uint = 0x6bb; 646 | pub const XK_Macedonia_KJE: c_uint = 0x6bc; 647 | pub const XK_Byelorussian_SHORTU: c_uint = 0x6be; 648 | pub const XK_Cyrillic_DZHE: c_uint = 0x6bf; 649 | pub const XK_Serbian_DZE: c_uint = 0x6bf; 650 | pub const XK_Cyrillic_yu: c_uint = 0x6c0; 651 | pub const XK_Cyrillic_a: c_uint = 0x6c1; 652 | pub const XK_Cyrillic_be: c_uint = 0x6c2; 653 | pub const XK_Cyrillic_tse: c_uint = 0x6c3; 654 | pub const XK_Cyrillic_de: c_uint = 0x6c4; 655 | pub const XK_Cyrillic_ie: c_uint = 0x6c5; 656 | pub const XK_Cyrillic_ef: c_uint = 0x6c6; 657 | pub const XK_Cyrillic_ghe: c_uint = 0x6c7; 658 | pub const XK_Cyrillic_ha: c_uint = 0x6c8; 659 | pub const XK_Cyrillic_i: c_uint = 0x6c9; 660 | pub const XK_Cyrillic_shorti: c_uint = 0x6ca; 661 | pub const XK_Cyrillic_ka: c_uint = 0x6cb; 662 | pub const XK_Cyrillic_el: c_uint = 0x6cc; 663 | pub const XK_Cyrillic_em: c_uint = 0x6cd; 664 | pub const XK_Cyrillic_en: c_uint = 0x6ce; 665 | pub const XK_Cyrillic_o: c_uint = 0x6cf; 666 | pub const XK_Cyrillic_pe: c_uint = 0x6d0; 667 | pub const XK_Cyrillic_ya: c_uint = 0x6d1; 668 | pub const XK_Cyrillic_er: c_uint = 0x6d2; 669 | pub const XK_Cyrillic_es: c_uint = 0x6d3; 670 | pub const XK_Cyrillic_te: c_uint = 0x6d4; 671 | pub const XK_Cyrillic_u: c_uint = 0x6d5; 672 | pub const XK_Cyrillic_zhe: c_uint = 0x6d6; 673 | pub const XK_Cyrillic_ve: c_uint = 0x6d7; 674 | pub const XK_Cyrillic_softsign: c_uint = 0x6d8; 675 | pub const XK_Cyrillic_yeru: c_uint = 0x6d9; 676 | pub const XK_Cyrillic_ze: c_uint = 0x6da; 677 | pub const XK_Cyrillic_sha: c_uint = 0x6db; 678 | pub const XK_Cyrillic_e: c_uint = 0x6dc; 679 | pub const XK_Cyrillic_shcha: c_uint = 0x6dd; 680 | pub const XK_Cyrillic_che: c_uint = 0x6de; 681 | pub const XK_Cyrillic_hardsign: c_uint = 0x6df; 682 | pub const XK_Cyrillic_YU: c_uint = 0x6e0; 683 | pub const XK_Cyrillic_A: c_uint = 0x6e1; 684 | pub const XK_Cyrillic_BE: c_uint = 0x6e2; 685 | pub const XK_Cyrillic_TSE: c_uint = 0x6e3; 686 | pub const XK_Cyrillic_DE: c_uint = 0x6e4; 687 | pub const XK_Cyrillic_IE: c_uint = 0x6e5; 688 | pub const XK_Cyrillic_EF: c_uint = 0x6e6; 689 | pub const XK_Cyrillic_GHE: c_uint = 0x6e7; 690 | pub const XK_Cyrillic_HA: c_uint = 0x6e8; 691 | pub const XK_Cyrillic_I: c_uint = 0x6e9; 692 | pub const XK_Cyrillic_SHORTI: c_uint = 0x6ea; 693 | pub const XK_Cyrillic_KA: c_uint = 0x6eb; 694 | pub const XK_Cyrillic_EL: c_uint = 0x6ec; 695 | pub const XK_Cyrillic_EM: c_uint = 0x6ed; 696 | pub const XK_Cyrillic_EN: c_uint = 0x6ee; 697 | pub const XK_Cyrillic_O: c_uint = 0x6ef; 698 | pub const XK_Cyrillic_PE: c_uint = 0x6f0; 699 | pub const XK_Cyrillic_YA: c_uint = 0x6f1; 700 | pub const XK_Cyrillic_ER: c_uint = 0x6f2; 701 | pub const XK_Cyrillic_ES: c_uint = 0x6f3; 702 | pub const XK_Cyrillic_TE: c_uint = 0x6f4; 703 | pub const XK_Cyrillic_U: c_uint = 0x6f5; 704 | pub const XK_Cyrillic_ZHE: c_uint = 0x6f6; 705 | pub const XK_Cyrillic_VE: c_uint = 0x6f7; 706 | pub const XK_Cyrillic_SOFTSIGN: c_uint = 0x6f8; 707 | pub const XK_Cyrillic_YERU: c_uint = 0x6f9; 708 | pub const XK_Cyrillic_ZE: c_uint = 0x6fa; 709 | pub const XK_Cyrillic_SHA: c_uint = 0x6fb; 710 | pub const XK_Cyrillic_E: c_uint = 0x6fc; 711 | pub const XK_Cyrillic_SHCHA: c_uint = 0x6fd; 712 | pub const XK_Cyrillic_CHE: c_uint = 0x6fe; 713 | pub const XK_Cyrillic_HARDSIGN: c_uint = 0x6ff; 714 | pub const XK_Greek_ALPHAaccent: c_uint = 0x7a1; 715 | pub const XK_Greek_EPSILONaccent: c_uint = 0x7a2; 716 | pub const XK_Greek_ETAaccent: c_uint = 0x7a3; 717 | pub const XK_Greek_IOTAaccent: c_uint = 0x7a4; 718 | pub const XK_Greek_IOTAdiaeresis: c_uint = 0x7a5; 719 | pub const XK_Greek_OMICRONaccent: c_uint = 0x7a7; 720 | pub const XK_Greek_UPSILONaccent: c_uint = 0x7a8; 721 | pub const XK_Greek_UPSILONdieresis: c_uint = 0x7a9; 722 | pub const XK_Greek_OMEGAaccent: c_uint = 0x7ab; 723 | pub const XK_Greek_accentdieresis: c_uint = 0x7ae; 724 | pub const XK_Greek_horizbar: c_uint = 0x7af; 725 | pub const XK_Greek_alphaaccent: c_uint = 0x7b1; 726 | pub const XK_Greek_epsilonaccent: c_uint = 0x7b2; 727 | pub const XK_Greek_etaaccent: c_uint = 0x7b3; 728 | pub const XK_Greek_iotaaccent: c_uint = 0x7b4; 729 | pub const XK_Greek_iotadieresis: c_uint = 0x7b5; 730 | pub const XK_Greek_iotaaccentdieresis: c_uint = 0x7b6; 731 | pub const XK_Greek_omicronaccent: c_uint = 0x7b7; 732 | pub const XK_Greek_upsilonaccent: c_uint = 0x7b8; 733 | pub const XK_Greek_upsilondieresis: c_uint = 0x7b9; 734 | pub const XK_Greek_upsilonaccentdieresis: c_uint = 0x7ba; 735 | pub const XK_Greek_omegaaccent: c_uint = 0x7bb; 736 | pub const XK_Greek_ALPHA: c_uint = 0x7c1; 737 | pub const XK_Greek_BETA: c_uint = 0x7c2; 738 | pub const XK_Greek_GAMMA: c_uint = 0x7c3; 739 | pub const XK_Greek_DELTA: c_uint = 0x7c4; 740 | pub const XK_Greek_EPSILON: c_uint = 0x7c5; 741 | pub const XK_Greek_ZETA: c_uint = 0x7c6; 742 | pub const XK_Greek_ETA: c_uint = 0x7c7; 743 | pub const XK_Greek_THETA: c_uint = 0x7c8; 744 | pub const XK_Greek_IOTA: c_uint = 0x7c9; 745 | pub const XK_Greek_KAPPA: c_uint = 0x7ca; 746 | pub const XK_Greek_LAMDA: c_uint = 0x7cb; 747 | pub const XK_Greek_LAMBDA: c_uint = 0x7cb; 748 | pub const XK_Greek_MU: c_uint = 0x7cc; 749 | pub const XK_Greek_NU: c_uint = 0x7cd; 750 | pub const XK_Greek_XI: c_uint = 0x7ce; 751 | pub const XK_Greek_OMICRON: c_uint = 0x7cf; 752 | pub const XK_Greek_PI: c_uint = 0x7d0; 753 | pub const XK_Greek_RHO: c_uint = 0x7d1; 754 | pub const XK_Greek_SIGMA: c_uint = 0x7d2; 755 | pub const XK_Greek_TAU: c_uint = 0x7d4; 756 | pub const XK_Greek_UPSILON: c_uint = 0x7d5; 757 | pub const XK_Greek_PHI: c_uint = 0x7d6; 758 | pub const XK_Greek_CHI: c_uint = 0x7d7; 759 | pub const XK_Greek_PSI: c_uint = 0x7d8; 760 | pub const XK_Greek_OMEGA: c_uint = 0x7d9; 761 | pub const XK_Greek_alpha: c_uint = 0x7e1; 762 | pub const XK_Greek_beta: c_uint = 0x7e2; 763 | pub const XK_Greek_gamma: c_uint = 0x7e3; 764 | pub const XK_Greek_delta: c_uint = 0x7e4; 765 | pub const XK_Greek_epsilon: c_uint = 0x7e5; 766 | pub const XK_Greek_zeta: c_uint = 0x7e6; 767 | pub const XK_Greek_eta: c_uint = 0x7e7; 768 | pub const XK_Greek_theta: c_uint = 0x7e8; 769 | pub const XK_Greek_iota: c_uint = 0x7e9; 770 | pub const XK_Greek_kappa: c_uint = 0x7ea; 771 | pub const XK_Greek_lamda: c_uint = 0x7eb; 772 | pub const XK_Greek_lambda: c_uint = 0x7eb; 773 | pub const XK_Greek_mu: c_uint = 0x7ec; 774 | pub const XK_Greek_nu: c_uint = 0x7ed; 775 | pub const XK_Greek_xi: c_uint = 0x7ee; 776 | pub const XK_Greek_omicron: c_uint = 0x7ef; 777 | pub const XK_Greek_pi: c_uint = 0x7f0; 778 | pub const XK_Greek_rho: c_uint = 0x7f1; 779 | pub const XK_Greek_sigma: c_uint = 0x7f2; 780 | pub const XK_Greek_finalsmallsigma: c_uint = 0x7f3; 781 | pub const XK_Greek_tau: c_uint = 0x7f4; 782 | pub const XK_Greek_upsilon: c_uint = 0x7f5; 783 | pub const XK_Greek_phi: c_uint = 0x7f6; 784 | pub const XK_Greek_chi: c_uint = 0x7f7; 785 | pub const XK_Greek_psi: c_uint = 0x7f8; 786 | pub const XK_Greek_omega: c_uint = 0x7f9; 787 | pub const XK_Greek_switch: c_uint = 0xFF7E; 788 | pub const XK_leftradical: c_uint = 0x8a1; 789 | pub const XK_topleftradical: c_uint = 0x8a2; 790 | pub const XK_horizconnector: c_uint = 0x8a3; 791 | pub const XK_topintegral: c_uint = 0x8a4; 792 | pub const XK_botintegral: c_uint = 0x8a5; 793 | pub const XK_vertconnector: c_uint = 0x8a6; 794 | pub const XK_topleftsqbracket: c_uint = 0x8a7; 795 | pub const XK_botleftsqbracket: c_uint = 0x8a8; 796 | pub const XK_toprightsqbracket: c_uint = 0x8a9; 797 | pub const XK_botrightsqbracket: c_uint = 0x8aa; 798 | pub const XK_topleftparens: c_uint = 0x8ab; 799 | pub const XK_botleftparens: c_uint = 0x8ac; 800 | pub const XK_toprightparens: c_uint = 0x8ad; 801 | pub const XK_botrightparens: c_uint = 0x8ae; 802 | pub const XK_leftmiddlecurlybrace: c_uint = 0x8af; 803 | pub const XK_rightmiddlecurlybrace: c_uint = 0x8b0; 804 | pub const XK_topleftsummation: c_uint = 0x8b1; 805 | pub const XK_botleftsummation: c_uint = 0x8b2; 806 | pub const XK_topvertsummationconnector: c_uint = 0x8b3; 807 | pub const XK_botvertsummationconnector: c_uint = 0x8b4; 808 | pub const XK_toprightsummation: c_uint = 0x8b5; 809 | pub const XK_botrightsummation: c_uint = 0x8b6; 810 | pub const XK_rightmiddlesummation: c_uint = 0x8b7; 811 | pub const XK_lessthanequal: c_uint = 0x8bc; 812 | pub const XK_notequal: c_uint = 0x8bd; 813 | pub const XK_greaterthanequal: c_uint = 0x8be; 814 | pub const XK_integral: c_uint = 0x8bf; 815 | pub const XK_therefore: c_uint = 0x8c0; 816 | pub const XK_variation: c_uint = 0x8c1; 817 | pub const XK_infinity: c_uint = 0x8c2; 818 | pub const XK_nabla: c_uint = 0x8c5; 819 | pub const XK_approximate: c_uint = 0x8c8; 820 | pub const XK_similarequal: c_uint = 0x8c9; 821 | pub const XK_ifonlyif: c_uint = 0x8cd; 822 | pub const XK_implies: c_uint = 0x8ce; 823 | pub const XK_identical: c_uint = 0x8cf; 824 | pub const XK_radical: c_uint = 0x8d6; 825 | pub const XK_includedin: c_uint = 0x8da; 826 | pub const XK_includes: c_uint = 0x8db; 827 | pub const XK_intersection: c_uint = 0x8dc; 828 | pub const XK_union: c_uint = 0x8dd; 829 | pub const XK_logicaland: c_uint = 0x8de; 830 | pub const XK_logicalor: c_uint = 0x8df; 831 | pub const XK_partialderivative: c_uint = 0x8ef; 832 | pub const XK_function: c_uint = 0x8f6; 833 | pub const XK_leftarrow: c_uint = 0x8fb; 834 | pub const XK_uparrow: c_uint = 0x8fc; 835 | pub const XK_rightarrow: c_uint = 0x8fd; 836 | pub const XK_downarrow: c_uint = 0x8fe; 837 | pub const XK_blank: c_uint = 0x9df; 838 | pub const XK_soliddiamond: c_uint = 0x9e0; 839 | pub const XK_checkerboard: c_uint = 0x9e1; 840 | pub const XK_ht: c_uint = 0x9e2; 841 | pub const XK_ff: c_uint = 0x9e3; 842 | pub const XK_cr: c_uint = 0x9e4; 843 | pub const XK_lf: c_uint = 0x9e5; 844 | pub const XK_nl: c_uint = 0x9e8; 845 | pub const XK_vt: c_uint = 0x9e9; 846 | pub const XK_lowrightcorner: c_uint = 0x9ea; 847 | pub const XK_uprightcorner: c_uint = 0x9eb; 848 | pub const XK_upleftcorner: c_uint = 0x9ec; 849 | pub const XK_lowleftcorner: c_uint = 0x9ed; 850 | pub const XK_crossinglines: c_uint = 0x9ee; 851 | pub const XK_horizlinescan1: c_uint = 0x9ef; 852 | pub const XK_horizlinescan3: c_uint = 0x9f0; 853 | pub const XK_horizlinescan5: c_uint = 0x9f1; 854 | pub const XK_horizlinescan7: c_uint = 0x9f2; 855 | pub const XK_horizlinescan9: c_uint = 0x9f3; 856 | pub const XK_leftt: c_uint = 0x9f4; 857 | pub const XK_rightt: c_uint = 0x9f5; 858 | pub const XK_bott: c_uint = 0x9f6; 859 | pub const XK_topt: c_uint = 0x9f7; 860 | pub const XK_vertbar: c_uint = 0x9f8; 861 | pub const XK_emspace: c_uint = 0xaa1; 862 | pub const XK_enspace: c_uint = 0xaa2; 863 | pub const XK_em3space: c_uint = 0xaa3; 864 | pub const XK_em4space: c_uint = 0xaa4; 865 | pub const XK_digitspace: c_uint = 0xaa5; 866 | pub const XK_punctspace: c_uint = 0xaa6; 867 | pub const XK_thinspace: c_uint = 0xaa7; 868 | pub const XK_hairspace: c_uint = 0xaa8; 869 | pub const XK_emdash: c_uint = 0xaa9; 870 | pub const XK_endash: c_uint = 0xaaa; 871 | pub const XK_signifblank: c_uint = 0xaac; 872 | pub const XK_ellipsis: c_uint = 0xaae; 873 | pub const XK_doubbaselinedot: c_uint = 0xaaf; 874 | pub const XK_onethird: c_uint = 0xab0; 875 | pub const XK_twothirds: c_uint = 0xab1; 876 | pub const XK_onefifth: c_uint = 0xab2; 877 | pub const XK_twofifths: c_uint = 0xab3; 878 | pub const XK_threefifths: c_uint = 0xab4; 879 | pub const XK_fourfifths: c_uint = 0xab5; 880 | pub const XK_onesixth: c_uint = 0xab6; 881 | pub const XK_fivesixths: c_uint = 0xab7; 882 | pub const XK_careof: c_uint = 0xab8; 883 | pub const XK_figdash: c_uint = 0xabb; 884 | pub const XK_leftanglebracket: c_uint = 0xabc; 885 | pub const XK_decimalpoint: c_uint = 0xabd; 886 | pub const XK_rightanglebracket: c_uint = 0xabe; 887 | pub const XK_marker: c_uint = 0xabf; 888 | pub const XK_oneeighth: c_uint = 0xac3; 889 | pub const XK_threeeighths: c_uint = 0xac4; 890 | pub const XK_fiveeighths: c_uint = 0xac5; 891 | pub const XK_seveneighths: c_uint = 0xac6; 892 | pub const XK_trademark: c_uint = 0xac9; 893 | pub const XK_signaturemark: c_uint = 0xaca; 894 | pub const XK_trademarkincircle: c_uint = 0xacb; 895 | pub const XK_leftopentriangle: c_uint = 0xacc; 896 | pub const XK_rightopentriangle: c_uint = 0xacd; 897 | pub const XK_emopencircle: c_uint = 0xace; 898 | pub const XK_emopenrectangle: c_uint = 0xacf; 899 | pub const XK_leftsinglequotemark: c_uint = 0xad0; 900 | pub const XK_rightsinglequotemark: c_uint = 0xad1; 901 | pub const XK_leftdoublequotemark: c_uint = 0xad2; 902 | pub const XK_rightdoublequotemark: c_uint = 0xad3; 903 | pub const XK_prescription: c_uint = 0xad4; 904 | pub const XK_minutes: c_uint = 0xad6; 905 | pub const XK_seconds: c_uint = 0xad7; 906 | pub const XK_latincross: c_uint = 0xad9; 907 | pub const XK_hexagram: c_uint = 0xada; 908 | pub const XK_filledrectbullet: c_uint = 0xadb; 909 | pub const XK_filledlefttribullet: c_uint = 0xadc; 910 | pub const XK_filledrighttribullet: c_uint = 0xadd; 911 | pub const XK_emfilledcircle: c_uint = 0xade; 912 | pub const XK_emfilledrect: c_uint = 0xadf; 913 | pub const XK_enopencircbullet: c_uint = 0xae0; 914 | pub const XK_enopensquarebullet: c_uint = 0xae1; 915 | pub const XK_openrectbullet: c_uint = 0xae2; 916 | pub const XK_opentribulletup: c_uint = 0xae3; 917 | pub const XK_opentribulletdown: c_uint = 0xae4; 918 | pub const XK_openstar: c_uint = 0xae5; 919 | pub const XK_enfilledcircbullet: c_uint = 0xae6; 920 | pub const XK_enfilledsqbullet: c_uint = 0xae7; 921 | pub const XK_filledtribulletup: c_uint = 0xae8; 922 | pub const XK_filledtribulletdown: c_uint = 0xae9; 923 | pub const XK_leftpointer: c_uint = 0xaea; 924 | pub const XK_rightpointer: c_uint = 0xaeb; 925 | pub const XK_club: c_uint = 0xaec; 926 | pub const XK_diamond: c_uint = 0xaed; 927 | pub const XK_heart: c_uint = 0xaee; 928 | pub const XK_maltesecross: c_uint = 0xaf0; 929 | pub const XK_dagger: c_uint = 0xaf1; 930 | pub const XK_doubledagger: c_uint = 0xaf2; 931 | pub const XK_checkmark: c_uint = 0xaf3; 932 | pub const XK_ballotcross: c_uint = 0xaf4; 933 | pub const XK_musicalsharp: c_uint = 0xaf5; 934 | pub const XK_musicalflat: c_uint = 0xaf6; 935 | pub const XK_malesymbol: c_uint = 0xaf7; 936 | pub const XK_femalesymbol: c_uint = 0xaf8; 937 | pub const XK_telephone: c_uint = 0xaf9; 938 | pub const XK_telephonerecorder: c_uint = 0xafa; 939 | pub const XK_phonographcopyright: c_uint = 0xafb; 940 | pub const XK_caret: c_uint = 0xafc; 941 | pub const XK_singlelowquotemark: c_uint = 0xafd; 942 | pub const XK_doublelowquotemark: c_uint = 0xafe; 943 | pub const XK_cursor: c_uint = 0xaff; 944 | pub const XK_leftcaret: c_uint = 0xba3; 945 | pub const XK_rightcaret: c_uint = 0xba6; 946 | pub const XK_downcaret: c_uint = 0xba8; 947 | pub const XK_upcaret: c_uint = 0xba9; 948 | pub const XK_overbar: c_uint = 0xbc0; 949 | pub const XK_downtack: c_uint = 0xbc2; 950 | pub const XK_upshoe: c_uint = 0xbc3; 951 | pub const XK_downstile: c_uint = 0xbc4; 952 | pub const XK_underbar: c_uint = 0xbc6; 953 | pub const XK_jot: c_uint = 0xbca; 954 | pub const XK_quad: c_uint = 0xbcc; 955 | pub const XK_uptack: c_uint = 0xbce; 956 | pub const XK_circle: c_uint = 0xbcf; 957 | pub const XK_upstile: c_uint = 0xbd3; 958 | pub const XK_downshoe: c_uint = 0xbd6; 959 | pub const XK_rightshoe: c_uint = 0xbd8; 960 | pub const XK_leftshoe: c_uint = 0xbda; 961 | pub const XK_lefttack: c_uint = 0xbdc; 962 | pub const XK_righttack: c_uint = 0xbfc; 963 | pub const XK_hebrew_doublelowline: c_uint = 0xcdf; 964 | pub const XK_hebrew_aleph: c_uint = 0xce0; 965 | pub const XK_hebrew_bet: c_uint = 0xce1; 966 | pub const XK_hebrew_beth: c_uint = 0xce1; 967 | pub const XK_hebrew_gimel: c_uint = 0xce2; 968 | pub const XK_hebrew_gimmel: c_uint = 0xce2; 969 | pub const XK_hebrew_dalet: c_uint = 0xce3; 970 | pub const XK_hebrew_daleth: c_uint = 0xce3; 971 | pub const XK_hebrew_he: c_uint = 0xce4; 972 | pub const XK_hebrew_waw: c_uint = 0xce5; 973 | pub const XK_hebrew_zain: c_uint = 0xce6; 974 | pub const XK_hebrew_zayin: c_uint = 0xce6; 975 | pub const XK_hebrew_chet: c_uint = 0xce7; 976 | pub const XK_hebrew_het: c_uint = 0xce7; 977 | pub const XK_hebrew_tet: c_uint = 0xce8; 978 | pub const XK_hebrew_teth: c_uint = 0xce8; 979 | pub const XK_hebrew_yod: c_uint = 0xce9; 980 | pub const XK_hebrew_finalkaph: c_uint = 0xcea; 981 | pub const XK_hebrew_kaph: c_uint = 0xceb; 982 | pub const XK_hebrew_lamed: c_uint = 0xcec; 983 | pub const XK_hebrew_finalmem: c_uint = 0xced; 984 | pub const XK_hebrew_mem: c_uint = 0xcee; 985 | pub const XK_hebrew_finalnun: c_uint = 0xcef; 986 | pub const XK_hebrew_nun: c_uint = 0xcf0; 987 | pub const XK_hebrew_samech: c_uint = 0xcf1; 988 | pub const XK_hebrew_samekh: c_uint = 0xcf1; 989 | pub const XK_hebrew_ayin: c_uint = 0xcf2; 990 | pub const XK_hebrew_finalpe: c_uint = 0xcf3; 991 | pub const XK_hebrew_pe: c_uint = 0xcf4; 992 | pub const XK_hebrew_finalzade: c_uint = 0xcf5; 993 | pub const XK_hebrew_finalzadi: c_uint = 0xcf5; 994 | pub const XK_hebrew_zade: c_uint = 0xcf6; 995 | pub const XK_hebrew_zadi: c_uint = 0xcf6; 996 | pub const XK_hebrew_qoph: c_uint = 0xcf7; 997 | pub const XK_hebrew_kuf: c_uint = 0xcf7; 998 | pub const XK_hebrew_resh: c_uint = 0xcf8; 999 | pub const XK_hebrew_shin: c_uint = 0xcf9; 1000 | pub const XK_hebrew_taw: c_uint = 0xcfa; 1001 | pub const XK_hebrew_taf: c_uint = 0xcfa; 1002 | pub const XK_Hebrew_switch: c_uint = 0xFF7E; 1003 | 1004 | pub const XF86XK_ModeLock: c_uint = 0x1008FF01; 1005 | pub const XF86XK_MonBrightnessUp: c_uint = 0x1008FF02; 1006 | pub const XF86XK_MonBrightnessDown: c_uint = 0x1008FF03; 1007 | pub const XF86XK_KbdLightOnOff: c_uint = 0x1008FF04; 1008 | pub const XF86XK_KbdBrightnessUp: c_uint = 0x1008FF05; 1009 | pub const XF86XK_KbdBrightnessDown: c_uint = 0x1008FF06; 1010 | pub const XF86XK_Standby: c_uint = 0x1008FF10; 1011 | pub const XF86XK_AudioLowerVolume: c_uint = 0x1008FF11; 1012 | pub const XF86XK_AudioMute: c_uint = 0x1008FF12; 1013 | pub const XF86XK_AudioRaiseVolume: c_uint = 0x1008FF13; 1014 | pub const XF86XK_AudioPlay: c_uint = 0x1008FF14; 1015 | pub const XF86XK_AudioStop: c_uint = 0x1008FF15; 1016 | pub const XF86XK_AudioPrev: c_uint = 0x1008FF16; 1017 | pub const XF86XK_AudioNext: c_uint = 0x1008FF17; 1018 | pub const XF86XK_HomePage: c_uint = 0x1008FF18; 1019 | pub const XF86XK_Mail: c_uint = 0x1008FF19; 1020 | pub const XF86XK_Start: c_uint = 0x1008FF1A; 1021 | pub const XF86XK_Search: c_uint = 0x1008FF1B; 1022 | pub const XF86XK_AudioRecord: c_uint = 0x1008FF1C; 1023 | pub const XF86XK_Calculator: c_uint = 0x1008FF1D; 1024 | pub const XF86XK_Memo: c_uint = 0x1008FF1E; 1025 | pub const XF86XK_ToDoList: c_uint = 0x1008FF1F; 1026 | pub const XF86XK_Calendar: c_uint = 0x1008FF20; 1027 | pub const XF86XK_PowerDown: c_uint = 0x1008FF21; 1028 | pub const XF86XK_ContrastAdjust: c_uint = 0x1008FF22; 1029 | pub const XF86XK_RockerUp: c_uint = 0x1008FF23; 1030 | pub const XF86XK_RockerDown: c_uint = 0x1008FF24; 1031 | pub const XF86XK_RockerEnter: c_uint = 0x1008FF25; 1032 | pub const XF86XK_Back: c_uint = 0x1008FF26; 1033 | pub const XF86XK_Forward: c_uint = 0x1008FF27; 1034 | pub const XF86XK_Stop: c_uint = 0x1008FF28; 1035 | pub const XF86XK_Refresh: c_uint = 0x1008FF29; 1036 | pub const XF86XK_PowerOff: c_uint = 0x1008FF2A; 1037 | pub const XF86XK_WakeUp: c_uint = 0x1008FF2B; 1038 | pub const XF86XK_Eject: c_uint = 0x1008FF2C; 1039 | pub const XF86XK_ScreenSaver: c_uint = 0x1008FF2D; 1040 | pub const XF86XK_WWW: c_uint = 0x1008FF2E; 1041 | pub const XF86XK_Sleep: c_uint = 0x1008FF2F; 1042 | pub const XF86XK_Favorites: c_uint = 0x1008FF30; 1043 | pub const XF86XK_AudioPause: c_uint = 0x1008FF31; 1044 | pub const XF86XK_AudioMedia: c_uint = 0x1008FF32; 1045 | pub const XF86XK_MyComputer: c_uint = 0x1008FF33; 1046 | pub const XF86XK_VendorHome: c_uint = 0x1008FF34; 1047 | pub const XF86XK_LightBulb: c_uint = 0x1008FF35; 1048 | pub const XF86XK_Shop: c_uint = 0x1008FF36; 1049 | pub const XF86XK_History: c_uint = 0x1008FF37; 1050 | pub const XF86XK_OpenURL: c_uint = 0x1008FF38; 1051 | pub const XF86XK_AddFavorite: c_uint = 0x1008FF39; 1052 | pub const XF86XK_HotLinks: c_uint = 0x1008FF3A; 1053 | pub const XF86XK_BrightnessAdjust: c_uint = 0x1008FF3B; 1054 | pub const XF86XK_Finance: c_uint = 0x1008FF3C; 1055 | pub const XF86XK_Community: c_uint = 0x1008FF3D; 1056 | pub const XF86XK_AudioRewind: c_uint = 0x1008FF3E; 1057 | pub const XF86XK_BackForward: c_uint = 0x1008FF3F; 1058 | pub const XF86XK_Launch0: c_uint = 0x1008FF40; 1059 | pub const XF86XK_Launch1: c_uint = 0x1008FF41; 1060 | pub const XF86XK_Launch2: c_uint = 0x1008FF42; 1061 | pub const XF86XK_Launch3: c_uint = 0x1008FF43; 1062 | pub const XF86XK_Launch4: c_uint = 0x1008FF44; 1063 | pub const XF86XK_Launch5: c_uint = 0x1008FF45; 1064 | pub const XF86XK_Launch6: c_uint = 0x1008FF46; 1065 | pub const XF86XK_Launch7: c_uint = 0x1008FF47; 1066 | pub const XF86XK_Launch8: c_uint = 0x1008FF48; 1067 | pub const XF86XK_Launch9: c_uint = 0x1008FF49; 1068 | pub const XF86XK_LaunchA: c_uint = 0x1008FF4A; 1069 | pub const XF86XK_LaunchB: c_uint = 0x1008FF4B; 1070 | pub const XF86XK_LaunchC: c_uint = 0x1008FF4C; 1071 | pub const XF86XK_LaunchD: c_uint = 0x1008FF4D; 1072 | pub const XF86XK_LaunchE: c_uint = 0x1008FF4E; 1073 | pub const XF86XK_LaunchF: c_uint = 0x1008FF4F; 1074 | pub const XF86XK_ApplicationLeft: c_uint = 0x1008FF50; 1075 | pub const XF86XK_ApplicationRight: c_uint = 0x1008FF51; 1076 | pub const XF86XK_Book: c_uint = 0x1008FF52; 1077 | pub const XF86XK_CD: c_uint = 0x1008FF53; 1078 | pub const XF86XK_Calculater: c_uint = 0x1008FF54; 1079 | pub const XF86XK_Clear: c_uint = 0x1008FF55; 1080 | pub const XF86XK_Close: c_uint = 0x1008FF56; 1081 | pub const XF86XK_Copy: c_uint = 0x1008FF57; 1082 | pub const XF86XK_Cut: c_uint = 0x1008FF58; 1083 | pub const XF86XK_Display: c_uint = 0x1008FF59; 1084 | pub const XF86XK_DOS: c_uint = 0x1008FF5A; 1085 | pub const XF86XK_Documents: c_uint = 0x1008FF5B; 1086 | pub const XF86XK_Excel: c_uint = 0x1008FF5C; 1087 | pub const XF86XK_Explorer: c_uint = 0x1008FF5D; 1088 | pub const XF86XK_Game: c_uint = 0x1008FF5E; 1089 | pub const XF86XK_Go: c_uint = 0x1008FF5F; 1090 | pub const XF86XK_iTouch: c_uint = 0x1008FF60; 1091 | pub const XF86XK_LogOff: c_uint = 0x1008FF61; 1092 | pub const XF86XK_Market: c_uint = 0x1008FF62; 1093 | pub const XF86XK_Meeting: c_uint = 0x1008FF63; 1094 | pub const XF86XK_MenuKB: c_uint = 0x1008FF65; 1095 | pub const XF86XK_MenuPB: c_uint = 0x1008FF66; 1096 | pub const XF86XK_MySites: c_uint = 0x1008FF67; 1097 | pub const XF86XK_New: c_uint = 0x1008FF68; 1098 | pub const XF86XK_News: c_uint = 0x1008FF69; 1099 | pub const XF86XK_OfficeHome: c_uint = 0x1008FF6A; 1100 | pub const XF86XK_Open: c_uint = 0x1008FF6B; 1101 | pub const XF86XK_Option: c_uint = 0x1008FF6C; 1102 | pub const XF86XK_Paste: c_uint = 0x1008FF6D; 1103 | pub const XF86XK_Phone: c_uint = 0x1008FF6E; 1104 | pub const XF86XK_Q: c_uint = 0x1008FF70; 1105 | pub const XF86XK_Reply: c_uint = 0x1008FF72; 1106 | pub const XF86XK_Reload: c_uint = 0x1008FF73; 1107 | pub const XF86XK_RotateWindows: c_uint = 0x1008FF74; 1108 | pub const XF86XK_RotationPB: c_uint = 0x1008FF75; 1109 | pub const XF86XK_RotationKB: c_uint = 0x1008FF76; 1110 | pub const XF86XK_Save: c_uint = 0x1008FF77; 1111 | pub const XF86XK_ScrollUp: c_uint = 0x1008FF78; 1112 | pub const XF86XK_ScrollDown: c_uint = 0x1008FF79; 1113 | pub const XF86XK_ScrollClick: c_uint = 0x1008FF7A; 1114 | pub const XF86XK_Send: c_uint = 0x1008FF7B; 1115 | pub const XF86XK_Spell: c_uint = 0x1008FF7C; 1116 | pub const XF86XK_SplitScreen: c_uint = 0x1008FF7D; 1117 | pub const XF86XK_Support: c_uint = 0x1008FF7E; 1118 | pub const XF86XK_TaskPane: c_uint = 0x1008FF7F; 1119 | pub const XF86XK_Terminal: c_uint = 0x1008FF80; 1120 | pub const XF86XK_Tools: c_uint = 0x1008FF81; 1121 | pub const XF86XK_Travel: c_uint = 0x1008FF82; 1122 | pub const XF86XK_UserPB: c_uint = 0x1008FF84; 1123 | pub const XF86XK_User1KB: c_uint = 0x1008FF85; 1124 | pub const XF86XK_User2KB: c_uint = 0x1008FF86; 1125 | pub const XF86XK_Video: c_uint = 0x1008FF87; 1126 | pub const XF86XK_WheelButton: c_uint = 0x1008FF88; 1127 | pub const XF86XK_Word: c_uint = 0x1008FF89; 1128 | pub const XF86XK_Xfer: c_uint = 0x1008FF8A; 1129 | pub const XF86XK_ZoomIn: c_uint = 0x1008FF8B; 1130 | pub const XF86XK_ZoomOut: c_uint = 0x1008FF8C; 1131 | pub const XF86XK_Away: c_uint = 0x1008FF8D; 1132 | pub const XF86XK_Messenger: c_uint = 0x1008FF8E; 1133 | pub const XF86XK_WebCam: c_uint = 0x1008FF8F; 1134 | pub const XF86XK_MailForward: c_uint = 0x1008FF90; 1135 | pub const XF86XK_Pictures: c_uint = 0x1008FF91; 1136 | pub const XF86XK_Music: c_uint = 0x1008FF92; 1137 | pub const XF86XK_Battery: c_uint = 0x1008FF93; 1138 | pub const XF86XK_Bluetooth: c_uint = 0x1008FF94; 1139 | pub const XF86XK_WLAN: c_uint = 0x1008FF95; 1140 | pub const XF86XK_UWB: c_uint = 0x1008FF96; 1141 | pub const XF86XK_AudioForward: c_uint = 0x1008FF97; 1142 | pub const XF86XK_AudioRepeat: c_uint = 0x1008FF98; 1143 | pub const XF86XK_AudioRandomPlay: c_uint = 0x1008FF99; 1144 | pub const XF86XK_Subtitle: c_uint = 0x1008FF9A; 1145 | pub const XF86XK_AudioCycleTrack: c_uint = 0x1008FF9B; 1146 | pub const XF86XK_CycleAngle: c_uint = 0x1008FF9C; 1147 | pub const XF86XK_FrameBack: c_uint = 0x1008FF9D; 1148 | pub const XF86XK_FrameForward: c_uint = 0x1008FF9E; 1149 | pub const XF86XK_Time: c_uint = 0x1008FF9F; 1150 | pub const XF86XK_Select: c_uint = 0x1008FFA0; 1151 | pub const XF86XK_View: c_uint = 0x1008FFA1; 1152 | pub const XF86XK_TopMenu: c_uint = 0x1008FFA2; 1153 | pub const XF86XK_Red: c_uint = 0x1008FFA3; 1154 | pub const XF86XK_Green: c_uint = 0x1008FFA4; 1155 | pub const XF86XK_Yellow: c_uint = 0x1008FFA5; 1156 | pub const XF86XK_Blue: c_uint = 0x1008FFA6; 1157 | pub const XF86XK_Suspend: c_uint = 0x1008FFA7; 1158 | pub const XF86XK_Hibernate: c_uint = 0x1008FFA8; 1159 | pub const XF86XK_TouchpadToggle: c_uint = 0x1008FFA9; 1160 | pub const XF86XK_TouchpadOn: c_uint = 0x1008FFB0; 1161 | pub const XF86XK_TouchpadOff: c_uint = 0x1008FFB1; 1162 | pub const XF86XK_AudioMicMute: c_uint = 0x1008FFB2; 1163 | pub const XF86XK_Switch_VT_1: c_uint = 0x1008FE01; 1164 | pub const XF86XK_Switch_VT_2: c_uint = 0x1008FE02; 1165 | pub const XF86XK_Switch_VT_3: c_uint = 0x1008FE03; 1166 | pub const XF86XK_Switch_VT_4: c_uint = 0x1008FE04; 1167 | pub const XF86XK_Switch_VT_5: c_uint = 0x1008FE05; 1168 | pub const XF86XK_Switch_VT_6: c_uint = 0x1008FE06; 1169 | pub const XF86XK_Switch_VT_7: c_uint = 0x1008FE07; 1170 | pub const XF86XK_Switch_VT_8: c_uint = 0x1008FE08; 1171 | pub const XF86XK_Switch_VT_9: c_uint = 0x1008FE09; 1172 | pub const XF86XK_Switch_VT_10: c_uint = 0x1008FE0A; 1173 | pub const XF86XK_Switch_VT_11: c_uint = 0x1008FE0B; 1174 | pub const XF86XK_Switch_VT_12: c_uint = 0x1008FE0C; 1175 | pub const XF86XK_Ungrab: c_uint = 0x1008FE20; 1176 | pub const XF86XK_ClearGrab: c_uint = 0x1008FE21; 1177 | pub const XF86XK_Next_VMode: c_uint = 0x1008FE22; 1178 | pub const XF86XK_Prev_VMode: c_uint = 0x1008FE23; 1179 | pub const XF86XK_LogWindowTree: c_uint = 0x1008FE24; 1180 | pub const XF86XK_LogGrabInfo: c_uint = 0x1008FE25; 1181 | 1182 | pub const XK_ISO_Lock: c_uint = 0xfe01; 1183 | pub const XK_ISO_Level2_Latch: c_uint = 0xfe02; 1184 | pub const XK_ISO_Level3_Shift: c_uint = 0xfe03; 1185 | pub const XK_ISO_Level3_Latch: c_uint = 0xfe04; 1186 | pub const XK_ISO_Level3_Lock: c_uint = 0xfe05; 1187 | pub const XK_ISO_Level5_Shift: c_uint = 0xfe11; 1188 | pub const XK_ISO_Level5_Latch: c_uint = 0xfe12; 1189 | pub const XK_ISO_Level5_Lock: c_uint = 0xfe13; 1190 | pub const XK_ISO_Group_Shift: c_uint = 0xff7e; 1191 | pub const XK_ISO_Group_Latch: c_uint = 0xfe06; 1192 | pub const XK_ISO_Group_Lock: c_uint = 0xfe07; 1193 | pub const XK_ISO_Next_Group: c_uint = 0xfe08; 1194 | pub const XK_ISO_Next_Group_Lock: c_uint = 0xfe09; 1195 | pub const XK_ISO_Prev_Group: c_uint = 0xfe0a; 1196 | pub const XK_ISO_Prev_Group_Lock: c_uint = 0xfe0b; 1197 | pub const XK_ISO_First_Group: c_uint = 0xfe0c; 1198 | pub const XK_ISO_First_Group_Lock: c_uint = 0xfe0d; 1199 | pub const XK_ISO_Last_Group: c_uint = 0xfe0e; 1200 | pub const XK_ISO_Last_Group_Lock: c_uint = 0xfe0f; 1201 | 1202 | pub const XK_ISO_Left_Tab: c_uint = 0xfe20; 1203 | pub const XK_ISO_Move_Line_Up: c_uint = 0xfe21; 1204 | pub const XK_ISO_Move_Line_Down: c_uint = 0xfe22; 1205 | pub const XK_ISO_Partial_Line_Up: c_uint = 0xfe23; 1206 | pub const XK_ISO_Partial_Line_Down: c_uint = 0xfe24; 1207 | pub const XK_ISO_Partial_Space_Left: c_uint = 0xfe25; 1208 | pub const XK_ISO_Partial_Space_Right: c_uint = 0xfe26; 1209 | pub const XK_ISO_Set_Margin_Left: c_uint = 0xfe27; 1210 | pub const XK_ISO_Set_Margin_Right: c_uint = 0xfe28; 1211 | pub const XK_ISO_Release_Margin_Left: c_uint = 0xfe29; 1212 | pub const XK_ISO_Release_Margin_Right: c_uint = 0xfe2a; 1213 | pub const XK_ISO_Release_Both_Margins: c_uint = 0xfe2b; 1214 | pub const XK_ISO_Fast_Cursor_Left: c_uint = 0xfe2c; 1215 | pub const XK_ISO_Fast_Cursor_Right: c_uint = 0xfe2d; 1216 | pub const XK_ISO_Fast_Cursor_Up: c_uint = 0xfe2e; 1217 | pub const XK_ISO_Fast_Cursor_Down: c_uint = 0xfe2f; 1218 | pub const XK_ISO_Continuous_Underline: c_uint = 0xfe30; 1219 | pub const XK_ISO_Discontinuous_Underline: c_uint = 0xfe31; 1220 | pub const XK_ISO_Emphasize: c_uint = 0xfe32; 1221 | pub const XK_ISO_Center_Object: c_uint = 0xfe33; 1222 | pub const XK_ISO_Enter: c_uint = 0xfe34; 1223 | 1224 | pub const XK_dead_grave: c_uint = 0xfe50; 1225 | pub const XK_dead_acute: c_uint = 0xfe51; 1226 | pub const XK_dead_circumflex: c_uint = 0xfe52; 1227 | pub const XK_dead_tilde: c_uint = 0xfe53; 1228 | pub const XK_dead_perispomeni: c_uint = 0xfe53; 1229 | pub const XK_dead_macron: c_uint = 0xfe54; 1230 | pub const XK_dead_breve: c_uint = 0xfe55; 1231 | pub const XK_dead_abovedot: c_uint = 0xfe56; 1232 | pub const XK_dead_diaeresis: c_uint = 0xfe57; 1233 | pub const XK_dead_abovering: c_uint = 0xfe58; 1234 | pub const XK_dead_doubleacute: c_uint = 0xfe59; 1235 | pub const XK_dead_caron: c_uint = 0xfe5a; 1236 | pub const XK_dead_cedilla: c_uint = 0xfe5b; 1237 | pub const XK_dead_ogonek: c_uint = 0xfe5c; 1238 | pub const XK_dead_iota: c_uint = 0xfe5d; 1239 | pub const XK_dead_voiced_sound: c_uint = 0xfe5e; 1240 | pub const XK_dead_semivoiced_sound: c_uint = 0xfe5f; 1241 | pub const XK_dead_belowdot: c_uint = 0xfe60; 1242 | pub const XK_dead_hook: c_uint = 0xfe61; 1243 | pub const XK_dead_horn: c_uint = 0xfe62; 1244 | pub const XK_dead_stroke: c_uint = 0xfe63; 1245 | pub const XK_dead_abovecomma: c_uint = 0xfe64; 1246 | pub const XK_dead_psili: c_uint = 0xfe64; 1247 | pub const XK_dead_abovereversedcomma: c_uint = 0xfe65; 1248 | pub const XK_dead_dasia: c_uint = 0xfe65; 1249 | pub const XK_dead_doublegrave: c_uint = 0xfe66; 1250 | pub const XK_dead_belowring: c_uint = 0xfe67; 1251 | pub const XK_dead_belowmacron: c_uint = 0xfe68; 1252 | pub const XK_dead_belowcircumflex: c_uint = 0xfe69; 1253 | pub const XK_dead_belowtilde: c_uint = 0xfe6a; 1254 | pub const XK_dead_belowbreve: c_uint = 0xfe6b; 1255 | pub const XK_dead_belowdiaeresis: c_uint = 0xfe6c; 1256 | pub const XK_dead_invertedbreve: c_uint = 0xfe6d; 1257 | pub const XK_dead_belowcomma: c_uint = 0xfe6e; 1258 | pub const XK_dead_currency: c_uint = 0xfe6f; 1259 | 1260 | pub const XK_dead_lowline: c_uint = 0xfe90; 1261 | pub const XK_dead_aboveverticalline: c_uint = 0xfe91; 1262 | pub const XK_dead_belowverticalline: c_uint = 0xfe92; 1263 | pub const XK_dead_longsolidusoverlay: c_uint = 0xfe93; 1264 | 1265 | pub const XK_dead_a: c_uint = 0xfe80; 1266 | pub const XK_dead_A: c_uint = 0xfe81; 1267 | pub const XK_dead_e: c_uint = 0xfe82; 1268 | pub const XK_dead_E: c_uint = 0xfe83; 1269 | pub const XK_dead_i: c_uint = 0xfe84; 1270 | pub const XK_dead_I: c_uint = 0xfe85; 1271 | pub const XK_dead_o: c_uint = 0xfe86; 1272 | pub const XK_dead_O: c_uint = 0xfe87; 1273 | pub const XK_dead_u: c_uint = 0xfe88; 1274 | pub const XK_dead_U: c_uint = 0xfe89; 1275 | pub const XK_dead_small_schwa: c_uint = 0xfe8a; 1276 | pub const XK_dead_capital_schwa: c_uint = 0xfe8b; 1277 | 1278 | pub const XK_dead_greek: c_uint = 0xfe8c; 1279 | 1280 | pub const XK_First_Virtual_Screen: c_uint = 0xfed0; 1281 | pub const XK_Prev_Virtual_Screen: c_uint = 0xfed1; 1282 | pub const XK_Next_Virtual_Screen: c_uint = 0xfed2; 1283 | pub const XK_Last_Virtual_Screen: c_uint = 0xfed4; 1284 | pub const XK_Terminate_Server: c_uint = 0xfed5; 1285 | 1286 | pub const XK_AccessX_Enable: c_uint = 0xfe70; 1287 | pub const XK_AccessX_Feedback_Enable: c_uint = 0xfe71; 1288 | pub const XK_RepeatKeys_Enable: c_uint = 0xfe72; 1289 | pub const XK_SlowKeys_Enable: c_uint = 0xfe73; 1290 | pub const XK_BounceKeys_Enable: c_uint = 0xfe74; 1291 | pub const XK_StickyKeys_Enable: c_uint = 0xfe75; 1292 | pub const XK_MouseKeys_Enable: c_uint = 0xfe76; 1293 | pub const XK_MouseKeys_Accel_Enable: c_uint = 0xfe77; 1294 | pub const XK_Overlay1_Enable: c_uint = 0xfe78; 1295 | pub const XK_Overlay2_Enable: c_uint = 0xfe79; 1296 | pub const XK_AudibleBell_Enable: c_uint = 0xfe7a; 1297 | 1298 | pub const XK_Pointer_Left: c_uint = 0xfee0; 1299 | pub const XK_Pointer_Right: c_uint = 0xfee1; 1300 | pub const XK_Pointer_Up: c_uint = 0xfee2; 1301 | pub const XK_Pointer_Down: c_uint = 0xfee3; 1302 | pub const XK_Pointer_UpLeft: c_uint = 0xfee4; 1303 | pub const XK_Pointer_UpRight: c_uint = 0xfee5; 1304 | pub const XK_Pointer_DownLeft: c_uint = 0xfee6; 1305 | pub const XK_Pointer_DownRight: c_uint = 0xfee7; 1306 | pub const XK_Pointer_Button_Dflt: c_uint = 0xfee8; 1307 | pub const XK_Pointer_Button1: c_uint = 0xfee9; 1308 | pub const XK_Pointer_Button2: c_uint = 0xfeea; 1309 | pub const XK_Pointer_Button3: c_uint = 0xfeeb; 1310 | pub const XK_Pointer_Button4: c_uint = 0xfeec; 1311 | pub const XK_Pointer_Button5: c_uint = 0xfeed; 1312 | pub const XK_Pointer_DblClick_Dflt: c_uint = 0xfeee; 1313 | pub const XK_Pointer_DblClick1: c_uint = 0xfeef; 1314 | pub const XK_Pointer_DblClick2: c_uint = 0xfef0; 1315 | pub const XK_Pointer_DblClick3: c_uint = 0xfef1; 1316 | pub const XK_Pointer_DblClick4: c_uint = 0xfef2; 1317 | pub const XK_Pointer_DblClick5: c_uint = 0xfef3; 1318 | pub const XK_Pointer_Drag_Dflt: c_uint = 0xfef4; 1319 | pub const XK_Pointer_Drag1: c_uint = 0xfef5; 1320 | pub const XK_Pointer_Drag2: c_uint = 0xfef6; 1321 | pub const XK_Pointer_Drag3: c_uint = 0xfef7; 1322 | pub const XK_Pointer_Drag4: c_uint = 0xfef8; 1323 | pub const XK_Pointer_Drag5: c_uint = 0xfefd; 1324 | 1325 | pub const XK_Pointer_EnableKeys: c_uint = 0xfef9; 1326 | pub const XK_Pointer_Accelerate: c_uint = 0xfefa; 1327 | pub const XK_Pointer_DfltBtnNext: c_uint = 0xfefb; 1328 | pub const XK_Pointer_DfltBtnPrev: c_uint = 0xfefc; 1329 | 1330 | pub const XK_ch: c_uint = 0xfea0; 1331 | pub const XK_Ch: c_uint = 0xfea1; 1332 | pub const XK_CH: c_uint = 0xfea2; 1333 | pub const XK_c_h: c_uint = 0xfea3; 1334 | pub const XK_C_h: c_uint = 0xfea4; 1335 | pub const XK_C_H: c_uint = 0xfea5; 1336 | 1337 | // modifier keys mask 1338 | pub const ShiftMask: c_uint = 0x01; 1339 | pub const LockMask: c_uint = 0x02; 1340 | pub const ControlMask: c_uint = 0x04; 1341 | pub const Mod1Mask: c_uint = 0x08; 1342 | pub const Mod2Mask: c_uint = 0x10; 1343 | pub const Mod3Mask: c_uint = 0x20; 1344 | pub const Mod4Mask: c_uint = 0x40; 1345 | pub const Mod5Mask: c_uint = 0x80; 1346 | 1347 | pub const AnyModifier: c_uint = 1 << 15; 1348 | --------------------------------------------------------------------------------