all: remove control center in its entirety
This commit is contained in:
parent
1dfd6169f8
commit
769d12a525
97 changed files with 59 additions and 10580 deletions
258
Cargo.lock
generated
258
Cargo.lock
generated
|
|
@ -2,15 +2,6 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 4
|
version = 4
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "accesskit"
|
|
||||||
version = "0.24.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5351dcebb14b579ccab05f288596b2ae097005be7ee50a7c3d4ca9d0d5a66f6a"
|
|
||||||
dependencies = [
|
|
||||||
"uuid",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "addr2line"
|
name = "addr2line"
|
||||||
version = "0.25.1"
|
version = "0.25.1"
|
||||||
|
|
@ -196,20 +187,6 @@ name = "bytemuck"
|
||||||
version = "1.25.0"
|
version = "1.25.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec"
|
checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec"
|
||||||
dependencies = [
|
|
||||||
"bytemuck_derive",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bytemuck_derive"
|
|
||||||
version = "1.10.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.117",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
|
|
@ -307,15 +284,6 @@ version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
|
checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "color"
|
|
||||||
version = "0.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a18ef4657441fb193b65f34dc39b3781f0dfec23d3bd94d0eeb4e88cde421edb"
|
|
||||||
dependencies = [
|
|
||||||
"bytemuck",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "colorchoice"
|
name = "colorchoice"
|
||||||
version = "1.0.5"
|
version = "1.0.5"
|
||||||
|
|
@ -397,77 +365,6 @@ dependencies = [
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ecolor"
|
|
||||||
version = "0.34.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "137c0ce4ce4152ff7e223a7ce22ee1057cdff61fce0a45c32459c3ccec64868d"
|
|
||||||
dependencies = [
|
|
||||||
"emath",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "egui"
|
|
||||||
version = "0.34.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f34aaf627da598dfadd64b0fee6101d22e9c451d1e5348157312720b7f459f0f"
|
|
||||||
dependencies = [
|
|
||||||
"accesskit",
|
|
||||||
"ahash",
|
|
||||||
"bitflags",
|
|
||||||
"emath",
|
|
||||||
"epaint",
|
|
||||||
"log",
|
|
||||||
"nohash-hasher",
|
|
||||||
"profiling",
|
|
||||||
"smallvec",
|
|
||||||
"unicode-segmentation",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "egui_tiles"
|
|
||||||
version = "0.15.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "08e570b77f6cce3292eba4aee9b9c08cf11dfc68430f4dc9613d939628498647"
|
|
||||||
dependencies = [
|
|
||||||
"ahash",
|
|
||||||
"egui",
|
|
||||||
"itertools",
|
|
||||||
"log",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "either"
|
|
||||||
version = "1.15.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "emath"
|
|
||||||
version = "0.34.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0a05cd8bdf3b598488c627ca97c7fe8909448ffa26278dd3c7e535cdb554d721"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "epaint"
|
|
||||||
version = "0.34.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "04f3017dd67f147a697ee0c8484fb568fd9553e2a0c114be5020dbbc11962841"
|
|
||||||
dependencies = [
|
|
||||||
"ahash",
|
|
||||||
"ecolor",
|
|
||||||
"emath",
|
|
||||||
"font-types",
|
|
||||||
"log",
|
|
||||||
"nohash-hasher",
|
|
||||||
"parking_lot",
|
|
||||||
"profiling",
|
|
||||||
"self_cell",
|
|
||||||
"skrifa",
|
|
||||||
"smallvec",
|
|
||||||
"vello_cpu",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "equivalent"
|
name = "equivalent"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
|
|
@ -490,15 +387,6 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "31ae425815400e5ed474178a7a22e275a9687086a12ca63ec793ff292d8fdae8"
|
checksum = "31ae425815400e5ed474178a7a22e275a9687086a12ca63ec793ff292d8fdae8"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "euclid"
|
|
||||||
version = "0.22.14"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f1a05365e3b1c6d1650318537c7460c6923f1abdd272ad6842baa2b509957a06"
|
|
||||||
dependencies = [
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastrand"
|
name = "fastrand"
|
||||||
version = "2.3.0"
|
version = "2.3.0"
|
||||||
|
|
@ -514,15 +402,6 @@ dependencies = [
|
||||||
"simd-adler32",
|
"simd-adler32",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fearless_simd"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8fb2907d1f08b2b316b9223ced5b0e89d87028ba8deae9764741dba8ff7f3903"
|
|
||||||
dependencies = [
|
|
||||||
"bytemuck",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "find-msvc-tools"
|
name = "find-msvc-tools"
|
||||||
version = "0.1.9"
|
version = "0.1.9"
|
||||||
|
|
@ -545,21 +424,6 @@ version = "0.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "foldhash"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "font-types"
|
|
||||||
version = "0.11.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "73829a7b5c91198af28a99159b7ae4afbb252fb906159ff7f189f3a2ceaa3df2"
|
|
||||||
dependencies = [
|
|
||||||
"bytemuck",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-core"
|
name = "futures-core"
|
||||||
version = "0.3.32"
|
version = "0.3.32"
|
||||||
|
|
@ -672,7 +536,7 @@ version = "0.15.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"foldhash 0.1.5",
|
"foldhash",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -680,9 +544,6 @@ name = "hashbrown"
|
||||||
version = "0.16.1"
|
version = "0.16.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
|
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
|
||||||
dependencies = [
|
|
||||||
"foldhash 0.2.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
|
|
@ -756,15 +617,6 @@ version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f1697e6b71679da96d5c41bb9035116141baadbf59a60625fd66cb3c9584e7b0"
|
checksum = "f1697e6b71679da96d5c41bb9035116141baadbf59a60625fd66cb3c9584e7b0"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "itertools"
|
|
||||||
version = "0.14.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
|
|
||||||
dependencies = [
|
|
||||||
"either",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.17"
|
version = "1.0.17"
|
||||||
|
|
@ -805,8 +657,6 @@ dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"clap_complete",
|
"clap_complete",
|
||||||
"dirs",
|
"dirs",
|
||||||
"egui",
|
|
||||||
"egui_tiles",
|
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"gpu-alloc",
|
"gpu-alloc",
|
||||||
"gpu-alloc-types",
|
"gpu-alloc-types",
|
||||||
|
|
@ -925,17 +775,6 @@ dependencies = [
|
||||||
"syn 2.0.117",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "kurbo"
|
|
||||||
version = "0.13.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7564e90fe3c0d5771e1f0bc95322b21baaeaa0d9213fa6a0b61c99f8b17b3bfb"
|
|
||||||
dependencies = [
|
|
||||||
"arrayvec",
|
|
||||||
"euclid",
|
|
||||||
"smallvec",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
|
|
@ -997,12 +836,6 @@ dependencies = [
|
||||||
"syn 2.0.117",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "linebender_resource_handle"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d4a5ff6bcca6c4867b1c4fd4ef63e4db7436ef363e0ad7531d1558856bae64f4"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
|
|
@ -1040,12 +873,6 @@ dependencies = [
|
||||||
"simd-adler32",
|
"simd-adler32",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nohash-hasher"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-conv"
|
name = "num-conv"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
|
@ -1143,19 +970,6 @@ dependencies = [
|
||||||
"windows-link",
|
"windows-link",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "peniko"
|
|
||||||
version = "0.6.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9a2b6aadb221872732e87d465213e9be5af2849b0e8cc5300a8ba98fffa2e00a"
|
|
||||||
dependencies = [
|
|
||||||
"bytemuck",
|
|
||||||
"color",
|
|
||||||
"kurbo",
|
|
||||||
"linebender_resource_handle",
|
|
||||||
"smallvec",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "phf"
|
name = "phf"
|
||||||
version = "0.13.1"
|
version = "0.13.1"
|
||||||
|
|
@ -1269,12 +1083,6 @@ dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "profiling"
|
|
||||||
version = "1.0.17"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quick-xml"
|
name = "quick-xml"
|
||||||
version = "0.39.2"
|
version = "0.39.2"
|
||||||
|
|
@ -1352,16 +1160,6 @@ version = "0.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba"
|
checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "read-fonts"
|
|
||||||
version = "0.37.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7b634fabf032fab15307ffd272149b622260f55974d9fad689292a5d33df02e5"
|
|
||||||
dependencies = [
|
|
||||||
"bytemuck",
|
|
||||||
"font-types",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.5.18"
|
version = "0.5.18"
|
||||||
|
|
@ -1487,12 +1285,6 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "self_cell"
|
|
||||||
version = "1.2.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
version = "1.0.27"
|
version = "1.0.27"
|
||||||
|
|
@ -1585,16 +1377,6 @@ version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e"
|
checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "skrifa"
|
|
||||||
version = "0.40.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7fbdfe3d2475fbd7ddd1f3e5cf8288a30eb3e5f95832829570cd88115a7434ac"
|
|
||||||
dependencies = [
|
|
||||||
"bytemuck",
|
|
||||||
"read-fonts",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.12"
|
version = "0.4.12"
|
||||||
|
|
@ -1792,12 +1574,6 @@ version = "1.0.24"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-segmentation"
|
|
||||||
version = "1.12.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-width"
|
name = "unicode-width"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
|
|
@ -1822,38 +1598,6 @@ version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "uuid"
|
|
||||||
version = "1.23.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "vello_common"
|
|
||||||
version = "0.0.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1bd1a4c633ce09e7d713df1a6e036644a125e15e0c169cfb5180ddf5836ca04b"
|
|
||||||
dependencies = [
|
|
||||||
"bytemuck",
|
|
||||||
"fearless_simd",
|
|
||||||
"hashbrown 0.16.1",
|
|
||||||
"log",
|
|
||||||
"peniko",
|
|
||||||
"skrifa",
|
|
||||||
"smallvec",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "vello_cpu"
|
|
||||||
version = "0.0.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0162bfe48aabf6a9fdcd401b628c7d9f260c2cbabb343c70a65feba6f7849edc"
|
|
||||||
dependencies = [
|
|
||||||
"bytemuck",
|
|
||||||
"hashbrown 0.16.1",
|
|
||||||
"vello_common",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.5"
|
version = "0.9.5"
|
||||||
|
|
|
||||||
45
Cargo.toml
45
Cargo.toml
|
|
@ -68,8 +68,6 @@ opera = "1.0.1"
|
||||||
with_builtin_macros = "0.1.0"
|
with_builtin_macros = "0.1.0"
|
||||||
blake3 = "1.8.2"
|
blake3 = "1.8.2"
|
||||||
run-on-drop = "1.0.0"
|
run-on-drop = "1.0.0"
|
||||||
egui = { version = "0.34.1", default-features = false }
|
|
||||||
egui_tiles = { version = "0.15.0", default-features = false }
|
|
||||||
numeric-sort = "0.1.5"
|
numeric-sort = "0.1.5"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
|
@ -89,49 +87,6 @@ opt-level = 3
|
||||||
[profile.dev.package."smallvec"]
|
[profile.dev.package."smallvec"]
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
|
|
||||||
[profile.dev.package."egui"]
|
|
||||||
opt-level = 3
|
|
||||||
debug = "line-tables-only"
|
|
||||||
|
|
||||||
[profile.dev.package."emath"]
|
|
||||||
opt-level = 3
|
|
||||||
debug = "line-tables-only"
|
|
||||||
|
|
||||||
[profile.dev.package."epaint"]
|
|
||||||
opt-level = 3
|
|
||||||
debug = "line-tables-only"
|
|
||||||
|
|
||||||
[profile.dev.package."ecolor"]
|
|
||||||
opt-level = 3
|
|
||||||
debug = "line-tables-only"
|
|
||||||
|
|
||||||
[profile.dev.package."font-types"]
|
|
||||||
opt-level = 3
|
|
||||||
debug = "line-tables-only"
|
|
||||||
|
|
||||||
[profile.dev.package."skrifa"]
|
|
||||||
opt-level = 3
|
|
||||||
debug = "line-tables-only"
|
|
||||||
|
|
||||||
[profile.dev.package."read-fonts"]
|
|
||||||
opt-level = 3
|
|
||||||
debug = "line-tables-only"
|
|
||||||
|
|
||||||
[profile.dev.package."vello_cpu"]
|
|
||||||
opt-level = 3
|
|
||||||
debug = "line-tables-only"
|
|
||||||
|
|
||||||
[profile.dev.package."vello_common"]
|
|
||||||
opt-level = 3
|
|
||||||
debug = "line-tables-only"
|
|
||||||
|
|
||||||
[profile.dev.package."peniko"]
|
|
||||||
opt-level = 3
|
|
||||||
debug = "line-tables-only"
|
|
||||||
|
|
||||||
[profile.dev.package."kurbo"]
|
|
||||||
opt-level = 3
|
|
||||||
debug = "line-tables-only"
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
rc_tracking = []
|
rc_tracking = []
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@
|
||||||
|
|
||||||
- [Installation](installation.md)
|
- [Installation](installation.md)
|
||||||
- [Running Jay](running.md)
|
- [Running Jay](running.md)
|
||||||
- [Control Center](control-center.md)
|
|
||||||
|
|
||||||
# Configuration
|
# Configuration
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -674,14 +674,6 @@ Show color management status:
|
||||||
|
|
||||||
## Other Commands
|
## Other Commands
|
||||||
|
|
||||||
### `jay control-center`
|
|
||||||
|
|
||||||
Open the [Control Center](control-center.md) GUI:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
~$ jay control-center
|
|
||||||
```
|
|
||||||
|
|
||||||
### `jay portal`
|
### `jay portal`
|
||||||
|
|
||||||
Run the Jay desktop portal (provides screen sharing and other XDG desktop
|
Run the Jay desktop portal (provides screen sharing and other XDG desktop
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,6 @@ alt-shift-r = "reload-config-toml"
|
||||||
- `disable-pointer-constraint` -- release a pointer lock/confinement
|
- `disable-pointer-constraint` -- release a pointer lock/confinement
|
||||||
- `focus-parent` -- move focus to the parent container
|
- `focus-parent` -- move focus to the parent container
|
||||||
- `toggle-bar`, `show-bar`, `hide-bar` -- control the status bar
|
- `toggle-bar`, `show-bar`, `hide-bar` -- control the status bar
|
||||||
- `open-control-center` -- open the Jay control center GUI
|
|
||||||
- `warp-mouse-to-focus` -- warp the cursor to the center of the focused window
|
- `warp-mouse-to-focus` -- warp the cursor to the center of the focused window
|
||||||
- `kill-client` -- forcefully disconnect a client (in a window rule, kills the
|
- `kill-client` -- forcefully disconnect a client (in a window rule, kills the
|
||||||
window's client; in a client rule, kills the matched client; has no effect
|
window's client; in a client rule, kills the matched client; has no effect
|
||||||
|
|
|
||||||
|
|
@ -1,608 +0,0 @@
|
||||||
# Control Center
|
|
||||||
|
|
||||||
The control center is Jay's built-in graphical interface for inspecting and
|
|
||||||
modifying compositor settings. It provides a convenient alternative to editing
|
|
||||||
configuration files or running CLI commands -- most settings that can be changed
|
|
||||||
in `config.toml` or via the CLI can also be changed here.
|
|
||||||
|
|
||||||
> [!NOTE]
|
|
||||||
> Changes made in the control center are not persisted across compositor
|
|
||||||
> restarts. To make settings permanent, add them to your `config.toml`.
|
|
||||||
|
|
||||||
> [!TIP]
|
|
||||||
> The control center consumes GPU and CPU resources while open. Close it when
|
|
||||||
> not in use to avoid reducing compositor performance.
|
|
||||||
|
|
||||||
## Opening the Control Center
|
|
||||||
|
|
||||||
- Press `alt-c` (the default shortcut for the `open-control-center` action).
|
|
||||||
- Run the CLI command:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
~$ jay control-center
|
|
||||||
```
|
|
||||||
|
|
||||||
## Interface Overview
|
|
||||||
|
|
||||||
The control center window has a sidebar on the left listing all available panes
|
|
||||||
and a central panel area on the right.
|
|
||||||
|
|
||||||
- **Click** a pane name in the sidebar to open it.
|
|
||||||
- **Multiple panes** can be open at the same time -- they appear as tabs in the
|
|
||||||
panel area.
|
|
||||||
- **Drag** pane tabs to rearrange them or to split the panel area into
|
|
||||||
side-by-side or stacked layouts.
|
|
||||||
- **Close** a pane by clicking its X button or middle-clicking its tab.
|
|
||||||
|
|
||||||
## Panes
|
|
||||||
|
|
||||||
### Compositor
|
|
||||||
|
|
||||||
General information and top-level controls for the running compositor.
|
|
||||||
|
|
||||||
Repository
|
|
||||||
: Link to the Jay GitHub repository
|
|
||||||
|
|
||||||
Version
|
|
||||||
: The running Jay version
|
|
||||||
|
|
||||||
PID
|
|
||||||
: The compositor process ID
|
|
||||||
|
|
||||||
WAYLAND_DISPLAY
|
|
||||||
: The Wayland socket name (shown when available)
|
|
||||||
|
|
||||||
Config DIR
|
|
||||||
: Path to the active configuration directory (shown when available)
|
|
||||||
|
|
||||||
Libei Socket
|
|
||||||
: Toggle the libei input emulation socket
|
|
||||||
|
|
||||||
LIBEI_SOCKET
|
|
||||||
: The socket name (shown when the Libei Socket toggle is enabled)
|
|
||||||
|
|
||||||
Workspace Display Order
|
|
||||||
: Dropdown to select how workspaces are ordered in the bar
|
|
||||||
|
|
||||||
Log Level
|
|
||||||
: Dropdown to change the active log level at runtime (shown when the logger is available)
|
|
||||||
|
|
||||||
Log File
|
|
||||||
: Click to copy the log file path to the clipboard (shown when the logger is available)
|
|
||||||
|
|
||||||
Buttons at the bottom:
|
|
||||||
|
|
||||||
- **Quit** -- stop the compositor.
|
|
||||||
- **Reload Config** -- reload the configuration file.
|
|
||||||
- **Switch to VT** -- switch to another virtual terminal (with a numeric input
|
|
||||||
to select which one).
|
|
||||||
|
|
||||||
### Outputs
|
|
||||||
|
|
||||||
The Outputs pane is the largest and most interactive pane. It has two sub-views:
|
|
||||||
a visual **arrangement editor** and per-connector **settings**.
|
|
||||||
|
|
||||||
#### Arrangement editor
|
|
||||||
|
|
||||||
A 2D preview of your monitor layout. Monitors are drawn as labeled rectangles
|
|
||||||
at their configured positions and sizes.
|
|
||||||
|
|
||||||
- **Click** a monitor to select it (highlighted with a shadow).
|
|
||||||
- **Drag** a selected monitor to reposition it.
|
|
||||||
- **Scroll** to zoom in and out.
|
|
||||||
- **Middle-click drag** or **right-click drag** to pan the viewport.
|
|
||||||
- **Arrow keys** nudge the selected monitor by 1 pixel.
|
|
||||||
- **Snap to neighbor** -- when enabled, dragged monitors snap to the edges of
|
|
||||||
neighboring monitors within a 10-pixel threshold. Hold **Shift** to
|
|
||||||
temporarily invert the snapping behavior.
|
|
||||||
- **Guide lines** -- optional horizontal and vertical lines at the edges of all
|
|
||||||
monitors, helping you align them precisely.
|
|
||||||
|
|
||||||
A **Zoom To Fit** checkbox in the top bar auto-scales the view to fit all
|
|
||||||
monitors. It is disabled when you manually pan or zoom.
|
|
||||||
|
|
||||||
Arrangement settings (accessible via the Settings button):
|
|
||||||
|
|
||||||
Show guide lines
|
|
||||||
: Draw alignment guide lines
|
|
||||||
|
|
||||||
Snap to neighbor
|
|
||||||
: Snap edges when dragging (hold Shift to invert)
|
|
||||||
|
|
||||||
Show arrangement area
|
|
||||||
: Toggle the visual arrangement sub-pane
|
|
||||||
|
|
||||||
Layout
|
|
||||||
: How the arrangement and settings are split: Auto, Vertical, or Horizontal
|
|
||||||
|
|
||||||
Show disconnected heads
|
|
||||||
: Include outputs that are no longer connected
|
|
||||||
|
|
||||||
Show disabled heads
|
|
||||||
: Include outputs that are disabled
|
|
||||||
|
|
||||||
#### Staged changes
|
|
||||||
|
|
||||||
Changes made in the Outputs pane are **staged** -- they are not applied
|
|
||||||
immediately. Three buttons in the top bar control the workflow:
|
|
||||||
|
|
||||||
- **Test** -- validates the staged changes against the display backend without
|
|
||||||
applying them. Errors are shown in the pane.
|
|
||||||
- **Commit** -- applies all staged changes. The pane title shows `Outputs (*)`
|
|
||||||
when there are uncommitted changes.
|
|
||||||
- **Reset** -- discards all staged changes and reverts to the live state.
|
|
||||||
This is displayed as a checkbox; checking it resets the staged changes.
|
|
||||||
|
|
||||||
When a staged value differs from the live value, the current (live) value is
|
|
||||||
shown alongside with a `^ current` annotation.
|
|
||||||
|
|
||||||
#### Per-connector settings
|
|
||||||
|
|
||||||
Each connected display appears as a collapsible section with the connector name,
|
|
||||||
manufacturer, and model. Inside:
|
|
||||||
|
|
||||||
Serial Number
|
|
||||||
: Read-only identifier
|
|
||||||
|
|
||||||
Enabled
|
|
||||||
: Toggle the connector on or off
|
|
||||||
|
|
||||||
Position
|
|
||||||
: X and Y coordinates in compositor space
|
|
||||||
|
|
||||||
Scale
|
|
||||||
: Fractional scaling factor, with +/- buttons for fine adjustment
|
|
||||||
|
|
||||||
Mode
|
|
||||||
: Resolution and refresh rate (dropdown when multiple modes are available)
|
|
||||||
|
|
||||||
Physical Size (mm)
|
|
||||||
: Read-only physical dimensions in millimeters
|
|
||||||
|
|
||||||
Size
|
|
||||||
: Read-only computed pixel dimensions of the output
|
|
||||||
|
|
||||||
Transform
|
|
||||||
: Rotation and mirroring (none, rotate-90, rotate-180, rotate-270, flip, and flipped rotations)
|
|
||||||
|
|
||||||
Custom Brightness
|
|
||||||
: Toggle whether to use a custom SDR content brightness
|
|
||||||
|
|
||||||
Brightness
|
|
||||||
: Brightness value in cd/m^2 (shown when Custom Brightness is enabled)
|
|
||||||
|
|
||||||
Colorimetry
|
|
||||||
: Color space (depends on monitor capabilities)
|
|
||||||
|
|
||||||
EOTF
|
|
||||||
: Transfer function (depends on monitor capabilities)
|
|
||||||
|
|
||||||
Format
|
|
||||||
: Framebuffer pixel format
|
|
||||||
|
|
||||||
Tearing
|
|
||||||
: Tearing mode. When set to a "Fullscreen" mode, a **Limit Windows** checkbox appears; inside that, a **Requests Tearing** checkbox filters by whether the window has requested tearing.
|
|
||||||
|
|
||||||
VRR Active
|
|
||||||
: Read-only indicator of whether VRR is currently active (only shown when the monitor supports VRR)
|
|
||||||
|
|
||||||
VRR
|
|
||||||
: Variable refresh rate mode (only shown when the monitor supports VRR). When set to a "Fullscreen" mode, a **Limit Windows** checkbox appears; inside that, a **Limit Content Types** checkbox enables filtering by content type (**Photos**, **Videos**, **Games** checkboxes).
|
|
||||||
|
|
||||||
Non-desktop
|
|
||||||
: Read-only indicator (Yes/No) of whether the connector is inherently non-desktop
|
|
||||||
|
|
||||||
Override
|
|
||||||
: Force the connector to be treated as desktop or non-desktop
|
|
||||||
|
|
||||||
Blend Space
|
|
||||||
: How colors are blended during compositing (sRGB or linear)
|
|
||||||
|
|
||||||
Use Native Gamut
|
|
||||||
: Use the display's advertised color primaries instead of assuming sRGB
|
|
||||||
|
|
||||||
Native Gamut
|
|
||||||
: Read-only CIE xy primaries for red, green, blue, and white point
|
|
||||||
|
|
||||||
Limit Cursor HZ
|
|
||||||
: Toggle to limit cursor-triggered refresh rate when VRR is active
|
|
||||||
|
|
||||||
Cursor HZ
|
|
||||||
: Cursor refresh rate value (shown when Limit Cursor HZ is enabled)
|
|
||||||
|
|
||||||
Flip Margin (ms)
|
|
||||||
: Read-only page-flip margin for this connector
|
|
||||||
|
|
||||||
### Virtual Outputs
|
|
||||||
|
|
||||||
Manage headless virtual outputs. These are useful for screen sharing, testing,
|
|
||||||
or running applications on a display without a physical monitor.
|
|
||||||
|
|
||||||
- View the list of existing virtual outputs.
|
|
||||||
- **Add** a new virtual output by entering a name and clicking Add.
|
|
||||||
- **Remove** an existing virtual output by clicking its X button.
|
|
||||||
|
|
||||||
### GPUs
|
|
||||||
|
|
||||||
Inspect and configure graphics cards (DRM devices). Each GPU appears as a
|
|
||||||
collapsible section showing its device path and model name.
|
|
||||||
|
|
||||||
Vendor
|
|
||||||
: Read-only GPU vendor name
|
|
||||||
|
|
||||||
Model
|
|
||||||
: Read-only GPU model name
|
|
||||||
|
|
||||||
Devnode
|
|
||||||
: Read-only device path
|
|
||||||
|
|
||||||
Syspath
|
|
||||||
: Read-only sysfs path
|
|
||||||
|
|
||||||
PCI ID
|
|
||||||
: Read-only vendor:model in hex
|
|
||||||
|
|
||||||
Dev
|
|
||||||
: Read-only major:minor device numbers
|
|
||||||
|
|
||||||
API
|
|
||||||
: Dropdown to select the graphics API -- Vulkan (recommended) or the legacy OpenGL renderer
|
|
||||||
|
|
||||||
Primary Device
|
|
||||||
: Checkbox to make this GPU the render device
|
|
||||||
|
|
||||||
Direct Scanout
|
|
||||||
: Toggle direct scanout (bypasses composition for lower latency)
|
|
||||||
|
|
||||||
Flip Margin
|
|
||||||
: Adjust the page-flip margin in milliseconds, with +/- buttons for 0.1 ms steps
|
|
||||||
|
|
||||||
Connectors
|
|
||||||
: List of display connectors attached to this GPU
|
|
||||||
|
|
||||||
### Input
|
|
||||||
|
|
||||||
The Input pane is divided into per-seat and per-device sections.
|
|
||||||
|
|
||||||
#### Per-seat settings
|
|
||||||
|
|
||||||
Each seat (typically just `default`) appears as a collapsible section:
|
|
||||||
|
|
||||||
Repeat Rate
|
|
||||||
: Key repeat speed, with +/- 20 buttons
|
|
||||||
|
|
||||||
Repeat Delay
|
|
||||||
: Initial delay before key repeat begins, with +/- 20 buttons
|
|
||||||
|
|
||||||
Cursor Size
|
|
||||||
: Size of the seat cursor in pixels
|
|
||||||
|
|
||||||
Simple IM
|
|
||||||
: Toggle the built-in XCompose-based input method
|
|
||||||
|
|
||||||
Hardware Cursor
|
|
||||||
: Toggle hardware cursor rendering
|
|
||||||
|
|
||||||
Pointer Revert Key
|
|
||||||
: Text field for the keysym name of the cancel key
|
|
||||||
|
|
||||||
Focus Follows Mouse
|
|
||||||
: Toggle whether moving the pointer over a window gives it focus
|
|
||||||
|
|
||||||
Fallback Output Mode
|
|
||||||
: Dropdown to choose between cursor-based and focus-based output selection
|
|
||||||
|
|
||||||
Below the settings grid:
|
|
||||||
|
|
||||||
- **Focus History** -- checkboxes for "Only Visible" and "Same Workspace".
|
|
||||||
- **Reload Simple IM** -- button to reload XCompose files without restarting.
|
|
||||||
|
|
||||||
##### Keymap management
|
|
||||||
|
|
||||||
Each seat has a full keymap management section:
|
|
||||||
|
|
||||||
- **Copy Keymap** -- copies the current keymap text to the clipboard.
|
|
||||||
- **Load Default Keymap** -- restores the compositor's default keymap.
|
|
||||||
- **Backup / Restore Keymap** -- save and restore a keymap backup.
|
|
||||||
- **Load Keymap from Clipboard** -- paste a keymap from the clipboard.
|
|
||||||
- **Create Keymap from Names** -- build a keymap from RMLVO (Rules, Model,
|
|
||||||
Layout, Variant, Options) fields. Rules and Model have a text input and a
|
|
||||||
"Default" checkbox; Layouts, Variants, and Options have text inputs only.
|
|
||||||
Click **Load** to apply.
|
|
||||||
|
|
||||||
#### Per-device settings
|
|
||||||
|
|
||||||
Each input device appears as a collapsible section. The available settings
|
|
||||||
depend on the device's capabilities:
|
|
||||||
|
|
||||||
Seat
|
|
||||||
: Dropdown to assign the device to a seat, with a Detach button. Shown for all devices.
|
|
||||||
|
|
||||||
Syspath / Devnode
|
|
||||||
: Read-only device paths. Shown for all devices.
|
|
||||||
|
|
||||||
Capabilities
|
|
||||||
: Read-only list (e.g. Keyboard, Pointer, Touch). Shown for all devices.
|
|
||||||
|
|
||||||
Natural Scrolling
|
|
||||||
: Toggle scroll direction. Shown for devices that support it.
|
|
||||||
|
|
||||||
Scroll Distance (px)
|
|
||||||
: Pixels per legacy scroll event. Shown for pointer devices.
|
|
||||||
|
|
||||||
Accel Profile
|
|
||||||
: Dropdown: Flat or Adaptive. Shown for devices with acceleration.
|
|
||||||
|
|
||||||
Accel Speed
|
|
||||||
: Numeric input (-1.0 to 1.0). Shown for devices with acceleration.
|
|
||||||
|
|
||||||
Click Method
|
|
||||||
: Dropdown: none, button-areas, clickfinger. Shown for devices that support it.
|
|
||||||
|
|
||||||
Tap Enabled
|
|
||||||
: Toggle tap-to-click. Shown for touchpads.
|
|
||||||
|
|
||||||
Tap Drag Enabled
|
|
||||||
: Toggle tap-and-drag. Shown for touchpads.
|
|
||||||
|
|
||||||
Tap Drag Lock Enabled
|
|
||||||
: Toggle tap-drag lock. Shown for touchpads.
|
|
||||||
|
|
||||||
Left Handed
|
|
||||||
: Swap primary and secondary buttons. Shown for devices that support it.
|
|
||||||
|
|
||||||
Middle Button Emulation
|
|
||||||
: Simultaneous left+right produces middle click. Shown for devices that support it.
|
|
||||||
|
|
||||||
Output
|
|
||||||
: Dropdown to map the device to a specific output (only has effect for touch and tablet devices), with a Detach button. Shown for all devices.
|
|
||||||
|
|
||||||
Transform Matrix
|
|
||||||
: 2x2 matrix applied to relative motion. Shown for pointer devices.
|
|
||||||
|
|
||||||
Calibration Matrix
|
|
||||||
: 2x3 matrix for absolute input calibration. Shown for devices that support it.
|
|
||||||
|
|
||||||
Device Keymap
|
|
||||||
: Override the seat keymap for this device, with full keymap management UI and a "Use Seat Keymap" button to revert. Shown for keyboards.
|
|
||||||
|
|
||||||
### Idle
|
|
||||||
|
|
||||||
Configure the screensaver and idle behavior:
|
|
||||||
|
|
||||||
Interval
|
|
||||||
: Minutes and seconds of inactivity before the on-idle action fires
|
|
||||||
|
|
||||||
Grace period
|
|
||||||
: Minutes and seconds of the warning phase (screen goes black but is not yet locked)
|
|
||||||
|
|
||||||
Inhibitors
|
|
||||||
: Collapsible list showing which applications are currently preventing idle (e.g. video players), with a count in the header
|
|
||||||
|
|
||||||
### Look and Feel
|
|
||||||
|
|
||||||
Visual customization with live preview. Changes take effect immediately.
|
|
||||||
|
|
||||||
Show Bar
|
|
||||||
: Toggle the status bar
|
|
||||||
|
|
||||||
Bar Position
|
|
||||||
: Dropdown to select the bar position
|
|
||||||
|
|
||||||
Show Titles
|
|
||||||
: Toggle window title bars
|
|
||||||
|
|
||||||
Primary Selection
|
|
||||||
: Toggle middle-click paste (requires application restart to take effect)
|
|
||||||
|
|
||||||
UI Drag
|
|
||||||
: Toggle whether workspaces and tiles can be dragged
|
|
||||||
|
|
||||||
UI Drag Threshold (px)
|
|
||||||
: Minimum distance in pixels before a drag begins
|
|
||||||
|
|
||||||
Float Pin Icon
|
|
||||||
: Show the pin icon on floating windows even when not pinned
|
|
||||||
|
|
||||||
Float Above Fullscreen
|
|
||||||
: Show floating windows above fullscreen windows
|
|
||||||
|
|
||||||
Font
|
|
||||||
: Text field for the main compositor font family
|
|
||||||
|
|
||||||
Title Font
|
|
||||||
: Override font for window title bars (empty = use main font)
|
|
||||||
|
|
||||||
Bar Font
|
|
||||||
: Override font for the status bar (empty = use main font)
|
|
||||||
|
|
||||||
Three reset buttons at the bottom: **Reset Sizes**, **Reset Colors**, and
|
|
||||||
**Reset Fonts**.
|
|
||||||
|
|
||||||
#### Sizes
|
|
||||||
|
|
||||||
A collapsible section with numeric inputs for every theme size: border widths,
|
|
||||||
title heights, bar height, gaps, and other spacing values.
|
|
||||||
|
|
||||||
#### Colors
|
|
||||||
|
|
||||||
A collapsible section with **color pickers** for every theme color. Click a
|
|
||||||
color swatch to open a full RGBA color picker with sliders and hex input.
|
|
||||||
This includes colors for backgrounds, borders, text, the status bar, focused
|
|
||||||
and unfocused windows, attention indicators, and more.
|
|
||||||
|
|
||||||
### Clients
|
|
||||||
|
|
||||||
Inspect and manage connected Wayland clients.
|
|
||||||
|
|
||||||
A **Filter** toggle at the top enables the composable filter builder (see
|
|
||||||
[Filtering](#filtering) below). When filtering is off, all clients are shown.
|
|
||||||
|
|
||||||
Each client appears as a collapsible section showing its ID and process name.
|
|
||||||
Expand it to see:
|
|
||||||
|
|
||||||
ID
|
|
||||||
: Client identifier
|
|
||||||
|
|
||||||
PID
|
|
||||||
: Process ID
|
|
||||||
|
|
||||||
UID
|
|
||||||
: User ID
|
|
||||||
|
|
||||||
comm
|
|
||||||
: Process name
|
|
||||||
|
|
||||||
exe
|
|
||||||
: Executable path
|
|
||||||
|
|
||||||
Sandboxed
|
|
||||||
: Whether the client is sandboxed (only shown for sandboxed clients)
|
|
||||||
|
|
||||||
Secure
|
|
||||||
: Whether the client uses the privileged socket (only shown for secure clients)
|
|
||||||
|
|
||||||
Xwayland
|
|
||||||
: Shown only for X11 clients
|
|
||||||
|
|
||||||
Sandbox Engine
|
|
||||||
: Sandbox engine name (shown when sandboxed)
|
|
||||||
|
|
||||||
App ID
|
|
||||||
: Sandbox application ID (shown when sandboxed)
|
|
||||||
|
|
||||||
Instance ID
|
|
||||||
: Sandbox instance ID (shown when sandboxed)
|
|
||||||
|
|
||||||
Tag
|
|
||||||
: The connection tag, if any
|
|
||||||
|
|
||||||
Kill
|
|
||||||
: Button to forcefully disconnect the client
|
|
||||||
|
|
||||||
Capabilities
|
|
||||||
: Collapsible list of effective Wayland capabilities
|
|
||||||
|
|
||||||
Windows
|
|
||||||
: Collapsible list of all windows owned by this client
|
|
||||||
|
|
||||||
Click the **open in new pane** icon on any client to open a dedicated pane for
|
|
||||||
that client, allowing you to keep it visible while browsing other panes.
|
|
||||||
|
|
||||||
### Window Search
|
|
||||||
|
|
||||||
Search and filter windows across the compositor using the composable filter
|
|
||||||
builder (see [Filtering](#filtering) below).
|
|
||||||
|
|
||||||
Each matching window appears as a collapsible section showing its title. Expand
|
|
||||||
it to see:
|
|
||||||
|
|
||||||
ID
|
|
||||||
: Window identifier
|
|
||||||
|
|
||||||
Title
|
|
||||||
: Window title
|
|
||||||
|
|
||||||
Workspace
|
|
||||||
: Which workspace the window is on
|
|
||||||
|
|
||||||
Type
|
|
||||||
: Container, xdg_toplevel, X Window, or Placeholder
|
|
||||||
|
|
||||||
Tag
|
|
||||||
: Toplevel tag (set via window rules); only shown for xdg_toplevel windows
|
|
||||||
|
|
||||||
X11 properties
|
|
||||||
: Class, Instance, and Role (only shown for Xwayland windows)
|
|
||||||
|
|
||||||
App ID
|
|
||||||
: Application identifier
|
|
||||||
|
|
||||||
Floating
|
|
||||||
: Whether the window is floating
|
|
||||||
|
|
||||||
Visible
|
|
||||||
: Whether the window is visible
|
|
||||||
|
|
||||||
Urgent
|
|
||||||
: Whether the window has the urgency flag
|
|
||||||
|
|
||||||
Fullscreen
|
|
||||||
: Whether the window is fullscreen
|
|
||||||
|
|
||||||
Content Type
|
|
||||||
: The content type hint (photo, video, game), if set
|
|
||||||
|
|
||||||
Client
|
|
||||||
: Full client details (same as the Clients pane)
|
|
||||||
|
|
||||||
Click the **open in new pane** icon on any window to open a dedicated pane for
|
|
||||||
that window.
|
|
||||||
|
|
||||||
### Xwayland
|
|
||||||
|
|
||||||
Manage the Xwayland compatibility layer for running X11 applications:
|
|
||||||
|
|
||||||
Enabled
|
|
||||||
: Toggle Xwayland on or off
|
|
||||||
|
|
||||||
Scaling Mode
|
|
||||||
: Dropdown: `default` or `downscaled` (renders at highest integer scale then downscales for sharper text on HiDPI)
|
|
||||||
|
|
||||||
DISPLAY
|
|
||||||
: Read-only X11 display number (only shown when Xwayland is running)
|
|
||||||
|
|
||||||
Running
|
|
||||||
: Whether Xwayland is currently running
|
|
||||||
|
|
||||||
PID
|
|
||||||
: Xwayland process ID (only shown when Xwayland is running)
|
|
||||||
|
|
||||||
Kill
|
|
||||||
: Button to forcefully terminate Xwayland (only shown when Xwayland is running)
|
|
||||||
|
|
||||||
Client
|
|
||||||
: Collapsible section with full client details for the Xwayland process (only shown when Xwayland is running)
|
|
||||||
|
|
||||||
### Color Management
|
|
||||||
|
|
||||||
Configure the Wayland color management protocol:
|
|
||||||
|
|
||||||
Enabled
|
|
||||||
: Toggle the color management protocol for clients
|
|
||||||
|
|
||||||
Available
|
|
||||||
: Read-only indicator of whether color management is available with the current renderer and hardware
|
|
||||||
|
|
||||||
## Filtering
|
|
||||||
|
|
||||||
The **Clients** and **Window Search** panes share a composable filter system
|
|
||||||
for narrowing down results. The filter builder works as follows:
|
|
||||||
|
|
||||||
At the top level, select a combinator or a leaf criterion from the dropdown:
|
|
||||||
|
|
||||||
- **Not** -- inverts a single child criterion.
|
|
||||||
- **All** -- all child criteria must match (AND).
|
|
||||||
- **Any** -- at least one child criterion must match (OR).
|
|
||||||
- **Exactly(n)** -- exactly *n* child criteria must match (with a numeric input
|
|
||||||
for *n*).
|
|
||||||
|
|
||||||
Compound criteria contain a list of children. Click **Add** to append a new
|
|
||||||
criterion; click the X button on any child to remove it. Criteria can be nested
|
|
||||||
to arbitrary depth.
|
|
||||||
|
|
||||||
Leaf criteria vary by context:
|
|
||||||
|
|
||||||
**Client criteria:** Comm, Exe, Tag, Sandbox Engine, Sandbox App ID, Sandbox
|
|
||||||
Instance ID (all regex-matched text fields with a "Regex" checkbox), Sandboxed,
|
|
||||||
Is Xwayland (boolean), UID, PID (numeric inputs).
|
|
||||||
|
|
||||||
**Window criteria:** Title, App ID, Tag, Workspace, X Class, X Instance, X Role
|
|
||||||
(all regex-matched text fields), Floating, Visible, Urgent, Fullscreen
|
|
||||||
(boolean), Content Types (checkboxes for Photo, Video, Game), and **Client**
|
|
||||||
(a nested client criterion builder for filtering by the owning client's
|
|
||||||
properties).
|
|
||||||
|
|
||||||
Text-matching criteria have a **Regex** checkbox. When unchecked, the input is
|
|
||||||
matched as a literal string. When checked, it is treated as a regular
|
|
||||||
expression. Invalid regex patterns show an error message.
|
|
||||||
|
|
@ -71,7 +71,6 @@ Commands:
|
||||||
color-management Inspect/modify the color-management settings
|
color-management Inspect/modify the color-management settings
|
||||||
clients Inspect/manipulate the connected clients
|
clients Inspect/manipulate the connected clients
|
||||||
tree Inspect the surface tree
|
tree Inspect the surface tree
|
||||||
control-center Opens the control center
|
|
||||||
version Prints the Jay version and exits
|
version Prints the Jay version and exits
|
||||||
pid Prints the Jay PID and exits
|
pid Prints the Jay PID and exits
|
||||||
help Print this message or the help of the given subcommand(s)
|
help Print this message or the help of the given subcommand(s)
|
||||||
|
|
@ -85,12 +84,6 @@ Options:
|
||||||
|
|
||||||
See the full [Command-Line Interface](cli.md) reference for details.
|
See the full [Command-Line Interface](cli.md) reference for details.
|
||||||
|
|
||||||
## Control Center
|
|
||||||
|
|
||||||
Jay includes a built-in GUI control center (opened with `alt-c`) for managing
|
|
||||||
outputs, input devices, GPUs, idle settings, color management, and more --
|
|
||||||
without editing the config file. See [Control Center](control-center.md).
|
|
||||||
|
|
||||||
## Multi-Monitor Support
|
## Multi-Monitor Support
|
||||||
|
|
||||||
Jay can be used with multiple monitors with hot-plug and hot-unplug support.
|
Jay can be used with multiple monitors with hot-plug and hot-unplug support.
|
||||||
|
|
@ -133,7 +126,7 @@ automatically by the default configuration.
|
||||||
## Fractional Scaling
|
## Fractional Scaling
|
||||||
|
|
||||||
Jay supports per-monitor fractional scaling. Scale factors can be set per
|
Jay supports per-monitor fractional scaling. Scale factors can be set per
|
||||||
output in the config file or at runtime via the control center and CLI.
|
output in the config file or at runtime via the CLI.
|
||||||
|
|
||||||
See [Outputs (Monitors)](configuration/outputs.md) for details.
|
See [Outputs (Monitors)](configuration/outputs.md) for details.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,12 +26,8 @@ variable refresh rate (VRR), tearing presentation, HDR, and screen sharing via
|
||||||
xdg-desktop-portal. X11 applications are supported through Xwayland.
|
xdg-desktop-portal. X11 applications are supported through Xwayland.
|
||||||
|
|
||||||
Jay is configured through a declarative TOML file, with an optional advanced
|
Jay is configured through a declarative TOML file, with an optional advanced
|
||||||
mode that uses a shared library for programmatic control. A built-in
|
mode that uses a shared library for programmatic control. A comprehensive
|
||||||
[control center](control-center.md) (opened with `alt-c`) provides a full GUI
|
command-line interface makes scripting and automation straightforward.
|
||||||
for inspecting and changing compositor settings at runtime -- including output
|
|
||||||
arrangement, input devices, color management, GPU selection, and more. A
|
|
||||||
comprehensive command-line interface makes scripting and automation
|
|
||||||
straightforward.
|
|
||||||
|
|
||||||
See the [Features](features.md) chapter for a comprehensive overview of what
|
See the [Features](features.md) chapter for a comprehensive overview of what
|
||||||
Jay can do, or jump straight to [Installation](installation.md) to get started.
|
Jay can do, or jump straight to [Installation](installation.md) to get started.
|
||||||
|
|
|
||||||
|
|
@ -44,24 +44,6 @@ Then log out and select **Jay** from the session list.
|
||||||
> ~$ sudo ln -s ~/.cargo/bin/jay /usr/local/bin/jay
|
> ~$ sudo ln -s ~/.cargo/bin/jay /usr/local/bin/jay
|
||||||
> ```
|
> ```
|
||||||
|
|
||||||
## The Control Center
|
|
||||||
|
|
||||||
Once Jay is running, press `alt-c` to open the
|
|
||||||
[control center](control-center.md) -- a built-in GUI that lets you inspect and
|
|
||||||
modify most compositor settings without editing config files or running CLI
|
|
||||||
commands. From the control center you can:
|
|
||||||
|
|
||||||
- Rearrange monitors with a visual drag-and-drop editor.
|
|
||||||
- Configure input devices -- acceleration, tap behavior, keymaps, and more.
|
|
||||||
- Switch GPUs and graphics APIs.
|
|
||||||
- Adjust theme colors, fonts, borders, and gaps with live color pickers.
|
|
||||||
- Manage idle timeouts and screen locking.
|
|
||||||
- Search and filter windows and clients.
|
|
||||||
- Toggle Xwayland and color management.
|
|
||||||
|
|
||||||
You can also open it from the command line with `jay control-center`. See the
|
|
||||||
[Control Center](control-center.md) chapter for a full tour of every pane.
|
|
||||||
|
|
||||||
## Default Keybindings
|
## Default Keybindings
|
||||||
|
|
||||||
Jay ships with a built-in default configuration. The most important default
|
Jay ships with a built-in default configuration. The most important default
|
||||||
|
|
@ -99,9 +81,6 @@ keybindings are listed below.
|
||||||
`alt-shift-f`
|
`alt-shift-f`
|
||||||
: Toggle floating
|
: Toggle floating
|
||||||
|
|
||||||
`alt-c`
|
|
||||||
: Open the control center
|
|
||||||
|
|
||||||
`alt-shift-c`
|
`alt-shift-c`
|
||||||
: Close focused window
|
: Close focused window
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,12 +26,6 @@ pub const TREES: &[Tree] = &[
|
||||||
"legacy/tex.frag",
|
"legacy/tex.frag",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
Tree {
|
|
||||||
root: "src/egui_adapter/shaders",
|
|
||||||
hash: "src/egui_adapter/shaders_hash.txt",
|
|
||||||
bin: "src/egui_adapter/shaders_bin",
|
|
||||||
shaders: &["shader.vert", "shader.frag"],
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
fn calculate_hash(tree: &Tree) -> anyhow::Result<String> {
|
fn calculate_hash(tree: &Tree) -> anyhow::Result<String> {
|
||||||
|
|
|
||||||
|
|
@ -1067,21 +1067,10 @@ impl ConfigClient {
|
||||||
position
|
position
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_egui_fonts(&self, proportional: Option<Vec<&str>>, monospace: Option<Vec<&str>>) {
|
|
||||||
self.send(&ClientMessage::SetEguiFonts {
|
|
||||||
proportional,
|
|
||||||
monospace,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_middle_click_paste_enabled(&self, enabled: bool) {
|
pub fn set_middle_click_paste_enabled(&self, enabled: bool) {
|
||||||
self.send(&ClientMessage::SetMiddleClickPasteEnabled { enabled });
|
self.send(&ClientMessage::SetMiddleClickPasteEnabled { enabled });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_control_center(&self) {
|
|
||||||
self.send(&ClientMessage::OpenControlCenter);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_workspace_display_order(&self, order: WorkspaceDisplayOrder) {
|
pub fn set_workspace_display_order(&self, order: WorkspaceDisplayOrder) {
|
||||||
self.send(&ClientMessage::SetWorkspaceDisplayOrder { order });
|
self.send(&ClientMessage::SetWorkspaceDisplayOrder { order });
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -847,11 +847,6 @@ pub enum ClientMessage<'a> {
|
||||||
fds: Vec<(i32, i32)>,
|
fds: Vec<(i32, i32)>,
|
||||||
tag: Option<&'a str>,
|
tag: Option<&'a str>,
|
||||||
},
|
},
|
||||||
SetEguiFonts {
|
|
||||||
proportional: Option<Vec<&'a str>>,
|
|
||||||
monospace: Option<Vec<&'a str>>,
|
|
||||||
},
|
|
||||||
OpenControlCenter,
|
|
||||||
ConnectorSupportsArbitraryModes {
|
ConnectorSupportsArbitraryModes {
|
||||||
connector: Connector,
|
connector: Connector,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -381,7 +381,3 @@ pub fn set_middle_click_paste_enabled(enabled: bool) {
|
||||||
get!().set_middle_click_paste_enabled(enabled);
|
get!().set_middle_click_paste_enabled(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Opens the control center.
|
|
||||||
pub fn open_control_center() {
|
|
||||||
get!().open_control_center();
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -197,20 +197,6 @@ pub fn get_bar_position() -> BarPosition {
|
||||||
get!(BarPosition::Top).get_bar_position()
|
get!(BarPosition::Top).get_bar_position()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the proportional fonts used by egui windows.
|
|
||||||
///
|
|
||||||
/// The default is `["sans-serif", "Noto Sans", "Noto Color Emoji"]`.
|
|
||||||
pub fn set_egui_proportional_fonts<'a>(fonts: impl IntoIterator<Item = &'a str>) {
|
|
||||||
get!().set_egui_fonts(Some(fonts.into_iter().collect()), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the monospace fonts used by egui windows.
|
|
||||||
///
|
|
||||||
/// The default is `["monospace", "Noto Sans Mono", "Noto Color Emoji"]`.
|
|
||||||
pub fn set_egui_monospace_fonts<'a>(fonts: impl IntoIterator<Item = &'a str>) {
|
|
||||||
get!().set_egui_fonts(None, Some(fonts.into_iter().collect()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Elements of the compositor whose color can be changed.
|
/// Elements of the compositor whose color can be changed.
|
||||||
pub mod colors {
|
pub mod colors {
|
||||||
use {
|
use {
|
||||||
|
|
|
||||||
|
|
@ -596,9 +596,6 @@ pub trait BackendDrmDevice {
|
||||||
fn set_flip_margin(&self, margin: u64) {
|
fn set_flip_margin(&self, margin: u64) {
|
||||||
let _ = margin;
|
let _ = margin;
|
||||||
}
|
}
|
||||||
fn flip_margin(&self) -> Option<u64> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait BackendDrmLease {
|
pub trait BackendDrmLease {
|
||||||
|
|
|
||||||
|
|
@ -318,9 +318,6 @@ impl BackendDrmDevice for MetalDrmDevice {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flip_margin(&self) -> Option<u64> {
|
|
||||||
Some(self.min_post_commit_margin.get())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct HandleEvents {
|
pub struct HandleEvents {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ mod clients;
|
||||||
mod color;
|
mod color;
|
||||||
mod color_management;
|
mod color_management;
|
||||||
mod config;
|
mod config;
|
||||||
mod control_center;
|
|
||||||
mod damage_tracking;
|
mod damage_tracking;
|
||||||
mod duration;
|
mod duration;
|
||||||
mod generate;
|
mod generate;
|
||||||
|
|
@ -112,8 +111,6 @@ pub enum Cmd {
|
||||||
Clients(ClientsArgs),
|
Clients(ClientsArgs),
|
||||||
/// Inspect the surface tree.
|
/// Inspect the surface tree.
|
||||||
Tree(TreeArgs),
|
Tree(TreeArgs),
|
||||||
/// Opens the control center.
|
|
||||||
ControlCenter,
|
|
||||||
/// Prints the Jay version and exits.
|
/// Prints the Jay version and exits.
|
||||||
Version,
|
Version,
|
||||||
/// Prints the Jay PID and exits.
|
/// Prints the Jay PID and exits.
|
||||||
|
|
@ -270,7 +267,6 @@ pub fn main() {
|
||||||
#[cfg(feature = "it")]
|
#[cfg(feature = "it")]
|
||||||
Cmd::RunTests => crate::it::run_tests(),
|
Cmd::RunTests => crate::it::run_tests(),
|
||||||
Cmd::Reexec(a) => reexec::main(cli.global, a),
|
Cmd::Reexec(a) => reexec::main(cli.global, a),
|
||||||
Cmd::ControlCenter => control_center::main(cli.global),
|
|
||||||
Cmd::Config(a) => config::main(cli.global, a),
|
Cmd::Config(a) => config::main(cli.global, a),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
use {
|
|
||||||
crate::{
|
|
||||||
cli::GlobalArgs,
|
|
||||||
tools::tool_client::{Handle, ToolClient, with_tool_client},
|
|
||||||
wire::{jay_compositor, jay_open_control_center_request},
|
|
||||||
},
|
|
||||||
std::rc::Rc,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn main(global: GlobalArgs) {
|
|
||||||
with_tool_client(global.log_level, |tc| async move {
|
|
||||||
let cc = ControlCenter { tc: tc.clone() };
|
|
||||||
cc.run().await;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ControlCenter {
|
|
||||||
tc: Rc<ToolClient>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ControlCenter {
|
|
||||||
async fn run(self) {
|
|
||||||
let tc = &self.tc;
|
|
||||||
let comp = tc.jay_compositor().await;
|
|
||||||
let id = tc.id();
|
|
||||||
tc.send(jay_compositor::OpenControlCenter { self_id: comp, id });
|
|
||||||
jay_open_control_center_request::Failed::handle(&tc, id, (), |_, ev| {
|
|
||||||
fatal!("Could not open the control center: {}", ev.msg);
|
|
||||||
});
|
|
||||||
tc.round_trip().await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -14,7 +14,6 @@ use {
|
||||||
clientmem::{self, ClientMemError},
|
clientmem::{self, ClientMemError},
|
||||||
cmm::{cmm_manager::ColorManager, cmm_primaries::Primaries},
|
cmm::{cmm_manager::ColorManager, cmm_primaries::Primaries},
|
||||||
config::ConfigProxy,
|
config::ConfigProxy,
|
||||||
control_center::redraw_control_centers,
|
|
||||||
copy_device::CopyDeviceRegistry,
|
copy_device::CopyDeviceRegistry,
|
||||||
cpu_worker::{CpuWorker, CpuWorkerError},
|
cpu_worker::{CpuWorker, CpuWorkerError},
|
||||||
criteria::{
|
criteria::{
|
||||||
|
|
@ -395,8 +394,6 @@ fn start_compositor2(
|
||||||
eventfd_cache,
|
eventfd_cache,
|
||||||
lazy_event_sources: Default::default(),
|
lazy_event_sources: Default::default(),
|
||||||
bo_drop_queue: Rc::new(ObjectDropQueue::new(&ring)),
|
bo_drop_queue: Rc::new(ObjectDropQueue::new(&ring)),
|
||||||
egg_state: Default::default(),
|
|
||||||
control_centers: Default::default(),
|
|
||||||
virtual_outputs: Default::default(),
|
virtual_outputs: Default::default(),
|
||||||
clean_logs_older_than: Default::default(),
|
clean_logs_older_than: Default::default(),
|
||||||
});
|
});
|
||||||
|
|
@ -605,10 +602,6 @@ fn start_global_event_handlers(state: &Rc<State>) -> Vec<SpawnedFuture<()>> {
|
||||||
"lazy event sources",
|
"lazy event sources",
|
||||||
handle_lazy_event_sources(state.clone()),
|
handle_lazy_event_sources(state.clone()),
|
||||||
),
|
),
|
||||||
eng.spawn(
|
|
||||||
"redraw control centers",
|
|
||||||
redraw_control_centers(state.clone()),
|
|
||||||
),
|
|
||||||
eng.spawn(
|
eng.spawn(
|
||||||
"warp mouse to focus",
|
"warp mouse to focus",
|
||||||
handle_warp_mouse_to_focus(state.clone()),
|
handle_warp_mouse_to_focus(state.clone()),
|
||||||
|
|
|
||||||
|
|
@ -1841,16 +1841,6 @@ impl ConfigProxyHandler {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_set_egui_fonts(&self, proportional: Option<Vec<&str>>, monospace: Option<Vec<&str>>) {
|
|
||||||
self.state.set_egui_fonts(proportional, monospace);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_open_control_center(&self) {
|
|
||||||
if let Err(e) = self.state.open_control_center() {
|
|
||||||
log::error!("Could not open control center: {}", ErrorFmt(e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_set_log_level(&self, level: ConfigLogLevel) {
|
fn handle_set_log_level(&self, level: ConfigLogLevel) {
|
||||||
self.state.set_log_level(level.into());
|
self.state.set_log_level(level.into());
|
||||||
}
|
}
|
||||||
|
|
@ -3410,11 +3400,6 @@ impl ConfigProxyHandler {
|
||||||
fds,
|
fds,
|
||||||
tag,
|
tag,
|
||||||
} => self.handle_run(prog, args, env, fds, tag).wrn("run")?,
|
} => self.handle_run(prog, args, env, fds, tag).wrn("run")?,
|
||||||
ClientMessage::SetEguiFonts {
|
|
||||||
proportional,
|
|
||||||
monospace,
|
|
||||||
} => self.handle_set_egui_fonts(proportional, monospace),
|
|
||||||
ClientMessage::OpenControlCenter => self.handle_open_control_center(),
|
|
||||||
ClientMessage::ConnectorSupportsArbitraryModes { connector } => self
|
ClientMessage::ConnectorSupportsArbitraryModes { connector } => self
|
||||||
.handle_connector_supports_arbitrary_modes(connector)
|
.handle_connector_supports_arbitrary_modes(connector)
|
||||||
.wrn("connector_supports_arbitrary_modes")?,
|
.wrn("connector_supports_arbitrary_modes")?,
|
||||||
|
|
|
||||||
|
|
@ -1,687 +0,0 @@
|
||||||
use {
|
|
||||||
crate::{
|
|
||||||
control_center::{
|
|
||||||
cc_clients::{ClientPane, ClientsPane},
|
|
||||||
cc_color_management::ColorManagementPane,
|
|
||||||
cc_compositor::CompositorPane,
|
|
||||||
cc_gpus::GpusPane,
|
|
||||||
cc_idle::IdlePane,
|
|
||||||
cc_input::InputPane,
|
|
||||||
cc_look_and_feel::LookAndFeelPane,
|
|
||||||
cc_outputs::OutputsPane,
|
|
||||||
cc_virtual_outputs::VirtualOutputsPane,
|
|
||||||
cc_window::{WindowPane, WindowSearchPane},
|
|
||||||
cc_xwayland::XwaylandPane,
|
|
||||||
},
|
|
||||||
egui_adapter::egui_platform::{
|
|
||||||
EggError, EggWindow, EggWindowOwner,
|
|
||||||
icons::{ICON_CLOSE, ICON_DRAG_INDICATOR, ICON_INFO},
|
|
||||||
},
|
|
||||||
macros::Bitflag,
|
|
||||||
state::State,
|
|
||||||
utils::{
|
|
||||||
asyncevent::AsyncEvent, copyhashmap::CopyHashMap,
|
|
||||||
event_listener::LazyEventSourceListener, numcell::NumCell, static_text::StaticText,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
egui::{
|
|
||||||
Align, CentralPanel, Checkbox, Color32, ComboBox, CursorIcon, DragValue, Frame, Grid, Id,
|
|
||||||
InnerResponse, Label, Layout, Panel, Response, Rgba, RichText, ScrollArea, Sense, Stroke,
|
|
||||||
TextBuffer, TextEdit, Ui, UiBuilder, Visuals, Widget, WidgetText, emath::Numeric, vec2,
|
|
||||||
},
|
|
||||||
egui_tiles::{ResizeState, TabState, Tile, TileId, Tiles, Tree},
|
|
||||||
linearize::{Linearize, LinearizeExt},
|
|
||||||
std::{
|
|
||||||
cell::RefCell,
|
|
||||||
hash::Hash,
|
|
||||||
mem,
|
|
||||||
ops::{Deref, DerefMut, RangeInclusive},
|
|
||||||
rc::Rc,
|
|
||||||
},
|
|
||||||
thiserror::Error,
|
|
||||||
};
|
|
||||||
|
|
||||||
mod cc_clients;
|
|
||||||
mod cc_color_management;
|
|
||||||
mod cc_compositor;
|
|
||||||
mod cc_criterion;
|
|
||||||
mod cc_gpus;
|
|
||||||
mod cc_idle;
|
|
||||||
mod cc_input;
|
|
||||||
mod cc_look_and_feel;
|
|
||||||
mod cc_outputs;
|
|
||||||
mod cc_sidebar;
|
|
||||||
mod cc_virtual_outputs;
|
|
||||||
mod cc_window;
|
|
||||||
mod cc_xwayland;
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
pub enum ControlCenterError {
|
|
||||||
#[error("Could not get the egg context")]
|
|
||||||
GetEggContext(#[source] EggError),
|
|
||||||
}
|
|
||||||
|
|
||||||
linear_ids!(ControlCenterIds, ControlCenterId, u64);
|
|
||||||
|
|
||||||
pub async fn redraw_control_centers(state: Rc<State>) {
|
|
||||||
let cc = &state.control_centers;
|
|
||||||
loop {
|
|
||||||
cc.redraw.triggered().await;
|
|
||||||
let interests = cc.change.take();
|
|
||||||
for cc in cc.control_centers.lock().values() {
|
|
||||||
if cc.inner.interests.interests.get().intersects(interests) {
|
|
||||||
cc.inner.window.request_redraw();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct ControlCenters {
|
|
||||||
ids: ControlCenterIds,
|
|
||||||
change: NumCell<ControlCenterInterest>,
|
|
||||||
redraw: AsyncEvent,
|
|
||||||
control_centers: CopyHashMap<ControlCenterId, Rc<ControlCenter>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
bitflags! {
|
|
||||||
ControlCenterInterest: u32;
|
|
||||||
CCI_COMPOSITOR,
|
|
||||||
CCI_IDLE,
|
|
||||||
CCI_COLOR_MANAGEMENT,
|
|
||||||
CCI_XWAYLAND,
|
|
||||||
CCI_OUTPUTS,
|
|
||||||
CCI_GPUS,
|
|
||||||
CCI_INPUT,
|
|
||||||
CCI_LOOK_AND_FEEL,
|
|
||||||
CCI_VIRTUAL_OUTPUTS,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ControlCenter {
|
|
||||||
inner: Rc<ControlCenterInner>,
|
|
||||||
}
|
|
||||||
|
|
||||||
linear_ids!(PaneIds, PaneId, u64);
|
|
||||||
|
|
||||||
struct ControlCenterInner {
|
|
||||||
id: ControlCenterId,
|
|
||||||
state: Rc<State>,
|
|
||||||
tree: RefCell<Settings>,
|
|
||||||
window: Rc<EggWindow>,
|
|
||||||
pane_ids: PaneIds,
|
|
||||||
interests: Rc<Interests>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
struct Interests {
|
|
||||||
interests: NumCell<ControlCenterInterest>,
|
|
||||||
interests_array: [NumCell<u64>; <ControlCenterInterest as Bitflag>::Type::BITS as usize],
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Settings {
|
|
||||||
tree: Tree<Pane>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Pane {
|
|
||||||
id: PaneId,
|
|
||||||
ps: PaneState,
|
|
||||||
own_interests: ControlCenterInterest,
|
|
||||||
cc_interests: Rc<Interests>,
|
|
||||||
ty: PaneType,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct PaneState {
|
|
||||||
errors: Vec<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
enum PaneType {
|
|
||||||
Compositor(CompositorPane),
|
|
||||||
Idle(IdlePane),
|
|
||||||
ColorManagement(ColorManagementPane),
|
|
||||||
Xwayland(XwaylandPane),
|
|
||||||
Outputs(Box<OutputsPane>),
|
|
||||||
GPUs(GpusPane),
|
|
||||||
Input(InputPane),
|
|
||||||
LookAndFeel(LookAndFeelPane),
|
|
||||||
Clients(ClientsPane),
|
|
||||||
Client(ClientPane),
|
|
||||||
WindowSearch(WindowSearchPane),
|
|
||||||
Window(WindowPane),
|
|
||||||
VirtualOutputs(VirtualOutputsPane),
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CcBehavior<'a> {
|
|
||||||
cc: &'a Rc<ControlCenterInner>,
|
|
||||||
close: Option<TileId>,
|
|
||||||
open: Option<PaneType>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ControlCenters {
|
|
||||||
pub fn clear(&self) {
|
|
||||||
self.control_centers.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Pane {
|
|
||||||
fn title(&self, res: &mut String) {
|
|
||||||
match &self.ty {
|
|
||||||
PaneType::Compositor(v) => v.title(res),
|
|
||||||
PaneType::Idle(v) => v.title(res),
|
|
||||||
PaneType::ColorManagement(v) => v.title(res),
|
|
||||||
PaneType::Xwayland(v) => v.title(res),
|
|
||||||
PaneType::Outputs(v) => v.title(res),
|
|
||||||
PaneType::GPUs(v) => v.title(res),
|
|
||||||
PaneType::Input(v) => v.title(res),
|
|
||||||
PaneType::LookAndFeel(v) => v.title(res),
|
|
||||||
PaneType::Clients(v) => v.title(res),
|
|
||||||
PaneType::Client(v) => v.title(res),
|
|
||||||
PaneType::WindowSearch(v) => v.title(res),
|
|
||||||
PaneType::Window(v) => v.title(res),
|
|
||||||
PaneType::VirtualOutputs(v) => v.title(res),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn show(&mut self, behavior: &mut CcBehavior<'_>, ui: &mut Ui) {
|
|
||||||
match &mut self.ty {
|
|
||||||
PaneType::Compositor(p) => p.show(ui),
|
|
||||||
PaneType::Idle(p) => p.show(ui),
|
|
||||||
PaneType::ColorManagement(p) => p.show(ui),
|
|
||||||
PaneType::Xwayland(p) => p.show(behavior, ui),
|
|
||||||
PaneType::Outputs(p) => p.show(&mut self.ps, ui),
|
|
||||||
PaneType::GPUs(p) => p.show(ui),
|
|
||||||
PaneType::Input(p) => p.show(&mut self.ps, ui),
|
|
||||||
PaneType::LookAndFeel(p) => p.show(ui),
|
|
||||||
PaneType::Clients(p) => p.show(behavior, ui),
|
|
||||||
PaneType::Client(p) => p.show(behavior, ui),
|
|
||||||
PaneType::WindowSearch(p) => p.show(behavior, ui),
|
|
||||||
PaneType::Window(p) => p.show(behavior, ui),
|
|
||||||
PaneType::VirtualOutputs(p) => p.show(ui),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PaneType {
|
|
||||||
fn interest(&self) -> ControlCenterInterest {
|
|
||||||
match self {
|
|
||||||
PaneType::Compositor(_) => CCI_COMPOSITOR,
|
|
||||||
PaneType::Idle(_) => CCI_IDLE,
|
|
||||||
PaneType::ColorManagement(_) => CCI_COLOR_MANAGEMENT,
|
|
||||||
PaneType::Xwayland(_) => CCI_XWAYLAND,
|
|
||||||
PaneType::Outputs(_) => CCI_OUTPUTS,
|
|
||||||
PaneType::GPUs(_) => CCI_GPUS,
|
|
||||||
PaneType::Input(_) => CCI_INPUT,
|
|
||||||
PaneType::LookAndFeel(_) => CCI_LOOK_AND_FEEL,
|
|
||||||
PaneType::Clients(_) => ControlCenterInterest::none(),
|
|
||||||
PaneType::Client(_) => ControlCenterInterest::none(),
|
|
||||||
PaneType::WindowSearch(_) => ControlCenterInterest::none(),
|
|
||||||
PaneType::Window(_) => ControlCenterInterest::none(),
|
|
||||||
PaneType::VirtualOutputs(_) => CCI_VIRTUAL_OUTPUTS,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl egui_tiles::Behavior<Pane> for CcBehavior<'_> {
|
|
||||||
fn pane_ui(&mut self, ui: &mut Ui, tile_id: TileId, pane: &mut Pane) -> egui_tiles::UiResponse {
|
|
||||||
let mut drag = false;
|
|
||||||
Frame::central_panel(ui.style()).show(ui, |ui| {
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
drag = ui
|
|
||||||
.add(icon_label(ICON_DRAG_INDICATOR).sense(Sense::drag()))
|
|
||||||
.total_drag_delta()
|
|
||||||
.map(|d| d.length() >= 5.0)
|
|
||||||
.unwrap_or(false);
|
|
||||||
let mut title = String::new();
|
|
||||||
pane.title(&mut title);
|
|
||||||
if ui
|
|
||||||
.add(icon_label(&title).sense(Sense::click()))
|
|
||||||
.middle_clicked()
|
|
||||||
{
|
|
||||||
self.close = Some(tile_id);
|
|
||||||
}
|
|
||||||
if ui
|
|
||||||
.add(icon_label(ICON_CLOSE).sense(Sense::click()))
|
|
||||||
.clicked()
|
|
||||||
{
|
|
||||||
self.close = Some(tile_id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
ui.separator();
|
|
||||||
show_errors(ui, &mut pane.ps);
|
|
||||||
ui.scope_builder(UiBuilder::new().id(Id::new(("pane", pane.id))), |ui| {
|
|
||||||
ScrollArea::vertical().show(ui, |ui| {
|
|
||||||
ui.allocate_space(vec2(ui.available_width(), 0.0));
|
|
||||||
pane.show(self, ui);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
if drag {
|
|
||||||
egui_tiles::UiResponse::DragStarted
|
|
||||||
} else {
|
|
||||||
egui_tiles::UiResponse::None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tab_title_for_pane(&mut self, _pane: &Pane) -> WidgetText {
|
|
||||||
"".into()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tab_hover_cursor_icon(&self) -> CursorIcon {
|
|
||||||
CursorIcon::Default
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tab_title_for_tile(&mut self, tiles: &Tiles<Pane>, tile_id: TileId) -> WidgetText {
|
|
||||||
fn add_title(tiles: &Tiles<Pane>, res: &mut String, first: &mut bool, tile_id: TileId) {
|
|
||||||
if !mem::take(first) {
|
|
||||||
res.push_str("/");
|
|
||||||
}
|
|
||||||
let Some(tile) = tiles.get(tile_id) else {
|
|
||||||
res.push_str("MISSING TILE");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
match tile {
|
|
||||||
Tile::Pane(p) => p.title(res),
|
|
||||||
Tile::Container(c) => {
|
|
||||||
let mut first = true;
|
|
||||||
for &tile_id in c.children() {
|
|
||||||
add_title(tiles, res, &mut first, tile_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let mut res = String::new();
|
|
||||||
let mut first = true;
|
|
||||||
add_title(tiles, &mut res, &mut first, tile_id);
|
|
||||||
res.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_tab_button(
|
|
||||||
&mut self,
|
|
||||||
_tiles: &mut Tiles<Pane>,
|
|
||||||
tile_id: TileId,
|
|
||||||
button_response: Response,
|
|
||||||
) -> Response {
|
|
||||||
if button_response.middle_clicked() {
|
|
||||||
self.close = Some(tile_id);
|
|
||||||
}
|
|
||||||
button_response
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resize_stroke(&self, style: &egui::Style, resize_state: ResizeState) -> Stroke {
|
|
||||||
match resize_state {
|
|
||||||
ResizeState::Idle => style.visuals.widgets.noninteractive.bg_stroke,
|
|
||||||
ResizeState::Hovering => style.visuals.widgets.hovered.fg_stroke,
|
|
||||||
ResizeState::Dragging => style.visuals.widgets.active.fg_stroke,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tab_bar_color(&self, visuals: &Visuals) -> Color32 {
|
|
||||||
(Rgba::from(visuals.panel_fill) * Rgba::from_gray(0.8)).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tab_bg_color(
|
|
||||||
&self,
|
|
||||||
visuals: &Visuals,
|
|
||||||
_tiles: &Tiles<Pane>,
|
|
||||||
_tile_id: TileId,
|
|
||||||
state: &TabState,
|
|
||||||
) -> Color32 {
|
|
||||||
match state.active {
|
|
||||||
true => visuals.panel_fill,
|
|
||||||
false => self.tab_bar_color(visuals),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EggWindowOwner for ControlCenterInner {
|
|
||||||
fn close(&self) {
|
|
||||||
self.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render(self: Rc<Self>, ui: &mut Ui) {
|
|
||||||
let settings = &mut *self.tree.borrow_mut();
|
|
||||||
Panel::left("sidebar").show_inside(ui, |ui| self.show_sidebar(&mut settings.tree, ui));
|
|
||||||
CentralPanel::default()
|
|
||||||
.frame(
|
|
||||||
Frame::central_panel(&ui.global_style())
|
|
||||||
.outer_margin(0.0)
|
|
||||||
.inner_margin(0.0),
|
|
||||||
)
|
|
||||||
.show_inside(ui, |ui| {
|
|
||||||
let tree = &mut settings.tree;
|
|
||||||
let mut behavior = CcBehavior {
|
|
||||||
cc: &self,
|
|
||||||
close: Default::default(),
|
|
||||||
open: Default::default(),
|
|
||||||
};
|
|
||||||
tree.ui(&mut behavior, ui);
|
|
||||||
if let Some(close) = behavior.close {
|
|
||||||
tree.set_visible(close, false);
|
|
||||||
tree.remove_recursively(close);
|
|
||||||
ui.request_repaint();
|
|
||||||
}
|
|
||||||
if let Some(ty) = behavior.open {
|
|
||||||
self.open(tree, ty);
|
|
||||||
ui.request_repaint();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl State {
|
|
||||||
pub fn open_control_center(self: &Rc<Self>) -> Result<Rc<ControlCenter>, ControlCenterError> {
|
|
||||||
let ctx = self
|
|
||||||
.get_egg_context()
|
|
||||||
.map_err(ControlCenterError::GetEggContext)?;
|
|
||||||
let window = ctx.create_window("Control Center");
|
|
||||||
let cc = Rc::new(ControlCenter {
|
|
||||||
inner: Rc::new(ControlCenterInner {
|
|
||||||
id: self.control_centers.ids.next(),
|
|
||||||
window,
|
|
||||||
state: self.clone(),
|
|
||||||
tree: RefCell::new(Settings {
|
|
||||||
tree: Tree::new_tabs("abcd", vec![]),
|
|
||||||
}),
|
|
||||||
pane_ids: Default::default(),
|
|
||||||
interests: Default::default(),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
cc.inner.window.set_owner(Some(cc.inner.clone()));
|
|
||||||
self.control_centers
|
|
||||||
.control_centers
|
|
||||||
.set(cc.inner.id, cc.clone());
|
|
||||||
Ok(cc)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn trigger_cci(&self, cci: ControlCenterInterest) {
|
|
||||||
self.control_centers.change.or_assign(cci);
|
|
||||||
self.control_centers.redraw.trigger();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ControlCenterInner {
|
|
||||||
fn close(&self) {
|
|
||||||
self.window.set_owner(None);
|
|
||||||
self.tree.borrow_mut().tree = Tree::empty("");
|
|
||||||
self.state.control_centers.control_centers.remove(&self.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for ControlCenter {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
self.inner.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ControlCenterInner {
|
|
||||||
fn create_pane(&self, ty: PaneType) -> Pane {
|
|
||||||
let pane = Pane {
|
|
||||||
id: self.pane_ids.next(),
|
|
||||||
ps: PaneState {
|
|
||||||
errors: Default::default(),
|
|
||||||
},
|
|
||||||
own_interests: ty.interest(),
|
|
||||||
cc_interests: self.interests.clone(),
|
|
||||||
ty,
|
|
||||||
};
|
|
||||||
let own = pane.own_interests;
|
|
||||||
for (idx, v) in pane.cc_interests.interests_array.iter().enumerate() {
|
|
||||||
let interest = ControlCenterInterest(1 << idx);
|
|
||||||
if own.intersects(interest) && v.fetch_add(1) == 0 {
|
|
||||||
pane.cc_interests.interests.or_assign(interest);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pane
|
|
||||||
}
|
|
||||||
|
|
||||||
fn open(&self, tree: &mut Tree<Pane>, ty: PaneType) {
|
|
||||||
let pane = self.create_pane(ty);
|
|
||||||
let id = tree.tiles.insert_pane(pane);
|
|
||||||
if let Some(root) = tree.root
|
|
||||||
&& let Some(tile) = tree.tiles.get_mut(root)
|
|
||||||
{
|
|
||||||
match tile {
|
|
||||||
Tile::Container(c) => {
|
|
||||||
c.add_child(id);
|
|
||||||
}
|
|
||||||
Tile::Pane(_) => {
|
|
||||||
let root = tree.tiles.insert_tab_tile(vec![root, id]);
|
|
||||||
tree.root = Some(root);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
tree.root = Some(id);
|
|
||||||
}
|
|
||||||
tree.make_active(|t, _| t == id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for Pane {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
let own = self.own_interests;
|
|
||||||
for (idx, v) in self.cc_interests.interests_array.iter().enumerate() {
|
|
||||||
let interest = ControlCenterInterest(1 << idx);
|
|
||||||
if own.intersects(interest) && v.fetch_sub(1) == 1 {
|
|
||||||
self.cc_interests.interests.and_assign(!interest);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn icon_label(icon: &str) -> Label {
|
|
||||||
Label::new(icon).selectable(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn grid_label(ui: &mut Ui, label: &str) {
|
|
||||||
ui.with_layout(Layout::right_to_left(Align::Center), |ui| {
|
|
||||||
ui.label(label);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn grid_label_ui<R>(ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResponse<R> {
|
|
||||||
ui.with_layout(Layout::right_to_left(Align::Center), add_contents)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tip(ui: &mut Ui, add_contents: impl FnOnce(&mut Ui)) {
|
|
||||||
icon_label(ICON_INFO).ui(ui).on_hover_ui(add_contents);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn text_edit(ui: &mut Ui, v: &mut dyn TextBuffer) -> Response {
|
|
||||||
TextEdit::singleline(v)
|
|
||||||
.clip_text(false)
|
|
||||||
.min_size(vec2(200.0, 0.0))
|
|
||||||
.ui(ui)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn show_errors(ui: &mut Ui, pane: &mut PaneState) {
|
|
||||||
if pane.errors.is_empty() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let mut to_remove = None;
|
|
||||||
for (idx, e) in pane.errors.iter().enumerate() {
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
Frame::new().inner_margin(5.0).show(ui, |ui| {
|
|
||||||
if ui.button(ICON_CLOSE).clicked() {
|
|
||||||
to_remove = Some(idx);
|
|
||||||
}
|
|
||||||
ui.label(
|
|
||||||
RichText::new("Error:")
|
|
||||||
.strong()
|
|
||||||
.color(ui.style().visuals.error_fg_color),
|
|
||||||
);
|
|
||||||
ui.add(Label::new(e).wrap());
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if let Some(idx) = to_remove {
|
|
||||||
pane.errors.remove(idx);
|
|
||||||
ui.request_repaint();
|
|
||||||
}
|
|
||||||
ui.separator();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn grid<R>(
|
|
||||||
ui: &mut Ui,
|
|
||||||
id_salt: impl Hash,
|
|
||||||
add_contents: impl FnOnce(&mut Ui) -> R,
|
|
||||||
) -> InnerResponse<R> {
|
|
||||||
let mut spacing = ui.spacing().item_spacing;
|
|
||||||
spacing.x *= 3.0;
|
|
||||||
Grid::new(id_salt).spacing(spacing).show(ui, add_contents)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn row<R>(ui: &mut Ui, name: &str, add_contents: impl FnOnce(&mut Ui) -> R) -> R {
|
|
||||||
row_ui(ui, name, |_| (), add_contents)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn row_ui<R, S>(
|
|
||||||
ui: &mut Ui,
|
|
||||||
name: &str,
|
|
||||||
label: impl FnOnce(&mut Ui) -> S,
|
|
||||||
add_contents: impl FnOnce(&mut Ui) -> R,
|
|
||||||
) -> R {
|
|
||||||
let ui = &mut *ui.row();
|
|
||||||
grid_label_ui(ui, |ui| {
|
|
||||||
ui.label(name);
|
|
||||||
label(ui);
|
|
||||||
});
|
|
||||||
add_contents(ui)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bool(ui: &mut Ui, name: &str, old: bool, set: impl FnOnce(bool)) {
|
|
||||||
bool_ui(ui, name, |_| (), old, set);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bool_ui<R>(
|
|
||||||
ui: &mut Ui,
|
|
||||||
name: &str,
|
|
||||||
label: impl FnOnce(&mut Ui) -> R,
|
|
||||||
mut v: bool,
|
|
||||||
set: impl FnOnce(bool),
|
|
||||||
) {
|
|
||||||
row_ui(ui, name, label, |ui| {
|
|
||||||
if Checkbox::without_text(&mut v).ui(ui).changed() {
|
|
||||||
set(v);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_only_bool(ui: &mut Ui, name: &str, old: bool) {
|
|
||||||
read_only_bool_ui(ui, name, |_| (), old);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_only_bool_ui<R>(ui: &mut Ui, name: &str, label: impl FnOnce(&mut Ui) -> R, mut v: bool) {
|
|
||||||
row_ui(ui, name, label, |ui| {
|
|
||||||
ui.add_enabled_ui(false, |ui| Checkbox::without_text(&mut v).ui(ui));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn combo_box<T>(ui: &mut Ui, name: &str, old: T, set: impl FnOnce(T))
|
|
||||||
where
|
|
||||||
T: StaticText + Linearize + PartialEq + Copy,
|
|
||||||
{
|
|
||||||
combo_box_ui(ui, name, |_| (), old, set);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn combo_box_ui<R, T>(
|
|
||||||
ui: &mut Ui,
|
|
||||||
name: &str,
|
|
||||||
label: impl FnOnce(&mut Ui) -> R,
|
|
||||||
mut v: T,
|
|
||||||
set: impl FnOnce(T),
|
|
||||||
) where
|
|
||||||
T: StaticText + Linearize + PartialEq + Copy,
|
|
||||||
{
|
|
||||||
row_ui(ui, name, label, |ui| {
|
|
||||||
let old = v;
|
|
||||||
ComboBox::from_id_salt(name)
|
|
||||||
.selected_text(v.text())
|
|
||||||
.show_ui(ui, |ui| {
|
|
||||||
for s in T::variants() {
|
|
||||||
ui.selectable_value(&mut v, s, s.text());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if old != v {
|
|
||||||
set(v);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn drag_value<N>(
|
|
||||||
ui: &mut Ui,
|
|
||||||
name: &str,
|
|
||||||
old: N,
|
|
||||||
range: RangeInclusive<N>,
|
|
||||||
speed: f64,
|
|
||||||
set: impl FnOnce(N),
|
|
||||||
) where
|
|
||||||
N: Numeric,
|
|
||||||
{
|
|
||||||
drag_value_ui(ui, name, |_| (), old, range, speed, set);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn drag_value_ui<R, N>(
|
|
||||||
ui: &mut Ui,
|
|
||||||
name: &str,
|
|
||||||
label: impl FnOnce(&mut Ui) -> R,
|
|
||||||
mut v: N,
|
|
||||||
range: RangeInclusive<N>,
|
|
||||||
speed: f64,
|
|
||||||
set: impl FnOnce(N),
|
|
||||||
) where
|
|
||||||
N: Numeric,
|
|
||||||
{
|
|
||||||
row_ui(ui, name, label, |ui| {
|
|
||||||
if DragValue::new(&mut v)
|
|
||||||
.range(range)
|
|
||||||
.speed(speed)
|
|
||||||
.ui(ui)
|
|
||||||
.changed()
|
|
||||||
{
|
|
||||||
set(v);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn label(ui: &mut Ui, name: &str, text: impl Into<WidgetText>) {
|
|
||||||
row(ui, name, |ui| ui.label(text));
|
|
||||||
}
|
|
||||||
|
|
||||||
trait GridExt {
|
|
||||||
fn row(&mut self) -> impl DerefMut<Target = Ui>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GridExt for Ui {
|
|
||||||
fn row(&mut self) -> impl DerefMut<Target = Ui> {
|
|
||||||
GridRow { ui: self }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct GridRow<'a> {
|
|
||||||
ui: &'a mut Ui,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for GridRow<'_> {
|
|
||||||
type Target = Ui;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
self.ui
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for GridRow<'_> {
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
&mut *self.ui
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for GridRow<'_> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
self.end_row();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LazyEventSourceListener for ControlCenterInner {
|
|
||||||
fn triggered(self: Rc<Self>) {
|
|
||||||
self.window.request_redraw();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,453 +0,0 @@
|
||||||
use {
|
|
||||||
crate::{
|
|
||||||
client::{Client, ClientId},
|
|
||||||
control_center::{
|
|
||||||
CcBehavior, ControlCenterInner, PaneType,
|
|
||||||
cc_criterion::{CcCriterion, CritImpl, CritRegex},
|
|
||||||
cc_window::show_window_collapsible,
|
|
||||||
grid, icon_label, label, read_only_bool,
|
|
||||||
},
|
|
||||||
criteria::{CritMgrExt, CritUpstreamNode, crit_leaf::CritLeafMatcher},
|
|
||||||
egui_adapter::egui_platform::icons::ICON_OPEN_IN_NEW,
|
|
||||||
state::State,
|
|
||||||
tree::{ToplevelData, ToplevelIdentifier},
|
|
||||||
utils::{copyhashmap::CopyHashMap, static_text::StaticText},
|
|
||||||
},
|
|
||||||
ahash::AHashMap,
|
|
||||||
egui::{
|
|
||||||
CollapsingHeader, DragValue, Sense, TextFormat, Ui, Widget, cache::CacheTrait,
|
|
||||||
text::LayoutJob,
|
|
||||||
},
|
|
||||||
linearize::Linearize,
|
|
||||||
std::rc::{Rc, Weak},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub enum ClientCrit {
|
|
||||||
SandboxEngine(CritRegex),
|
|
||||||
SandboxAppId(CritRegex),
|
|
||||||
SandboxInstanceId(CritRegex),
|
|
||||||
Sandboxed,
|
|
||||||
Uid(i32),
|
|
||||||
Pid(i32),
|
|
||||||
IsXwayland,
|
|
||||||
Comm(CritRegex),
|
|
||||||
Exe(CritRegex),
|
|
||||||
Tag(CritRegex),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Linearize)]
|
|
||||||
pub enum ClientCritTy {
|
|
||||||
SandboxEngine,
|
|
||||||
SandboxAppId,
|
|
||||||
SandboxInstanceId,
|
|
||||||
Sandboxed,
|
|
||||||
Uid,
|
|
||||||
Pid,
|
|
||||||
IsXwayland,
|
|
||||||
Comm,
|
|
||||||
Exe,
|
|
||||||
Tag,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for ClientCrit {
|
|
||||||
fn default() -> Self {
|
|
||||||
ClientCrit::Comm(Default::default())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StaticText for ClientCritTy {
|
|
||||||
fn text(&self) -> &'static str {
|
|
||||||
match self {
|
|
||||||
ClientCritTy::SandboxEngine => "Sandbox Engine",
|
|
||||||
ClientCritTy::SandboxAppId => "Sandbox App ID",
|
|
||||||
ClientCritTy::SandboxInstanceId => "Sandbox Instance ID",
|
|
||||||
ClientCritTy::Sandboxed => "Sandboxed",
|
|
||||||
ClientCritTy::Uid => "UID",
|
|
||||||
ClientCritTy::Pid => "PID",
|
|
||||||
ClientCritTy::IsXwayland => "Is Xwayland",
|
|
||||||
ClientCritTy::Comm => "Comm",
|
|
||||||
ClientCritTy::Exe => "Exe",
|
|
||||||
ClientCritTy::Tag => "Tag",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CritImpl for ClientCrit {
|
|
||||||
type Type = ClientCritTy;
|
|
||||||
type Target = Rc<Client>;
|
|
||||||
|
|
||||||
fn ty(&self) -> Self::Type {
|
|
||||||
macro_rules! map {
|
|
||||||
($($n:ident,)*) => {
|
|
||||||
match self {
|
|
||||||
$(
|
|
||||||
Self::$n { .. } => ClientCritTy::$n,
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
map! {
|
|
||||||
SandboxEngine,
|
|
||||||
SandboxAppId,
|
|
||||||
SandboxInstanceId,
|
|
||||||
Sandboxed,
|
|
||||||
Uid,
|
|
||||||
Pid,
|
|
||||||
IsXwayland,
|
|
||||||
Comm,
|
|
||||||
Exe,
|
|
||||||
Tag,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_ty(ty: Self::Type) -> Self {
|
|
||||||
match ty {
|
|
||||||
ClientCritTy::SandboxEngine => Self::SandboxEngine(Default::default()),
|
|
||||||
ClientCritTy::SandboxAppId => Self::SandboxAppId(Default::default()),
|
|
||||||
ClientCritTy::SandboxInstanceId => Self::SandboxInstanceId(Default::default()),
|
|
||||||
ClientCritTy::Sandboxed => Self::Sandboxed,
|
|
||||||
ClientCritTy::Uid => Self::Uid(Default::default()),
|
|
||||||
ClientCritTy::Pid => Self::Pid(Default::default()),
|
|
||||||
ClientCritTy::IsXwayland => Self::IsXwayland,
|
|
||||||
ClientCritTy::Comm => Self::Comm(Default::default()),
|
|
||||||
ClientCritTy::Exe => Self::Exe(Default::default()),
|
|
||||||
ClientCritTy::Tag => Self::Tag(Default::default()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn show(&mut self, ui: &mut Ui) -> bool {
|
|
||||||
match self {
|
|
||||||
ClientCrit::SandboxEngine(v) => v.show(ui),
|
|
||||||
ClientCrit::SandboxAppId(v) => v.show(ui),
|
|
||||||
ClientCrit::SandboxInstanceId(v) => v.show(ui),
|
|
||||||
ClientCrit::Sandboxed => false,
|
|
||||||
ClientCrit::Uid(v) => DragValue::new(v).ui(ui).changed(),
|
|
||||||
ClientCrit::Pid(v) => DragValue::new(v).ui(ui).changed(),
|
|
||||||
ClientCrit::IsXwayland => false,
|
|
||||||
ClientCrit::Comm(v) => v.show(ui),
|
|
||||||
ClientCrit::Exe(v) => v.show(ui),
|
|
||||||
ClientCrit::Tag(v) => v.show(ui),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_crit(&self, state: &Rc<State>) -> Option<Rc<dyn CritUpstreamNode<Self::Target>>> {
|
|
||||||
let m = &state.cl_matcher_manager;
|
|
||||||
let res = match self {
|
|
||||||
ClientCrit::SandboxEngine(v) => m.sandbox_engine(v.to_crit()?),
|
|
||||||
ClientCrit::SandboxAppId(v) => m.sandbox_app_id(v.to_crit()?),
|
|
||||||
ClientCrit::SandboxInstanceId(v) => m.sandbox_instance_id(v.to_crit()?),
|
|
||||||
ClientCrit::Sandboxed => m.sandboxed(),
|
|
||||||
ClientCrit::Uid(v) => m.uid(*v),
|
|
||||||
ClientCrit::Pid(v) => m.pid(*v),
|
|
||||||
ClientCrit::IsXwayland => m.is_xwayland(),
|
|
||||||
ClientCrit::Comm(v) => m.comm(v.to_crit()?),
|
|
||||||
ClientCrit::Exe(v) => m.exe(v.to_crit()?),
|
|
||||||
ClientCrit::Tag(v) => m.tag(v.to_crit()?),
|
|
||||||
};
|
|
||||||
Some(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn not(
|
|
||||||
state: &State,
|
|
||||||
upstream: &Rc<dyn CritUpstreamNode<Self::Target>>,
|
|
||||||
) -> Rc<dyn CritUpstreamNode<Self::Target>> {
|
|
||||||
state.cl_matcher_manager.not(upstream)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn list(
|
|
||||||
state: &State,
|
|
||||||
upstream: &[Rc<dyn CritUpstreamNode<Self::Target>>],
|
|
||||||
all: bool,
|
|
||||||
) -> Rc<dyn CritUpstreamNode<Self::Target>> {
|
|
||||||
state.cl_matcher_manager.list(upstream, all)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn exactly(
|
|
||||||
state: &State,
|
|
||||||
n: usize,
|
|
||||||
upstream: &[Rc<dyn CritUpstreamNode<Self::Target>>],
|
|
||||||
) -> Rc<dyn CritUpstreamNode<Self::Target>> {
|
|
||||||
state.cl_matcher_manager.exactly(upstream, n)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ClientsPane {
|
|
||||||
state: Rc<State>,
|
|
||||||
filter: bool,
|
|
||||||
criterion: CcCriterion<ClientCrit>,
|
|
||||||
matched: Rc<Matched>,
|
|
||||||
leaf: Option<Rc<CritLeafMatcher<Rc<Client>>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Matched {
|
|
||||||
slf: Weak<ControlCenterInner>,
|
|
||||||
clients: CopyHashMap<ClientId, ()>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Matched {
|
|
||||||
fn request_frame(&self) {
|
|
||||||
if let Some(slf) = self.slf.upgrade() {
|
|
||||||
slf.window.request_redraw();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ControlCenterInner {
|
|
||||||
pub fn create_clients_pane(self: &Rc<Self>) -> ClientsPane {
|
|
||||||
let mut pane = ClientsPane {
|
|
||||||
state: self.state.clone(),
|
|
||||||
filter: false,
|
|
||||||
criterion: Default::default(),
|
|
||||||
matched: Rc::new(Matched {
|
|
||||||
slf: Rc::downgrade(self),
|
|
||||||
clients: Default::default(),
|
|
||||||
}),
|
|
||||||
leaf: Default::default(),
|
|
||||||
};
|
|
||||||
pane.update_matcher();
|
|
||||||
pane
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ClientsPane {
|
|
||||||
pub fn title(&self, res: &mut String) {
|
|
||||||
res.push_str("Clients");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show(&mut self, behavior: &mut CcBehavior<'_>, ui: &mut Ui) {
|
|
||||||
if ui.checkbox(&mut self.filter, "Filter").changed() && !self.filter {
|
|
||||||
self.criterion = Default::default();
|
|
||||||
self.update_matcher();
|
|
||||||
}
|
|
||||||
let mut clear_clients = false;
|
|
||||||
if self.filter && self.criterion.show(ui) {
|
|
||||||
clear_clients = self.update_matcher();
|
|
||||||
}
|
|
||||||
ui.separator();
|
|
||||||
let mut clients: Vec<_> = self.matched.clients.lock().keys().copied().collect();
|
|
||||||
clients.sort();
|
|
||||||
for id in clients {
|
|
||||||
let Ok(client) = self.state.clients.get(id) else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
show_client_collapsible(behavior, ui, &client);
|
|
||||||
}
|
|
||||||
if clear_clients {
|
|
||||||
self.matched.clients.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_matcher(&mut self) -> bool {
|
|
||||||
let mut clear_clients = false;
|
|
||||||
let state = &self.state;
|
|
||||||
if let Some(new) = self.criterion.to_crit(state) {
|
|
||||||
clear_clients = true;
|
|
||||||
let matched = self.matched.clone();
|
|
||||||
let leaf = state.cl_matcher_manager.leaf(&new, move |data| {
|
|
||||||
matched.clients.set(data, ());
|
|
||||||
matched.request_frame();
|
|
||||||
Box::new({
|
|
||||||
let matched = matched.clone();
|
|
||||||
move || {
|
|
||||||
matched.clients.remove(&data);
|
|
||||||
matched.request_frame();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
});
|
|
||||||
state.cl_matcher_manager.rematch_all(state);
|
|
||||||
self.leaf = Some(leaf);
|
|
||||||
}
|
|
||||||
clear_clients
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ClientPane {
|
|
||||||
client: Rc<Client>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ControlCenterInner {
|
|
||||||
pub fn create_client_pane(self: &Rc<Self>, client: &Rc<Client>) -> ClientPane {
|
|
||||||
ClientPane {
|
|
||||||
client: client.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ClientPane {
|
|
||||||
pub fn title(&self, res: &mut String) {
|
|
||||||
res.push_str("Client ");
|
|
||||||
res.push_str(&self.client.pid_info.comm);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show(&mut self, behavior: &mut CcBehavior<'_>, ui: &mut Ui) {
|
|
||||||
show_client(behavior, ui, &self.client);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show_client_collapsible(behavior: &mut CcBehavior, ui: &mut Ui, client: &Rc<Client>) {
|
|
||||||
let mut layout_job = LayoutJob::default();
|
|
||||||
layout_job.append(
|
|
||||||
"Client",
|
|
||||||
0.0,
|
|
||||||
TextFormat {
|
|
||||||
color: ui.style().visuals.widgets.inactive.text_color(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
);
|
|
||||||
layout_job.append(
|
|
||||||
&client.id.to_string(),
|
|
||||||
10.0,
|
|
||||||
TextFormat {
|
|
||||||
color: ui.style().visuals.widgets.active.text_color(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
);
|
|
||||||
layout_job.append(
|
|
||||||
&client.pid_info.comm,
|
|
||||||
10.0,
|
|
||||||
TextFormat {
|
|
||||||
color: ui.style().visuals.widgets.inactive.text_color(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
);
|
|
||||||
CollapsingHeader::new(layout_job)
|
|
||||||
.id_salt(("client", client.id))
|
|
||||||
.show(ui, |ui| {
|
|
||||||
if icon_label(ICON_OPEN_IN_NEW)
|
|
||||||
.sense(Sense::CLICK)
|
|
||||||
.ui(ui)
|
|
||||||
.clicked()
|
|
||||||
{
|
|
||||||
behavior.open = Some(PaneType::Client(behavior.cc.create_client_pane(client)));
|
|
||||||
}
|
|
||||||
show_client(behavior, ui, client)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show_client(behavior: &mut CcBehavior<'_>, ui: &mut Ui, client: &Client) {
|
|
||||||
grid(ui, ("client", client.id), |ui| {
|
|
||||||
label(ui, "ID", client.id.to_string());
|
|
||||||
label(ui, "PID", client.pid_info.pid.to_string());
|
|
||||||
label(ui, "UID", client.pid_info.uid.to_string());
|
|
||||||
label(ui, "comm", &client.pid_info.comm);
|
|
||||||
label(ui, "exe", &client.pid_info.exe);
|
|
||||||
if client.acceptor.sandboxed {
|
|
||||||
read_only_bool(ui, "Sandboxed", true);
|
|
||||||
}
|
|
||||||
if client.acceptor.secure {
|
|
||||||
read_only_bool(ui, "Secure", true);
|
|
||||||
}
|
|
||||||
if client.is_xwayland {
|
|
||||||
read_only_bool(ui, "Xwayland", true);
|
|
||||||
}
|
|
||||||
if let Some(v) = &client.acceptor.sandbox_engine {
|
|
||||||
label(ui, "Sandbox Engine", v);
|
|
||||||
}
|
|
||||||
if let Some(v) = &client.acceptor.app_id {
|
|
||||||
label(ui, "App ID", v);
|
|
||||||
}
|
|
||||||
if let Some(v) = &client.acceptor.instance_id {
|
|
||||||
label(ui, "Instance ID", v);
|
|
||||||
}
|
|
||||||
if let Some(v) = &client.acceptor.tag {
|
|
||||||
label(ui, "Tag", v);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if ui.button("Kill").clicked() {
|
|
||||||
client.state.clients.kill(client.id);
|
|
||||||
}
|
|
||||||
ui.collapsing("Capabilities", |ui| {
|
|
||||||
ui.add_enabled_ui(false, |ui| {
|
|
||||||
for (k, v) in client.effective_caps.get().to_map() {
|
|
||||||
if v {
|
|
||||||
ui.checkbox(&mut true, k.text());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
ui.collapsing("Windows", |ui| {
|
|
||||||
let matcher = ui.memory_mut(|m| {
|
|
||||||
m.caches
|
|
||||||
.cache::<ClientWindowMatchersCache>()
|
|
||||||
.get(behavior.cc, client.id)
|
|
||||||
.clone()
|
|
||||||
});
|
|
||||||
let mut windows: Vec<_> = matcher.windows.lock().keys().copied().collect();
|
|
||||||
windows.sort();
|
|
||||||
for id in windows {
|
|
||||||
let Some(window) = client.state.toplevels.get(&id).and_then(|v| v.upgrade()) else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
show_window_collapsible(behavior, ui, &window);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
struct ClientWindowMatchersCache {
|
|
||||||
generation: u64,
|
|
||||||
matchers: AHashMap<ClientId, CachedWindowMatcher>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CachedWindowMatcher {
|
|
||||||
generation: u64,
|
|
||||||
_matcher: Rc<CritLeafMatcher<ToplevelData>>,
|
|
||||||
matchers: Rc<WindowMatchers>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct WindowMatchers {
|
|
||||||
cc: Weak<ControlCenterInner>,
|
|
||||||
windows: CopyHashMap<ToplevelIdentifier, ()>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ClientWindowMatchersCache {
|
|
||||||
fn get(&mut self, cc: &Rc<ControlCenterInner>, id: ClientId) -> &Rc<WindowMatchers> {
|
|
||||||
let res = self.matchers.entry(id).or_insert_with(|| {
|
|
||||||
let state = &cc.state;
|
|
||||||
let node = state.cl_matcher_manager.id(id);
|
|
||||||
let node = state.tl_matcher_manager.client(state, &node);
|
|
||||||
let matchers = Rc::new(WindowMatchers {
|
|
||||||
cc: Rc::downgrade(&cc),
|
|
||||||
windows: Default::default(),
|
|
||||||
});
|
|
||||||
let matchers2 = matchers.clone();
|
|
||||||
let matcher = state.tl_matcher_manager.leaf(&node, move |id| {
|
|
||||||
matchers2.windows.set(id, ());
|
|
||||||
if let Some(cc) = matchers2.cc.upgrade() {
|
|
||||||
cc.window.request_redraw();
|
|
||||||
}
|
|
||||||
let matchers2 = matchers2.clone();
|
|
||||||
Box::new(move || {
|
|
||||||
matchers2.windows.remove(&id);
|
|
||||||
if let Some(cc) = matchers2.cc.upgrade() {
|
|
||||||
cc.window.request_redraw();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
});
|
|
||||||
let res = CachedWindowMatcher {
|
|
||||||
generation: 0,
|
|
||||||
_matcher: matcher,
|
|
||||||
matchers,
|
|
||||||
};
|
|
||||||
state.cl_matcher_manager.rematch_all(state);
|
|
||||||
state.tl_matcher_manager.rematch_all(state);
|
|
||||||
res
|
|
||||||
});
|
|
||||||
res.generation = self.generation;
|
|
||||||
&res.matchers
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Sync for ClientWindowMatchersCache {}
|
|
||||||
unsafe impl Send for ClientWindowMatchersCache {}
|
|
||||||
|
|
||||||
impl CacheTrait for ClientWindowMatchersCache {
|
|
||||||
fn update(&mut self) {
|
|
||||||
self.matchers.retain(|_, m| m.generation == self.generation);
|
|
||||||
self.generation += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn len(&self) -> usize {
|
|
||||||
self.matchers.len()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
use {
|
|
||||||
crate::{
|
|
||||||
control_center::{ControlCenterInner, bool, grid, read_only_bool},
|
|
||||||
state::State,
|
|
||||||
},
|
|
||||||
egui::Ui,
|
|
||||||
std::rc::Rc,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct ColorManagementPane {
|
|
||||||
state: Rc<State>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ControlCenterInner {
|
|
||||||
pub fn create_color_management_pane(self: &Rc<Self>) -> ColorManagementPane {
|
|
||||||
ColorManagementPane {
|
|
||||||
state: self.state.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ColorManagementPane {
|
|
||||||
pub fn title(&self, res: &mut String) {
|
|
||||||
res.push_str("Color Management");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show(&mut self, ui: &mut Ui) {
|
|
||||||
let s = &self.state;
|
|
||||||
grid(ui, "settings", |ui| {
|
|
||||||
bool(ui, "Enabled", s.color_management_enabled.get(), |b| {
|
|
||||||
s.set_color_management_enabled(b);
|
|
||||||
});
|
|
||||||
read_only_bool(ui, "Available", s.color_management_available());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,88 +0,0 @@
|
||||||
use {
|
|
||||||
crate::{
|
|
||||||
compositor::{LIBEI_SOCKET, WAYLAND_DISPLAY},
|
|
||||||
control_center::{ControlCenterInner, bool, combo_box, grid, label, row},
|
|
||||||
state::State,
|
|
||||||
version::VERSION,
|
|
||||||
},
|
|
||||||
egui::{DragValue, OpenUrl, Ui, Widget},
|
|
||||||
std::rc::Rc,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct CompositorPane {
|
|
||||||
state: Rc<State>,
|
|
||||||
switch_to_vt: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ControlCenterInner {
|
|
||||||
pub fn create_compositor_pane(self: &Rc<Self>) -> CompositorPane {
|
|
||||||
CompositorPane {
|
|
||||||
state: self.state.clone(),
|
|
||||||
switch_to_vt: 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CompositorPane {
|
|
||||||
pub fn title(&self, res: &mut String) {
|
|
||||||
res.push_str("Compositor");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show(&mut self, ui: &mut Ui) {
|
|
||||||
let s = &self.state;
|
|
||||||
grid(ui, "compositor", |ui| {
|
|
||||||
row(ui, "Repository", |ui| {
|
|
||||||
let url = "https://github.com/mahkoh/jay";
|
|
||||||
if ui.link(url).clicked() {
|
|
||||||
ui.open_url(OpenUrl::new_tab(url));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
label(ui, "Version", VERSION);
|
|
||||||
label(ui, "PID", s.pid.to_string());
|
|
||||||
if let Some(acceptor) = s.acceptor.get() {
|
|
||||||
label(ui, WAYLAND_DISPLAY, acceptor.socket_name());
|
|
||||||
}
|
|
||||||
if let Some(dir) = &s.config_dir {
|
|
||||||
label(ui, "Config DIR", dir);
|
|
||||||
}
|
|
||||||
bool(ui, "Libei Socket", s.enable_ei_acceptor.get(), |v| {
|
|
||||||
s.set_ei_socket_enabled(v);
|
|
||||||
});
|
|
||||||
if let Some(a) = s.ei_acceptor.get() {
|
|
||||||
label(ui, LIBEI_SOCKET, a.socket_name());
|
|
||||||
}
|
|
||||||
combo_box(
|
|
||||||
ui,
|
|
||||||
"Workspace Display Order",
|
|
||||||
s.workspace_display_order.get(),
|
|
||||||
|o| s.set_workspace_display_order(o),
|
|
||||||
);
|
|
||||||
if let Some(logger) = &s.logger {
|
|
||||||
combo_box(ui, "Log Level", logger.level(), |l| s.set_log_level(l));
|
|
||||||
row(ui, "Log File", |ui| {
|
|
||||||
let path = logger.path().to_string();
|
|
||||||
if ui
|
|
||||||
.link(&path)
|
|
||||||
.on_hover_text_at_pointer("Copy to clipboard")
|
|
||||||
.clicked()
|
|
||||||
{
|
|
||||||
ui.copy_text(path);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if ui.button("Quit").clicked() {
|
|
||||||
s.quit();
|
|
||||||
}
|
|
||||||
if ui.button("Reload Config").clicked() {
|
|
||||||
s.reload_config();
|
|
||||||
}
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
let button = ui.button("Switch to VT");
|
|
||||||
DragValue::new(&mut self.switch_to_vt).ui(ui);
|
|
||||||
if button.clicked() {
|
|
||||||
s.backend.get().switch_to(self.switch_to_vt);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,253 +0,0 @@
|
||||||
use {
|
|
||||||
crate::{
|
|
||||||
criteria::{CritLiteralOrRegex, CritUpstreamNode},
|
|
||||||
egui_adapter::egui_platform::icons::ICON_CLOSE,
|
|
||||||
state::State,
|
|
||||||
utils::{numcell::NumCell, static_text::StaticText},
|
|
||||||
},
|
|
||||||
ahash::AHashSet,
|
|
||||||
egui::{ComboBox, DragValue, Ui, UiBuilder, Widget},
|
|
||||||
isnt::std_1::collections::IsntHashSetExt,
|
|
||||||
linearize::{Linearize, LinearizeExt},
|
|
||||||
regex::Regex,
|
|
||||||
std::rc::Rc,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub enum CcCriterion<T> {
|
|
||||||
Not(Box<Self>),
|
|
||||||
List(Vec<Self>, bool),
|
|
||||||
Exactly(usize, Vec<Self>),
|
|
||||||
T(T),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Default for CcCriterion<T>
|
|
||||||
where
|
|
||||||
T: Default,
|
|
||||||
{
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::T(T::default())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Linearize)]
|
|
||||||
enum CompoundCritTy {
|
|
||||||
Not,
|
|
||||||
All,
|
|
||||||
Any,
|
|
||||||
Exactly,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
|
||||||
enum CritTy<T> {
|
|
||||||
Compound(CompoundCritTy),
|
|
||||||
T(T),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StaticText for CompoundCritTy {
|
|
||||||
fn text(&self) -> &'static str {
|
|
||||||
match self {
|
|
||||||
Self::Not => "Not",
|
|
||||||
Self::All => "All",
|
|
||||||
Self::Any => "Any",
|
|
||||||
Self::Exactly => "Exactly",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> StaticText for CritTy<T>
|
|
||||||
where
|
|
||||||
T: StaticText,
|
|
||||||
{
|
|
||||||
fn text(&self) -> &'static str {
|
|
||||||
match self {
|
|
||||||
Self::Compound(t) => t.text(),
|
|
||||||
Self::T(t) => t.text(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait CritImpl: Default {
|
|
||||||
type Type: Copy + Eq + PartialEq + StaticText + Linearize;
|
|
||||||
type Target;
|
|
||||||
|
|
||||||
fn ty(&self) -> Self::Type;
|
|
||||||
fn from_ty(ty: Self::Type) -> Self;
|
|
||||||
#[must_use]
|
|
||||||
fn show(&mut self, ui: &mut Ui) -> bool;
|
|
||||||
|
|
||||||
fn to_crit(&self, state: &Rc<State>) -> Option<Rc<dyn CritUpstreamNode<Self::Target>>>;
|
|
||||||
fn not(
|
|
||||||
state: &State,
|
|
||||||
upstream: &Rc<dyn CritUpstreamNode<Self::Target>>,
|
|
||||||
) -> Rc<dyn CritUpstreamNode<Self::Target>>;
|
|
||||||
fn list(
|
|
||||||
state: &State,
|
|
||||||
upstream: &[Rc<dyn CritUpstreamNode<Self::Target>>],
|
|
||||||
all: bool,
|
|
||||||
) -> Rc<dyn CritUpstreamNode<Self::Target>>;
|
|
||||||
fn exactly(
|
|
||||||
state: &State,
|
|
||||||
n: usize,
|
|
||||||
upstream: &[Rc<dyn CritUpstreamNode<Self::Target>>],
|
|
||||||
) -> Rc<dyn CritUpstreamNode<Self::Target>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> CcCriterion<T>
|
|
||||||
where
|
|
||||||
T: CritImpl,
|
|
||||||
{
|
|
||||||
#[must_use]
|
|
||||||
pub fn show(&mut self, ui: &mut Ui) -> bool {
|
|
||||||
let mut changed = false;
|
|
||||||
ui.vertical(|ui| {
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
let mut v = self.ty();
|
|
||||||
let old = v;
|
|
||||||
ComboBox::from_id_salt("ty")
|
|
||||||
.selected_text(v.text())
|
|
||||||
.show_ui(ui, |ui| {
|
|
||||||
for s in CompoundCritTy::variants() {
|
|
||||||
ui.selectable_value(&mut v, CritTy::Compound(s), s.text());
|
|
||||||
}
|
|
||||||
for s in T::Type::variants() {
|
|
||||||
ui.selectable_value(&mut v, CritTy::T(s), s.text());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if old != v {
|
|
||||||
*self = match v {
|
|
||||||
CritTy::Compound(CompoundCritTy::Not) => {
|
|
||||||
CcCriterion::Not(Default::default())
|
|
||||||
}
|
|
||||||
CritTy::Compound(CompoundCritTy::All) => {
|
|
||||||
CcCriterion::List(Default::default(), true)
|
|
||||||
}
|
|
||||||
CritTy::Compound(CompoundCritTy::Any) => {
|
|
||||||
CcCriterion::List(Default::default(), false)
|
|
||||||
}
|
|
||||||
CritTy::Compound(CompoundCritTy::Exactly) => {
|
|
||||||
CcCriterion::Exactly(1, Default::default())
|
|
||||||
}
|
|
||||||
CritTy::T(t) => CcCriterion::T(T::from_ty(t)),
|
|
||||||
};
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
match self {
|
|
||||||
CcCriterion::Not(n) => changed |= n.show(ui),
|
|
||||||
CcCriterion::List(_, _) => {}
|
|
||||||
CcCriterion::Exactly(n, _) => {
|
|
||||||
changed |= DragValue::new(n).ui(ui).changed();
|
|
||||||
}
|
|
||||||
CcCriterion::T(t) => changed |= t.show(ui),
|
|
||||||
}
|
|
||||||
});
|
|
||||||
match self {
|
|
||||||
CcCriterion::Not(_) => {}
|
|
||||||
CcCriterion::List(v, _) | CcCriterion::Exactly(_, v) => {
|
|
||||||
ui.indent("compound", |ui| {
|
|
||||||
let mut to_remove = AHashSet::new();
|
|
||||||
for (idx, v) in v.iter_mut().enumerate() {
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
if ui.button(ICON_CLOSE).clicked() {
|
|
||||||
changed = true;
|
|
||||||
to_remove.insert(idx);
|
|
||||||
}
|
|
||||||
ui.scope_builder(UiBuilder::new().id_salt(idx), |ui| {
|
|
||||||
changed |= v.show(ui);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let i = NumCell::new(0);
|
|
||||||
v.retain(|_| to_remove.not_contains(&i.fetch_add(1)));
|
|
||||||
if ui.button("Add").clicked() {
|
|
||||||
v.push(CcCriterion::default());
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
CcCriterion::T(_) => {}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
changed
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ty(&self) -> CritTy<T::Type> {
|
|
||||||
match self {
|
|
||||||
CcCriterion::Not(_) => CritTy::Compound(CompoundCritTy::Not),
|
|
||||||
CcCriterion::List(_, true) => CritTy::Compound(CompoundCritTy::All),
|
|
||||||
CcCriterion::List(_, false) => CritTy::Compound(CompoundCritTy::Any),
|
|
||||||
CcCriterion::Exactly(_, _) => CritTy::Compound(CompoundCritTy::Exactly),
|
|
||||||
CcCriterion::T(t) => CritTy::T(t.ty()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_crit(&self, state: &Rc<State>) -> Option<Rc<dyn CritUpstreamNode<T::Target>>> {
|
|
||||||
match self {
|
|
||||||
CcCriterion::Not(t) => Some(T::not(state, &t.to_crit(state)?)),
|
|
||||||
CcCriterion::List(v, all) => {
|
|
||||||
let mut upstream = Vec::with_capacity(v.len());
|
|
||||||
for v in v {
|
|
||||||
upstream.push(v.to_crit(state)?);
|
|
||||||
}
|
|
||||||
Some(T::list(state, &upstream, *all))
|
|
||||||
}
|
|
||||||
CcCriterion::Exactly(n, v) => {
|
|
||||||
let mut upstream = Vec::with_capacity(v.len());
|
|
||||||
for v in v {
|
|
||||||
upstream.push(v.to_crit(state)?);
|
|
||||||
}
|
|
||||||
Some(T::exactly(state, *n, &upstream))
|
|
||||||
}
|
|
||||||
CcCriterion::T(t) => t.to_crit(state),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn any(&self, mut any: impl FnMut(&T) -> bool) -> bool {
|
|
||||||
self.any_(&mut any)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn any_(&self, any: &mut impl FnMut(&T) -> bool) -> bool {
|
|
||||||
match self {
|
|
||||||
CcCriterion::Not(v) => v.any_(any),
|
|
||||||
CcCriterion::List(v, _) => v.iter().any(|v| v.any_(any)),
|
|
||||||
CcCriterion::Exactly(_, v) => v.iter().any(|v| v.any_(any)),
|
|
||||||
CcCriterion::T(t) => any(t),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CritRegex {
|
|
||||||
pub text: String,
|
|
||||||
pub regex: Option<Option<Regex>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for CritRegex {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
text: Default::default(),
|
|
||||||
regex: Some(Some(Regex::new("").unwrap())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CritRegex {
|
|
||||||
pub fn show(&mut self, ui: &mut Ui) -> bool {
|
|
||||||
let mut is_regex = self.regex.is_some();
|
|
||||||
let mut changed = false;
|
|
||||||
changed |= ui.text_edit_singleline(&mut self.text).changed();
|
|
||||||
changed |= ui.checkbox(&mut is_regex, "Regex").changed();
|
|
||||||
if changed {
|
|
||||||
self.regex = is_regex.then(|| Regex::new(&self.text).ok());
|
|
||||||
}
|
|
||||||
if let Some(None) = self.regex {
|
|
||||||
ui.label("Error: Invalid regex");
|
|
||||||
}
|
|
||||||
changed
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_crit(&self) -> Option<CritLiteralOrRegex> {
|
|
||||||
match &self.regex {
|
|
||||||
None => Some(CritLiteralOrRegex::Literal(self.text.clone())),
|
|
||||||
Some(v) => Some(CritLiteralOrRegex::Regex(v.clone()?)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,146 +0,0 @@
|
||||||
use {
|
|
||||||
crate::{
|
|
||||||
control_center::{
|
|
||||||
ControlCenterInner, GridExt, bool, combo_box, grid, grid_label, label, row,
|
|
||||||
},
|
|
||||||
egui_adapter::egui_platform::icons::{ICON_ADD, ICON_REMOVE},
|
|
||||||
state::{DrmDevData, State},
|
|
||||||
},
|
|
||||||
egui::{Checkbox, CollapsingHeader, DragValue, TextFormat, Ui, Widget, text::LayoutJob},
|
|
||||||
std::rc::Rc,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct GpusPane {
|
|
||||||
state: Rc<State>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ControlCenterInner {
|
|
||||||
pub fn create_gpus_pane(self: &Rc<Self>) -> GpusPane {
|
|
||||||
GpusPane {
|
|
||||||
state: self.state.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GpusPane {
|
|
||||||
pub fn title(&self, res: &mut String) {
|
|
||||||
res.push_str("GPUs");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show(&mut self, ui: &mut Ui) {
|
|
||||||
let devs = self.state.drm_devs.lock();
|
|
||||||
let mut devs: Vec<_> = devs.iter().collect();
|
|
||||||
devs.sort_by_key(|d| d.0);
|
|
||||||
for dev in devs {
|
|
||||||
self.show_dev(ui, dev.1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn show_dev(&self, ui: &mut Ui, dev: &DrmDevData) {
|
|
||||||
let title_buf;
|
|
||||||
let title = match dev.devnode.as_deref() {
|
|
||||||
Some(t) => t,
|
|
||||||
_ => {
|
|
||||||
let dev_t = dev.dev.dev_t();
|
|
||||||
title_buf = format!("{}:{}", uapi::major(dev_t), uapi::minor(dev_t));
|
|
||||||
&title_buf
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let mut layout_job = LayoutJob::default();
|
|
||||||
layout_job.append(
|
|
||||||
title,
|
|
||||||
0.0,
|
|
||||||
TextFormat {
|
|
||||||
color: ui.style().visuals.widgets.active.text_color(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
);
|
|
||||||
if let Some(model) = &dev.model {
|
|
||||||
layout_job.append(
|
|
||||||
model,
|
|
||||||
10.0,
|
|
||||||
TextFormat {
|
|
||||||
color: ui.style().visuals.widgets.inactive.text_color(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
ui.collapsing(layout_job, |ui| {
|
|
||||||
grid(ui, ("settings", dev.dev.id()), |ui| {
|
|
||||||
macro_rules! string {
|
|
||||||
($field:ident, $name:expr) => {
|
|
||||||
if let Some(v) = &dev.$field {
|
|
||||||
label(ui, $name, v);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
string!(vendor, "Vendor");
|
|
||||||
string!(model, "Model");
|
|
||||||
string!(devnode, "Devnode");
|
|
||||||
string!(syspath, "Syspath");
|
|
||||||
if let Some(v) = dev.pci_id {
|
|
||||||
label(ui, "PCI ID", format!("{:x}:{:x}", v.vendor, v.model));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
let v = dev.dev.dev_t();
|
|
||||||
label(ui, "Dev", format!("{}:{}", uapi::major(v), uapi::minor(v)));
|
|
||||||
}
|
|
||||||
combo_box(ui, "API", dev.dev.gtx_api(), |v| dev.dev.set_gfx_api(v));
|
|
||||||
row(ui, "Primary Device", |ui| {
|
|
||||||
let mut v = dev.dev.is_render_device();
|
|
||||||
let old = v;
|
|
||||||
ui.add_enabled(!v, Checkbox::without_text(&mut v));
|
|
||||||
if v != old {
|
|
||||||
dev.dev.make_render_device();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
bool(
|
|
||||||
ui,
|
|
||||||
"Direct Scanout",
|
|
||||||
dev.dev.direct_scanout_enabled(),
|
|
||||||
|v| dev.set_direct_scanout_enabled(&self.state, v),
|
|
||||||
);
|
|
||||||
if let Some(mut v) = dev.dev.flip_margin() {
|
|
||||||
let ui = &mut *ui.row();
|
|
||||||
grid_label(ui, "Flip Margin");
|
|
||||||
let old = v;
|
|
||||||
let denom = 1_000_000.0;
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
let mut s = v as f64 / denom;
|
|
||||||
let res = DragValue::new(&mut s)
|
|
||||||
.range(0.0..=50.0)
|
|
||||||
.speed(0.1)
|
|
||||||
.fixed_decimals(1)
|
|
||||||
.ui(ui);
|
|
||||||
if res.changed() {
|
|
||||||
v = (s * denom) as u64;
|
|
||||||
}
|
|
||||||
if ui.button(ICON_REMOVE).clicked() {
|
|
||||||
v = v.saturating_sub(100_000);
|
|
||||||
}
|
|
||||||
if ui.button(ICON_ADD).clicked() {
|
|
||||||
v += 100_000;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if old != v {
|
|
||||||
dev.set_flip_margin(&self.state, v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
CollapsingHeader::new("Connectors")
|
|
||||||
.default_open(true)
|
|
||||||
.show(ui, |ui| {
|
|
||||||
let mut cs: Vec<_> = dev
|
|
||||||
.connectors
|
|
||||||
.lock()
|
|
||||||
.values()
|
|
||||||
.map(|v| v.name.clone())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
cs.sort();
|
|
||||||
for c in cs {
|
|
||||||
ui.label(&**c);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
use {
|
|
||||||
crate::{
|
|
||||||
control_center::{ControlCenterInner, grid, row},
|
|
||||||
state::State,
|
|
||||||
},
|
|
||||||
egui::{CollapsingHeader, DragValue, Ui, Widget},
|
|
||||||
std::{rc::Rc, time::Duration},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct IdlePane {
|
|
||||||
state: Rc<State>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ControlCenterInner {
|
|
||||||
pub fn create_idle_pane(self: &Rc<Self>) -> IdlePane {
|
|
||||||
IdlePane {
|
|
||||||
state: self.state.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IdlePane {
|
|
||||||
pub fn title(&self, res: &mut String) {
|
|
||||||
res.push_str("Idle");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show(&mut self, ui: &mut Ui) {
|
|
||||||
grid(ui, "sliders", |ui| {
|
|
||||||
for interval in [true, false] {
|
|
||||||
let label = match interval {
|
|
||||||
true => "Interval",
|
|
||||||
false => "Grace period",
|
|
||||||
};
|
|
||||||
let idle = &self.state.idle;
|
|
||||||
let field = match interval {
|
|
||||||
true => &idle.timeout,
|
|
||||||
false => &idle.grace_period,
|
|
||||||
};
|
|
||||||
row(ui, label, |ui| {
|
|
||||||
let secs = field.get().as_secs();
|
|
||||||
let mut minutes = secs / 60;
|
|
||||||
let mut seconds = secs % 60;
|
|
||||||
let mut changed = false;
|
|
||||||
changed |= DragValue::new(&mut minutes).ui(ui).changed();
|
|
||||||
ui.label("minutes");
|
|
||||||
changed |= DragValue::new(&mut seconds).range(0..=59).ui(ui).changed();
|
|
||||||
ui.label("seconds");
|
|
||||||
if changed {
|
|
||||||
let duration =
|
|
||||||
Duration::from_secs(minutes.saturating_mul(60).saturating_add(seconds));
|
|
||||||
match interval {
|
|
||||||
true => idle.set_timeout(&self.state, duration),
|
|
||||||
false => idle.set_grace_period(&self.state, duration),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
let inhibitors = self.state.idle.inhibitors.lock();
|
|
||||||
let mut is: Vec<_> = inhibitors.values().collect();
|
|
||||||
is.sort_by_key(|is| is.inhibit_id);
|
|
||||||
CollapsingHeader::new(format!("Inhibitors ({})", is.len()))
|
|
||||||
.id_salt("Inhibitors")
|
|
||||||
.show(ui, |ui| {
|
|
||||||
for i in is {
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
ui.label(&i.client.pid_info.comm);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,685 +0,0 @@
|
||||||
use {
|
|
||||||
crate::{
|
|
||||||
backend::{InputDeviceCapability, InputDeviceId},
|
|
||||||
control_center::{
|
|
||||||
ControlCenterInner, GridExt, PaneState, bool, bool_ui, combo_box, combo_box_ui,
|
|
||||||
drag_value, drag_value_ui, grid, grid_label, grid_label_ui, label, text_edit, tip,
|
|
||||||
},
|
|
||||||
egui_adapter::egui_platform::icons::ICON_PENDING,
|
|
||||||
ifs::{
|
|
||||||
wl_output::WlOutputGlobal,
|
|
||||||
wl_seat::{SeatId, WlSeatGlobal},
|
|
||||||
},
|
|
||||||
kbvm::KbvmMap,
|
|
||||||
state::{DeviceHandlerData, State},
|
|
||||||
utils::{errorfmt::ErrorFmt, static_text::StaticText},
|
|
||||||
},
|
|
||||||
ahash::AHashMap,
|
|
||||||
egui::{
|
|
||||||
CollapsingHeader, ComboBox, DragValue, Event, Grid, Id, TextBuffer, TextFormat, Ui,
|
|
||||||
UiBuilder, ViewportCommand, Widget, emath::Numeric, text::LayoutJob,
|
|
||||||
},
|
|
||||||
isnt::std_1::string::IsntStringExt,
|
|
||||||
jay_config::keyboard::syms::KeySym,
|
|
||||||
kbvm::Keysym,
|
|
||||||
linearize::LinearizeExt,
|
|
||||||
rand::random,
|
|
||||||
std::{mem, rc::Rc},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct InputPane {
|
|
||||||
state: Rc<State>,
|
|
||||||
paste_requested: Option<Id>,
|
|
||||||
keymaps: AHashMap<Key, KeymapState>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
|
||||||
enum Key {
|
|
||||||
Seat(SeatId),
|
|
||||||
Dev(InputDeviceId),
|
|
||||||
}
|
|
||||||
|
|
||||||
struct KeymapState {
|
|
||||||
seed: u64,
|
|
||||||
rules_default: bool,
|
|
||||||
rules: String,
|
|
||||||
model_default: bool,
|
|
||||||
model: String,
|
|
||||||
layouts: String,
|
|
||||||
variants: String,
|
|
||||||
options: String,
|
|
||||||
backup: Option<Rc<KbvmMap>>,
|
|
||||||
pointer_revert_key: Keysym,
|
|
||||||
pointer_revert_key_str: Option<String>,
|
|
||||||
unknown_pointer_revert_key: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for KeymapState {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
seed: random(),
|
|
||||||
rules_default: true,
|
|
||||||
rules: Default::default(),
|
|
||||||
model_default: true,
|
|
||||||
model: Default::default(),
|
|
||||||
layouts: Default::default(),
|
|
||||||
variants: Default::default(),
|
|
||||||
options: Default::default(),
|
|
||||||
backup: Default::default(),
|
|
||||||
pointer_revert_key: Default::default(),
|
|
||||||
pointer_revert_key_str: None,
|
|
||||||
unknown_pointer_revert_key: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ControlCenterInner {
|
|
||||||
pub fn create_input_pane(self: &Rc<Self>) -> InputPane {
|
|
||||||
InputPane {
|
|
||||||
state: self.state.clone(),
|
|
||||||
paste_requested: Default::default(),
|
|
||||||
keymaps: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InputPane {
|
|
||||||
pub fn title(&self, res: &mut String) {
|
|
||||||
res.push_str("Input");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show(&mut self, ps: &mut PaneState, ui: &mut Ui) {
|
|
||||||
let state = self.state.clone();
|
|
||||||
let seats = state.globals.seats.lock();
|
|
||||||
let mut seats: Vec<_> = seats.values().collect();
|
|
||||||
seats.sort_by_key(|d| d.seat_name());
|
|
||||||
for seat in &seats {
|
|
||||||
self.show_seat(ps, ui, seat);
|
|
||||||
}
|
|
||||||
let outputs = state.globals.outputs.lock();
|
|
||||||
let mut outputs: Vec<_> = outputs.values().collect();
|
|
||||||
outputs.sort_by_key(|o| &o.connector.name);
|
|
||||||
let dev = &*state.input_device_handlers.borrow();
|
|
||||||
let mut dev: Vec<_> = dev.values().collect();
|
|
||||||
dev.sort_by_key(|d| d.data.device.name());
|
|
||||||
for dev in dev {
|
|
||||||
self.show_device(ps, ui, &dev.data, &seats, &outputs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn show_seat(&mut self, ps: &mut PaneState, ui: &mut Ui, seat: &Rc<WlSeatGlobal>) {
|
|
||||||
let mut layout_job = LayoutJob::default();
|
|
||||||
layout_job.append(
|
|
||||||
"Seat",
|
|
||||||
0.0,
|
|
||||||
TextFormat {
|
|
||||||
color: ui.style().visuals.widgets.inactive.text_color(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
);
|
|
||||||
layout_job.append(
|
|
||||||
seat.seat_name(),
|
|
||||||
10.0,
|
|
||||||
TextFormat {
|
|
||||||
color: ui.style().visuals.widgets.active.text_color(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
);
|
|
||||||
let ks = self.keymaps.entry(Key::Seat(seat.id())).or_default();
|
|
||||||
CollapsingHeader::new(layout_job)
|
|
||||||
.id_salt(("seat", seat.id()))
|
|
||||||
.show(ui, |ui| {
|
|
||||||
grid(ui, ("seat", seat.id()), |ui| {
|
|
||||||
let mut dv = |name: &str, get: &dyn Fn(&mut (i32, i32)) -> &mut i32| {
|
|
||||||
let ui = &mut *ui.row();
|
|
||||||
grid_label(ui, name);
|
|
||||||
let mut v = seat.get_rate();
|
|
||||||
let old = v;
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
let v = get(&mut v);
|
|
||||||
DragValue::new(v).range(0..=i32::MAX).ui(ui);
|
|
||||||
if ui.button("-20").clicked() {
|
|
||||||
*v = v.saturating_sub(20).max(0)
|
|
||||||
}
|
|
||||||
if ui.button("+20").clicked() {
|
|
||||||
*v = v.saturating_add(20);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if v != old {
|
|
||||||
seat.set_rate(v.0, v.1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
dv("Repeat Rate", &|v| &mut v.0);
|
|
||||||
dv("Repeat Delay", &|v| &mut v.1);
|
|
||||||
drag_value(
|
|
||||||
ui,
|
|
||||||
"Cursor Size",
|
|
||||||
seat.cursor_group().cursor_size(),
|
|
||||||
0..=u32::MAX,
|
|
||||||
1.0,
|
|
||||||
|v| seat.cursor_group().set_cursor_size(v),
|
|
||||||
);
|
|
||||||
bool_ui(
|
|
||||||
ui,
|
|
||||||
"Simple IM",
|
|
||||||
|ui| {
|
|
||||||
tip(ui, |ui| {
|
|
||||||
ui.label("A simple input method based on Xcompose files.");
|
|
||||||
ui.label(concat!(
|
|
||||||
"If you're not using another input method, you should ",
|
|
||||||
"leave this enabled as it will work for sandboxed ",
|
|
||||||
"applications, which regular Xcompose will not.",
|
|
||||||
));
|
|
||||||
ui.label(concat!(
|
|
||||||
"The `enable-unicode-input` action can be used to input ",
|
|
||||||
"characters by their unicode value.",
|
|
||||||
));
|
|
||||||
});
|
|
||||||
},
|
|
||||||
seat.simple_im_enabled(),
|
|
||||||
|b| seat.set_simple_im_enabled(b),
|
|
||||||
);
|
|
||||||
bool_ui(
|
|
||||||
ui,
|
|
||||||
"Hardware Cursor",
|
|
||||||
|ui| {
|
|
||||||
tip(ui, |ui| {
|
|
||||||
ui.label(
|
|
||||||
"Allow this seat to use the hardware cursor, if available.",
|
|
||||||
);
|
|
||||||
ui.label("Only one seat can use the hardware cursor at a time.");
|
|
||||||
});
|
|
||||||
},
|
|
||||||
seat.cursor_group().hardware_cursor(),
|
|
||||||
|b| seat.cursor_group().set_hardware_cursor(b),
|
|
||||||
);
|
|
||||||
{
|
|
||||||
let ui = &mut *ui.row();
|
|
||||||
let v = seat.pointer_revert_key();
|
|
||||||
let v = Keysym(v.0);
|
|
||||||
if mem::replace(&mut ks.pointer_revert_key, v) != v {
|
|
||||||
ks.pointer_revert_key_str = None;
|
|
||||||
}
|
|
||||||
let name = ks
|
|
||||||
.pointer_revert_key_str
|
|
||||||
.get_or_insert_with(|| v.name().unwrap_or_default().to_string());
|
|
||||||
grid_label_ui(ui, |ui| {
|
|
||||||
ui.label("Pointer Revert Key");
|
|
||||||
tip(ui, |ui| {
|
|
||||||
ui.label(concat!(
|
|
||||||
"Pressing this key reverts the pointer to the default state, ",
|
|
||||||
"breaking grabs, drags, etc.",
|
|
||||||
));
|
|
||||||
ui.label(
|
|
||||||
"Setting this to `NoSymbol` effectively disables this feature.",
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
if ui.text_edit_singleline(name).changed() {
|
|
||||||
let v = Keysym::from_str(name);
|
|
||||||
ks.unknown_pointer_revert_key = v.is_none();
|
|
||||||
if let Some(v) = v {
|
|
||||||
ks.pointer_revert_key = v;
|
|
||||||
seat.set_pointer_revert_key(KeySym(v.0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ks.unknown_pointer_revert_key {
|
|
||||||
ui.label("Error: Unknown key");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
bool(ui, "Focus Follows Mouse", seat.focus_follows_mouse(), |v| {
|
|
||||||
seat.set_focus_follows_mouse(v);
|
|
||||||
});
|
|
||||||
bool(ui, "Mouse Follows Focus", seat.mouse_follows_focus(), |v| {
|
|
||||||
seat.set_mouse_follows_focus(v);
|
|
||||||
});
|
|
||||||
combo_box_ui(
|
|
||||||
ui,
|
|
||||||
"Fallback Output Mode",
|
|
||||||
|ui| {
|
|
||||||
tip(ui, |ui| {
|
|
||||||
ui.label(concat!(
|
|
||||||
"This determines the output to use in operations where no ",
|
|
||||||
"output is explicitly specified.",
|
|
||||||
));
|
|
||||||
ui.label(concat!(
|
|
||||||
"For example, when a new window is opened, this determines ",
|
|
||||||
"where the window will be opened.",
|
|
||||||
));
|
|
||||||
ui.label("`Cursor` refers to the output that contains the cursor.");
|
|
||||||
ui.label(
|
|
||||||
"`Focus` refers to the output that has the keyboard focus.",
|
|
||||||
);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
seat.fallback_output_mode(),
|
|
||||||
|v| seat.set_fallback_output_mode(v),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
ui.label("Focus History");
|
|
||||||
ui.indent("focus-history", |ui| {
|
|
||||||
let mut v = seat.focus_history_visible();
|
|
||||||
if ui.checkbox(&mut v, "Only Visible").changed() {
|
|
||||||
seat.focus_history_set_visible(v);
|
|
||||||
}
|
|
||||||
let mut v = seat.focus_history_same_workspace();
|
|
||||||
if ui.checkbox(&mut v, "Same Workspace").changed() {
|
|
||||||
seat.focus_history_set_same_workspace(v);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if ui.button("Reload Simple IM").clicked() {
|
|
||||||
seat.reload_simple_im();
|
|
||||||
}
|
|
||||||
show_keymap(
|
|
||||||
&self.state,
|
|
||||||
ps,
|
|
||||||
&mut self.paste_requested,
|
|
||||||
ks,
|
|
||||||
ui,
|
|
||||||
Some(&seat.keymap()),
|
|
||||||
|m| seat.set_seat_keymap(m),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn show_device(
|
|
||||||
&mut self,
|
|
||||||
ps: &mut PaneState,
|
|
||||||
ui: &mut Ui,
|
|
||||||
dev: &Rc<DeviceHandlerData>,
|
|
||||||
seats: &[&Rc<WlSeatGlobal>],
|
|
||||||
outputs: &[&Rc<WlOutputGlobal>],
|
|
||||||
) {
|
|
||||||
let mut layout_job = LayoutJob::default();
|
|
||||||
layout_job.append(
|
|
||||||
"Device",
|
|
||||||
0.0,
|
|
||||||
TextFormat {
|
|
||||||
color: ui.style().visuals.widgets.inactive.text_color(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
);
|
|
||||||
layout_job.append(
|
|
||||||
&dev.device.name(),
|
|
||||||
10.0,
|
|
||||||
TextFormat {
|
|
||||||
color: ui.style().visuals.widgets.active.text_color(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
);
|
|
||||||
let dev_id = dev.device.id();
|
|
||||||
CollapsingHeader::new(layout_job)
|
|
||||||
.id_salt(("device", dev_id))
|
|
||||||
.show(ui, |ui| {
|
|
||||||
grid(ui, ("device", dev_id), |ui| {
|
|
||||||
{
|
|
||||||
let old = dev.seat.get();
|
|
||||||
let ui = &mut *ui.row();
|
|
||||||
grid_label(ui, "Seat");
|
|
||||||
let mut seat = old.as_ref();
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
let mut cb = ComboBox::from_id_salt("seat");
|
|
||||||
if let Some(seat) = seat {
|
|
||||||
cb = cb.selected_text(seat.seat_name());
|
|
||||||
}
|
|
||||||
cb.show_ui(ui, |ui| {
|
|
||||||
for s in seats {
|
|
||||||
ui.selectable_value(&mut seat, Some(s), s.seat_name());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if ui.button("Detach").clicked() {
|
|
||||||
seat = None;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if seat != old.as_ref() {
|
|
||||||
dev.set_seat(&self.state, seat.cloned());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
macro_rules! string {
|
|
||||||
($field:ident, $name:expr) => {
|
|
||||||
if let Some(v) = &dev.$field {
|
|
||||||
label(ui, $name, v);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
string!(syspath, "Syspath");
|
|
||||||
string!(devnode, "Devnode");
|
|
||||||
{
|
|
||||||
let ui = &mut *ui.row();
|
|
||||||
grid_label(ui, "Capabilities");
|
|
||||||
let mut s = String::new();
|
|
||||||
for cap in InputDeviceCapability::variants() {
|
|
||||||
if dev.device.has_capability(cap) {
|
|
||||||
if s.is_not_empty() {
|
|
||||||
s.push_str(" | ");
|
|
||||||
}
|
|
||||||
s.push_str(cap.text());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ui.label(s);
|
|
||||||
}
|
|
||||||
if let Some(old) = dev.device.natural_scrolling_enabled() {
|
|
||||||
bool(ui, "Natural Scrolling", old, |v| {
|
|
||||||
dev.set_natural_scrolling_enabled(&self.state, v)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if dev.device.has_capability(InputDeviceCapability::Pointer) {
|
|
||||||
drag_value_ui(
|
|
||||||
ui,
|
|
||||||
"Scroll Distance (px)",
|
|
||||||
|ui| {
|
|
||||||
tip(ui, |ui| {
|
|
||||||
ui.label(concat!(
|
|
||||||
"This only applies to applications that use the ",
|
|
||||||
"legacy px scrolling events.",
|
|
||||||
));
|
|
||||||
});
|
|
||||||
},
|
|
||||||
dev.px_per_scroll_wheel.get(),
|
|
||||||
-f64::INFINITY..=f64::INFINITY,
|
|
||||||
0.1,
|
|
||||||
|v| dev.set_px_per_scroll_wheel(&self.state, v),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if let Some(old) = dev.device.accel_profile() {
|
|
||||||
combo_box(ui, "Accel Profile", old, |v| {
|
|
||||||
dev.set_accel_profile(&self.state, v)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if let Some(old) = dev.device.accel_speed() {
|
|
||||||
drag_value(ui, "Accel Speed", old, -1.0..=1.0, 0.01, |v| {
|
|
||||||
dev.set_accel_speed(&self.state, v)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if let Some(old) = dev.device.click_method() {
|
|
||||||
combo_box(ui, "Click Method", old, |v| {
|
|
||||||
dev.set_click_method(&self.state, v)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if let Some(old) = dev.device.tap_enabled() {
|
|
||||||
bool(ui, "Tap Enabled", old, |v| {
|
|
||||||
dev.set_tap_enabled(&self.state, v)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if let Some(old) = dev.device.drag_enabled() {
|
|
||||||
bool(ui, "Tap Drag Enabled", old, |v| {
|
|
||||||
dev.set_drag_enabled(&self.state, v)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if let Some(old) = dev.device.drag_lock_enabled() {
|
|
||||||
bool(ui, "Tap Drag Lock Enabled", old, |v| {
|
|
||||||
dev.set_drag_lock_enabled(&self.state, v)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if let Some(old) = dev.device.left_handed() {
|
|
||||||
bool(ui, "Left Handed", old, |v| {
|
|
||||||
dev.set_left_handed(&self.state, v)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if let Some(old) = dev.device.middle_button_emulation_enabled() {
|
|
||||||
bool(ui, "Middle Button Emulation", old, |v| {
|
|
||||||
dev.set_middle_button_emulation_enabled(&self.state, v)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
{
|
|
||||||
let ui = &mut *ui.row();
|
|
||||||
grid_label_ui(ui, |ui| {
|
|
||||||
ui.label("Output");
|
|
||||||
tip(ui, |ui| {
|
|
||||||
ui.label("This applies to touch and tablet input.");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
let old = dev.output.get().and_then(|v| v.global.get());
|
|
||||||
let old = old.as_ref();
|
|
||||||
let mut v = old;
|
|
||||||
let mut cb = ComboBox::from_id_salt("output");
|
|
||||||
if let Some(v) = v {
|
|
||||||
cb = cb.selected_text(&*v.connector.name);
|
|
||||||
}
|
|
||||||
cb.show_ui(ui, |ui| {
|
|
||||||
for &output in outputs {
|
|
||||||
ui.selectable_value(
|
|
||||||
&mut v,
|
|
||||||
Some(output),
|
|
||||||
&*output.connector.name,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if v != old {
|
|
||||||
dev.set_output(&self.state, v.map(|v| &**v));
|
|
||||||
}
|
|
||||||
if ui.button("Detach").clicked() {
|
|
||||||
dev.set_output(&self.state, None);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
matrix_ui(
|
|
||||||
ui,
|
|
||||||
"Transform Matrix",
|
|
||||||
|ui| {
|
|
||||||
tip(ui, |ui| {
|
|
||||||
ui.label("This matrix is applied to relative pointer movements.");
|
|
||||||
});
|
|
||||||
},
|
|
||||||
dev.device
|
|
||||||
.has_capability(InputDeviceCapability::Pointer)
|
|
||||||
.then(|| {
|
|
||||||
dev.device
|
|
||||||
.transform_matrix()
|
|
||||||
.unwrap_or([[1.0, 0.0], [0.0, 1.0]])
|
|
||||||
}),
|
|
||||||
|v| dev.set_transform_matrix(&self.state, v),
|
|
||||||
);
|
|
||||||
matrix(
|
|
||||||
ui,
|
|
||||||
"Calibration Matrix",
|
|
||||||
dev.device.calibration_matrix(),
|
|
||||||
|v| dev.set_calibration_matrix(&self.state, v),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
if dev.device.has_capability(InputDeviceCapability::Keyboard) {
|
|
||||||
ui.collapsing("Device Keymap", |ui| {
|
|
||||||
let ks = self.keymaps.entry(Key::Dev(dev_id)).or_default();
|
|
||||||
let map = dev.keymap.get();
|
|
||||||
ui.add_enabled_ui(map.is_some(), |ui| {
|
|
||||||
if ui.button("Use Seat Keymap").clicked() {
|
|
||||||
ks.backup(map.as_ref());
|
|
||||||
dev.set_keymap(&self.state, None);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
show_keymap(
|
|
||||||
&self.state,
|
|
||||||
ps,
|
|
||||||
&mut self.paste_requested,
|
|
||||||
ks,
|
|
||||||
ui,
|
|
||||||
map.as_ref(),
|
|
||||||
|m| {
|
|
||||||
dev.set_keymap(&self.state, Some(m.clone()));
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl KeymapState {
|
|
||||||
fn backup(&mut self, map: Option<&Rc<KbvmMap>>) {
|
|
||||||
if self.backup.is_none()
|
|
||||||
&& let Some(map) = map
|
|
||||||
{
|
|
||||||
self.backup = Some(map.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn show_keymap(
|
|
||||||
state: &State,
|
|
||||||
ps: &mut PaneState,
|
|
||||||
paste_requested: &mut Option<Id>,
|
|
||||||
ks: &mut KeymapState,
|
|
||||||
ui: &mut Ui,
|
|
||||||
map: Option<&Rc<KbvmMap>>,
|
|
||||||
set_map: impl Fn(&Rc<KbvmMap>),
|
|
||||||
) {
|
|
||||||
ui.scope_builder(
|
|
||||||
UiBuilder::new().id(Id::new(("keymap-settings", ks.seed))),
|
|
||||||
|ui| {
|
|
||||||
ui.add_enabled_ui(map.is_some(), |ui| {
|
|
||||||
if ui.button("Copy Keymap").clicked()
|
|
||||||
&& let Some(map) = map
|
|
||||||
{
|
|
||||||
ui.copy_text(map.map_text.clone());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
let backup = |ks: &mut KeymapState| {
|
|
||||||
ks.backup(map);
|
|
||||||
};
|
|
||||||
if ui.button("Load Default Keymap").clicked() {
|
|
||||||
backup(ks);
|
|
||||||
set_map(&state.default_keymap);
|
|
||||||
}
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
ui.add_enabled_ui(map.is_some(), |ui| {
|
|
||||||
if ui.button("Backup Keymap").clicked() {
|
|
||||||
ks.backup = None;
|
|
||||||
backup(ks);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if let Some(backup) = &ks.backup
|
|
||||||
&& ui.button("Restore Keymap").clicked()
|
|
||||||
{
|
|
||||||
set_map(backup);
|
|
||||||
ks.backup = None;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
let mut label = "Load Keymap from Clipboard".to_string();
|
|
||||||
if *paste_requested == Some(ui.id()) {
|
|
||||||
label.push_str(" ");
|
|
||||||
label.push_str(ICON_PENDING);
|
|
||||||
}
|
|
||||||
let button = ui.button(label);
|
|
||||||
if button.clicked() {
|
|
||||||
*paste_requested = Some(ui.id());
|
|
||||||
button.request_focus();
|
|
||||||
ui.send_viewport_cmd(ViewportCommand::RequestPaste);
|
|
||||||
} else if *paste_requested == Some(ui.id()) && button.has_focus() {
|
|
||||||
ui.input(|e| {
|
|
||||||
let map = e
|
|
||||||
.events
|
|
||||||
.iter()
|
|
||||||
.filter_map(|e| match e {
|
|
||||||
Event::Paste(s) => Some(s),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.next();
|
|
||||||
let Some(map) = map else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
*paste_requested = None;
|
|
||||||
let map = match state.kb_ctx.parse_keymap(map.as_bytes()) {
|
|
||||||
Ok(m) => m,
|
|
||||||
Err(e) => {
|
|
||||||
let error = format!("Could not parse keymap: {}", ErrorFmt(e));
|
|
||||||
ps.errors.push(error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
backup(ks);
|
|
||||||
set_map(&map);
|
|
||||||
});
|
|
||||||
} else if *paste_requested == Some(ui.id()) {
|
|
||||||
*paste_requested = None;
|
|
||||||
}
|
|
||||||
ui.collapsing("Create Keymap from Names", |ui| {
|
|
||||||
grid(ui, ("keymap-from-names", ui.id()), |ui| {
|
|
||||||
let defaulted =
|
|
||||||
|ui: &mut Ui, name: &str, default: &mut bool, text: &mut dyn TextBuffer| {
|
|
||||||
let ui = &mut *ui.row();
|
|
||||||
grid_label(ui, name);
|
|
||||||
ui.add_enabled_ui(!*default, |ui| {
|
|
||||||
text_edit(ui, text);
|
|
||||||
});
|
|
||||||
ui.checkbox(default, "Default");
|
|
||||||
};
|
|
||||||
let required = |ui: &mut Ui, name, text| {
|
|
||||||
let ui = &mut *ui.row();
|
|
||||||
grid_label(ui, name);
|
|
||||||
text_edit(ui, text);
|
|
||||||
};
|
|
||||||
defaulted(ui, "Rules", &mut ks.rules_default, &mut ks.rules);
|
|
||||||
defaulted(ui, "Model", &mut ks.model_default, &mut ks.model);
|
|
||||||
required(ui, "Layouts", &mut ks.layouts);
|
|
||||||
required(ui, "Variants", &mut ks.variants);
|
|
||||||
required(ui, "Options", &mut ks.options);
|
|
||||||
});
|
|
||||||
if ui.button("Load").clicked() {
|
|
||||||
'set_map: {
|
|
||||||
let map = state.kb_ctx.keymap_from_rmlvo(
|
|
||||||
(!ks.rules_default).then_some(&ks.rules),
|
|
||||||
(!ks.model_default).then_some(&ks.model),
|
|
||||||
Some(&ks.layouts),
|
|
||||||
Some(&ks.variants),
|
|
||||||
Some(&ks.options),
|
|
||||||
);
|
|
||||||
let map = match map {
|
|
||||||
Ok(map) => map,
|
|
||||||
Err(e) => {
|
|
||||||
let error = format!("Could not parse keymap: {}", ErrorFmt(e));
|
|
||||||
ps.errors.push(error);
|
|
||||||
break 'set_map;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
backup(ks);
|
|
||||||
set_map(&map);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn matrix<T, const W: usize>(
|
|
||||||
ui: &mut Ui,
|
|
||||||
name: &str,
|
|
||||||
old: Option<[[T; W]; 2]>,
|
|
||||||
set: impl FnOnce([[T; W]; 2]),
|
|
||||||
) where
|
|
||||||
T: Numeric,
|
|
||||||
{
|
|
||||||
matrix_ui(ui, name, |_| (), old, set);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn matrix_ui<R, T, const W: usize>(
|
|
||||||
ui: &mut Ui,
|
|
||||||
name: &str,
|
|
||||||
label: impl FnOnce(&mut Ui) -> R,
|
|
||||||
old: Option<[[T; W]; 2]>,
|
|
||||||
set: impl FnOnce([[T; W]; 2]),
|
|
||||||
) where
|
|
||||||
T: Numeric,
|
|
||||||
{
|
|
||||||
if let Some(mut m) = old {
|
|
||||||
let old = m;
|
|
||||||
let ui = &mut *ui.row();
|
|
||||||
grid_label_ui(ui, |ui| {
|
|
||||||
ui.label(name);
|
|
||||||
label(ui);
|
|
||||||
});
|
|
||||||
Grid::new(name).show(ui, |ui| {
|
|
||||||
for row in &mut m {
|
|
||||||
for cell in row {
|
|
||||||
DragValue::new(cell).speed(0.01).ui(ui);
|
|
||||||
}
|
|
||||||
ui.end_row();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if old != m {
|
|
||||||
set(m);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,163 +0,0 @@
|
||||||
use {
|
|
||||||
crate::{
|
|
||||||
cmm::cmm_eotf::Eotf,
|
|
||||||
control_center::{
|
|
||||||
ControlCenterInner, bool, bool_ui, combo_box, drag_value, grid, grid_label, row,
|
|
||||||
text_edit, tip,
|
|
||||||
},
|
|
||||||
gfx_api::AlphaMode,
|
|
||||||
state::State,
|
|
||||||
theme::{Color, ThemeColor, ThemeSized},
|
|
||||||
utils::static_text::StaticText,
|
|
||||||
},
|
|
||||||
egui::Ui,
|
|
||||||
isnt::std_1::primitive::IsntStrExt,
|
|
||||||
linearize::LinearizeExt,
|
|
||||||
std::rc::Rc,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct LookAndFeelPane {
|
|
||||||
state: Rc<State>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ControlCenterInner {
|
|
||||||
pub fn create_look_and_feel_pane(self: &Rc<Self>) -> LookAndFeelPane {
|
|
||||||
LookAndFeelPane {
|
|
||||||
state: self.state.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LookAndFeelPane {
|
|
||||||
pub fn title(&self, res: &mut String) {
|
|
||||||
res.push_str("Look and Feel");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show(&mut self, ui: &mut Ui) {
|
|
||||||
let t = &self.state.theme;
|
|
||||||
grid(ui, "settings", |ui| {
|
|
||||||
bool(ui, "Show Bar", self.state.show_bar.get(), |v| {
|
|
||||||
self.state.set_show_bar(v)
|
|
||||||
});
|
|
||||||
combo_box(ui, "Bar Position", t.bar_position.get(), |p| {
|
|
||||||
self.state.set_bar_position(p);
|
|
||||||
});
|
|
||||||
bool(ui, "Show Titles", t.show_titles.get(), |v| {
|
|
||||||
self.state.set_show_titles(v)
|
|
||||||
});
|
|
||||||
bool_ui(
|
|
||||||
ui,
|
|
||||||
"Primary Selection",
|
|
||||||
|ui| {
|
|
||||||
tip(ui, |ui| {
|
|
||||||
ui.label("Requires applications to be restarted.");
|
|
||||||
});
|
|
||||||
},
|
|
||||||
self.state.enable_primary_selection.get(),
|
|
||||||
|v| self.state.set_primary_selection_enabled(v),
|
|
||||||
);
|
|
||||||
bool_ui(
|
|
||||||
ui,
|
|
||||||
"UI Drag",
|
|
||||||
|ui| {
|
|
||||||
tip(ui, |ui| {
|
|
||||||
ui.label("Allows dragging workspaces and tiled windows with the mouse.");
|
|
||||||
});
|
|
||||||
},
|
|
||||||
self.state.ui_drag_enabled.get(),
|
|
||||||
|v| self.state.set_ui_drag_enabled(v),
|
|
||||||
);
|
|
||||||
drag_value(
|
|
||||||
ui,
|
|
||||||
"UI Drag Threshold (px)",
|
|
||||||
self.state.ui_drag_threshold_squared.get().isqrt(),
|
|
||||||
1..=i32::MAX,
|
|
||||||
1.0,
|
|
||||||
|v| {
|
|
||||||
self.state.set_ui_drag_threshold(v);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
bool_ui(
|
|
||||||
ui,
|
|
||||||
"Float Pin Icon",
|
|
||||||
|ui| {
|
|
||||||
tip(ui, |ui| {
|
|
||||||
ui.label("Show the pin icon even if the window is not pinned.");
|
|
||||||
ui.label("Pinned floating windows are shown on all workspaces.");
|
|
||||||
});
|
|
||||||
},
|
|
||||||
self.state.show_pin_icon.get(),
|
|
||||||
|v| self.state.set_show_pin_icon(v),
|
|
||||||
);
|
|
||||||
bool_ui(
|
|
||||||
ui,
|
|
||||||
"Float Above Fullscreen",
|
|
||||||
|ui| {
|
|
||||||
tip(ui, |ui| {
|
|
||||||
ui.label("Show floating windows above fullscreen windows.");
|
|
||||||
});
|
|
||||||
},
|
|
||||||
self.state.float_above_fullscreen.get(),
|
|
||||||
|v| self.state.set_float_above_fullscreen(v),
|
|
||||||
);
|
|
||||||
row(ui, "Font", |ui| {
|
|
||||||
let mut v = self.state.theme.font.get().to_string();
|
|
||||||
if text_edit(ui, &mut v).changed() {
|
|
||||||
self.state.set_font(&v);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
row(ui, "Title Font", |ui| {
|
|
||||||
let mut v = t
|
|
||||||
.title_font
|
|
||||||
.get()
|
|
||||||
.map(|v| v.to_string())
|
|
||||||
.unwrap_or_default();
|
|
||||||
if text_edit(ui, &mut v).changed() {
|
|
||||||
self.state.set_title_font(v.is_not_empty().then_some(&v));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
row(ui, "Bar Font", |ui| {
|
|
||||||
let mut v = t.bar_font.get().map(|v| v.to_string()).unwrap_or_default();
|
|
||||||
if text_edit(ui, &mut v).changed() {
|
|
||||||
self.state.set_bar_font(v.is_not_empty().then_some(&v));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
if ui.button("Reset Sizes").clicked() {
|
|
||||||
self.state.reset_sizes();
|
|
||||||
}
|
|
||||||
if ui.button("Reset Colors").clicked() {
|
|
||||||
self.state.reset_colors();
|
|
||||||
}
|
|
||||||
if ui.button("Reset Fonts").clicked() {
|
|
||||||
self.state.reset_fonts();
|
|
||||||
}
|
|
||||||
ui.collapsing("Sizes", |ui| {
|
|
||||||
grid(ui, "Sizes", |ui| {
|
|
||||||
for v in ThemeSized::variants() {
|
|
||||||
let f = v.field(&self.state.theme);
|
|
||||||
drag_value(ui, v.text(), f.get(), v.min()..=v.max(), 1.0, |i| {
|
|
||||||
self.state.set_size(v, i);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
ui.collapsing("Colors", |ui| {
|
|
||||||
grid(ui, "Colors", |ui| {
|
|
||||||
for tc in ThemeColor::variants() {
|
|
||||||
let f = tc.field(t);
|
|
||||||
let mut v = f.get().to_array(Eotf::Linear);
|
|
||||||
grid_label(ui, tc.text());
|
|
||||||
let changed = ui.color_edit_button_rgba_premultiplied(&mut v).changed();
|
|
||||||
ui.end_row();
|
|
||||||
if changed {
|
|
||||||
let [r, g, b, a] = v;
|
|
||||||
let c =
|
|
||||||
Color::new(Eotf::Linear, AlphaMode::PremultipliedOptical, r, g, b, a);
|
|
||||||
self.state.set_color(tc, c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,97 +0,0 @@
|
||||||
use {
|
|
||||||
crate::control_center::{ControlCenterInner, Pane, PaneType},
|
|
||||||
egui::{Align, Layout, ScrollArea, Ui, ViewportCommand},
|
|
||||||
egui_tiles::Tree,
|
|
||||||
linearize::{Linearize, LinearizeExt},
|
|
||||||
std::{rc::Rc, sync::LazyLock},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Linearize)]
|
|
||||||
enum PaneName {
|
|
||||||
Compositor,
|
|
||||||
Idle,
|
|
||||||
ColorManagement,
|
|
||||||
Xwayland,
|
|
||||||
Outputs,
|
|
||||||
GPUs,
|
|
||||||
Input,
|
|
||||||
LookAndFeel,
|
|
||||||
Clients,
|
|
||||||
WindowSearch,
|
|
||||||
VirtualOutputs,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PaneName {
|
|
||||||
fn name(self) -> &'static str {
|
|
||||||
match self {
|
|
||||||
PaneName::Compositor => "Compositor",
|
|
||||||
PaneName::Idle => "Idle",
|
|
||||||
PaneName::ColorManagement => "Color Management",
|
|
||||||
PaneName::Xwayland => "Xwayland",
|
|
||||||
PaneName::Outputs => "Outputs",
|
|
||||||
PaneName::GPUs => "GPUs",
|
|
||||||
PaneName::Input => "Input",
|
|
||||||
PaneName::LookAndFeel => "Look and Feel",
|
|
||||||
PaneName::Clients => "Clients",
|
|
||||||
PaneName::WindowSearch => "Window Search",
|
|
||||||
PaneName::VirtualOutputs => "Virtual Outputs",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static TYPES: LazyLock<Vec<PaneName>> = LazyLock::new(|| {
|
|
||||||
let mut res: Vec<_> = PaneName::variants().collect();
|
|
||||||
res.sort_by_key(|t| t.name());
|
|
||||||
res
|
|
||||||
});
|
|
||||||
|
|
||||||
impl ControlCenterInner {
|
|
||||||
pub fn show_sidebar(self: &Rc<Self>, tree: &mut Tree<Pane>, ui: &mut Ui) {
|
|
||||||
ui.with_layout(
|
|
||||||
Layout::top_down(Align::Center).with_cross_justify(true),
|
|
||||||
|ui| {
|
|
||||||
ui.add_space(6.0);
|
|
||||||
if ui.button("Close").clicked() {
|
|
||||||
ui.send_viewport_cmd(ViewportCommand::Close);
|
|
||||||
}
|
|
||||||
ui.separator();
|
|
||||||
ScrollArea::vertical().show(ui, |ui| {
|
|
||||||
for &ty in &*TYPES {
|
|
||||||
if ui.button(ty.name()).clicked() {
|
|
||||||
let ty = match ty {
|
|
||||||
PaneName::Compositor => {
|
|
||||||
PaneType::Compositor(self.create_compositor_pane())
|
|
||||||
}
|
|
||||||
PaneName::Idle => PaneType::Idle(self.create_idle_pane()),
|
|
||||||
PaneName::ColorManagement => {
|
|
||||||
PaneType::ColorManagement(self.create_color_management_pane())
|
|
||||||
}
|
|
||||||
PaneName::Xwayland => {
|
|
||||||
PaneType::Xwayland(self.create_xwayland_pane())
|
|
||||||
}
|
|
||||||
PaneName::Outputs => {
|
|
||||||
PaneType::Outputs(Box::new(self.create_outputs_pane()))
|
|
||||||
}
|
|
||||||
PaneName::GPUs => PaneType::GPUs(self.create_gpus_pane()),
|
|
||||||
PaneName::Input => PaneType::Input(self.create_input_pane()),
|
|
||||||
PaneName::LookAndFeel => {
|
|
||||||
PaneType::LookAndFeel(self.create_look_and_feel_pane())
|
|
||||||
}
|
|
||||||
PaneName::Clients => PaneType::Clients(self.create_clients_pane()),
|
|
||||||
PaneName::WindowSearch => {
|
|
||||||
PaneType::WindowSearch(self.create_window_search_pane())
|
|
||||||
}
|
|
||||||
PaneName::VirtualOutputs => {
|
|
||||||
PaneType::VirtualOutputs(self.create_virtual_outputs_pane())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
self.open(tree, ty);
|
|
||||||
ui.request_repaint();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ui.add_space(3.0);
|
|
||||||
})
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
use {
|
|
||||||
crate::{
|
|
||||||
control_center::ControlCenterInner, egui_adapter::egui_platform::icons::ICON_CLOSE,
|
|
||||||
state::State,
|
|
||||||
},
|
|
||||||
egui::Ui,
|
|
||||||
std::rc::Rc,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct VirtualOutputsPane {
|
|
||||||
state: Rc<State>,
|
|
||||||
new: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ControlCenterInner {
|
|
||||||
pub fn create_virtual_outputs_pane(self: &Rc<Self>) -> VirtualOutputsPane {
|
|
||||||
VirtualOutputsPane {
|
|
||||||
state: self.state.clone(),
|
|
||||||
new: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VirtualOutputsPane {
|
|
||||||
pub fn title(&self, res: &mut String) {
|
|
||||||
res.push_str("Virtual Outputs");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show(&mut self, ui: &mut Ui) {
|
|
||||||
let s = &self.state;
|
|
||||||
let mut outputs: Vec<_> = s.virtual_outputs.outputs.lock().keys().cloned().collect();
|
|
||||||
outputs.sort();
|
|
||||||
for o in &outputs {
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
if ui.button(ICON_CLOSE).clicked() {
|
|
||||||
s.virtual_outputs.remove_output(s, o);
|
|
||||||
}
|
|
||||||
ui.label(o);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
ui.text_edit_singleline(&mut self.new);
|
|
||||||
if ui.button("Add").clicked() {
|
|
||||||
s.virtual_outputs.get_or_create(s, &self.new);
|
|
||||||
ui.request_repaint();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,475 +0,0 @@
|
||||||
use {
|
|
||||||
crate::{
|
|
||||||
control_center::{
|
|
||||||
CcBehavior, ControlCenterInner, PaneType,
|
|
||||||
cc_clients::{ClientCrit, show_client_collapsible},
|
|
||||||
cc_criterion::{CcCriterion, CritImpl, CritRegex},
|
|
||||||
grid, icon_label, label, read_only_bool,
|
|
||||||
},
|
|
||||||
criteria::{CritMgrExt, CritUpstreamNode, crit_leaf::CritLeafMatcher},
|
|
||||||
egui_adapter::egui_platform::icons::ICON_OPEN_IN_NEW,
|
|
||||||
state::State,
|
|
||||||
tree::{NodeId, ToplevelData, ToplevelIdentifier, ToplevelNode, ToplevelType},
|
|
||||||
utils::{
|
|
||||||
copyhashmap::CopyHashMap,
|
|
||||||
event_listener::{EventListener, LazyEventSourceListener},
|
|
||||||
static_text::StaticText,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
ahash::AHashMap,
|
|
||||||
egui::{CollapsingHeader, Sense, TextFormat, Ui, Widget, cache::CacheTrait, text::LayoutJob},
|
|
||||||
isnt::std_1::primitive::IsntStrExt,
|
|
||||||
jay_config::window::{
|
|
||||||
ContentType, GAME_CONTENT, NO_CONTENT_TYPE, PHOTO_CONTENT, VIDEO_CONTENT,
|
|
||||||
},
|
|
||||||
linearize::Linearize,
|
|
||||||
std::{
|
|
||||||
mem,
|
|
||||||
rc::{Rc, Weak},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
enum WindowClit {
|
|
||||||
Client(CcCriterion<ClientCrit>),
|
|
||||||
Title(CritRegex),
|
|
||||||
AppId(CritRegex),
|
|
||||||
Floating,
|
|
||||||
Visible,
|
|
||||||
Urgent,
|
|
||||||
Fullscreen,
|
|
||||||
Tag(CritRegex),
|
|
||||||
XClass(CritRegex),
|
|
||||||
XInstance(CritRegex),
|
|
||||||
XRole(CritRegex),
|
|
||||||
Workspace(CritRegex),
|
|
||||||
ContentTypes(ContentType),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Linearize)]
|
|
||||||
enum WindowCritTy {
|
|
||||||
Client,
|
|
||||||
Title,
|
|
||||||
AppId,
|
|
||||||
Floating,
|
|
||||||
Visible,
|
|
||||||
Urgent,
|
|
||||||
Fullscreen,
|
|
||||||
Tag,
|
|
||||||
XClass,
|
|
||||||
XInstance,
|
|
||||||
XRole,
|
|
||||||
Workspace,
|
|
||||||
ContentTypes,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for WindowClit {
|
|
||||||
fn default() -> Self {
|
|
||||||
WindowClit::Title(Default::default())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StaticText for WindowCritTy {
|
|
||||||
fn text(&self) -> &'static str {
|
|
||||||
match self {
|
|
||||||
WindowCritTy::Client => "Client",
|
|
||||||
WindowCritTy::Title => "Title",
|
|
||||||
WindowCritTy::AppId => "App ID",
|
|
||||||
WindowCritTy::Floating => "Floating",
|
|
||||||
WindowCritTy::Visible => "Visible",
|
|
||||||
WindowCritTy::Urgent => "Urgent",
|
|
||||||
WindowCritTy::Fullscreen => "Fullscreen",
|
|
||||||
WindowCritTy::Tag => "Tag",
|
|
||||||
WindowCritTy::XClass => "X Class",
|
|
||||||
WindowCritTy::XInstance => "X Instance",
|
|
||||||
WindowCritTy::XRole => "X Role",
|
|
||||||
WindowCritTy::Workspace => "Workspace",
|
|
||||||
WindowCritTy::ContentTypes => "Content Types",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CritImpl for WindowClit {
|
|
||||||
type Type = WindowCritTy;
|
|
||||||
type Target = ToplevelData;
|
|
||||||
|
|
||||||
fn ty(&self) -> Self::Type {
|
|
||||||
macro_rules! map {
|
|
||||||
($($n:ident,)*) => {
|
|
||||||
match self {
|
|
||||||
$(
|
|
||||||
Self::$n { .. } => WindowCritTy::$n,
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
map! {
|
|
||||||
Client,
|
|
||||||
Title,
|
|
||||||
AppId,
|
|
||||||
Floating,
|
|
||||||
Visible,
|
|
||||||
Urgent,
|
|
||||||
Fullscreen,
|
|
||||||
Tag,
|
|
||||||
XClass,
|
|
||||||
XInstance,
|
|
||||||
XRole,
|
|
||||||
Workspace,
|
|
||||||
ContentTypes,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_ty(ty: Self::Type) -> Self {
|
|
||||||
match ty {
|
|
||||||
WindowCritTy::Client => Self::Client(Default::default()),
|
|
||||||
WindowCritTy::Title => Self::Title(Default::default()),
|
|
||||||
WindowCritTy::AppId => Self::AppId(Default::default()),
|
|
||||||
WindowCritTy::Floating => Self::Floating,
|
|
||||||
WindowCritTy::Visible => Self::Visible,
|
|
||||||
WindowCritTy::Urgent => Self::Urgent,
|
|
||||||
WindowCritTy::Fullscreen => Self::Fullscreen,
|
|
||||||
WindowCritTy::Tag => Self::Tag(Default::default()),
|
|
||||||
WindowCritTy::XClass => Self::XClass(Default::default()),
|
|
||||||
WindowCritTy::XInstance => Self::XInstance(Default::default()),
|
|
||||||
WindowCritTy::XRole => Self::XRole(Default::default()),
|
|
||||||
WindowCritTy::Workspace => Self::Workspace(Default::default()),
|
|
||||||
WindowCritTy::ContentTypes => {
|
|
||||||
Self::ContentTypes(PHOTO_CONTENT | VIDEO_CONTENT | GAME_CONTENT)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn show(&mut self, ui: &mut Ui) -> bool {
|
|
||||||
match self {
|
|
||||||
WindowClit::Client(v) => v.show(ui),
|
|
||||||
WindowClit::Title(v) => v.show(ui),
|
|
||||||
WindowClit::AppId(v) => v.show(ui),
|
|
||||||
WindowClit::Floating => false,
|
|
||||||
WindowClit::Visible => false,
|
|
||||||
WindowClit::Urgent => false,
|
|
||||||
WindowClit::Fullscreen => false,
|
|
||||||
WindowClit::Tag(v) => v.show(ui),
|
|
||||||
WindowClit::XClass(v) => v.show(ui),
|
|
||||||
WindowClit::XInstance(v) => v.show(ui),
|
|
||||||
WindowClit::XRole(v) => v.show(ui),
|
|
||||||
WindowClit::Workspace(v) => v.show(ui),
|
|
||||||
WindowClit::ContentTypes(v) => show_content_types(ui, v),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_crit(&self, state: &Rc<State>) -> Option<Rc<dyn CritUpstreamNode<Self::Target>>> {
|
|
||||||
let m = &state.tl_matcher_manager;
|
|
||||||
let res = match self {
|
|
||||||
WindowClit::Client(v) => m.client(state, &v.to_crit(state)?),
|
|
||||||
WindowClit::Title(v) => m.title(v.to_crit()?),
|
|
||||||
WindowClit::AppId(v) => m.app_id(v.to_crit()?),
|
|
||||||
WindowClit::Floating => m.floating(),
|
|
||||||
WindowClit::Visible => m.visible(),
|
|
||||||
WindowClit::Urgent => m.urgent(),
|
|
||||||
WindowClit::Fullscreen => m.fullscreen(),
|
|
||||||
WindowClit::Tag(v) => m.tag(v.to_crit()?),
|
|
||||||
WindowClit::XClass(v) => m.class(v.to_crit()?),
|
|
||||||
WindowClit::XInstance(v) => m.instance(v.to_crit()?),
|
|
||||||
WindowClit::XRole(v) => m.role(v.to_crit()?),
|
|
||||||
WindowClit::Workspace(v) => m.workspace(v.to_crit()?),
|
|
||||||
WindowClit::ContentTypes(v) => m.content_type(*v),
|
|
||||||
};
|
|
||||||
Some(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn not(
|
|
||||||
state: &State,
|
|
||||||
upstream: &Rc<dyn CritUpstreamNode<Self::Target>>,
|
|
||||||
) -> Rc<dyn CritUpstreamNode<Self::Target>> {
|
|
||||||
state.tl_matcher_manager.not(upstream)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn list(
|
|
||||||
state: &State,
|
|
||||||
upstream: &[Rc<dyn CritUpstreamNode<Self::Target>>],
|
|
||||||
all: bool,
|
|
||||||
) -> Rc<dyn CritUpstreamNode<Self::Target>> {
|
|
||||||
state.tl_matcher_manager.list(upstream, all)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn exactly(
|
|
||||||
state: &State,
|
|
||||||
n: usize,
|
|
||||||
upstream: &[Rc<dyn CritUpstreamNode<Self::Target>>],
|
|
||||||
) -> Rc<dyn CritUpstreamNode<Self::Target>> {
|
|
||||||
state.tl_matcher_manager.exactly(upstream, n)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct WindowSearchPane {
|
|
||||||
state: Rc<State>,
|
|
||||||
criterion: CcCriterion<WindowClit>,
|
|
||||||
matched: Rc<Matched>,
|
|
||||||
leaf: Option<Rc<CritLeafMatcher<ToplevelData>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Matched {
|
|
||||||
slf: Weak<ControlCenterInner>,
|
|
||||||
windows: CopyHashMap<ToplevelIdentifier, ()>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Matched {
|
|
||||||
fn request_frame(&self) {
|
|
||||||
if let Some(slf) = self.slf.upgrade() {
|
|
||||||
slf.window.request_redraw();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ControlCenterInner {
|
|
||||||
pub fn create_window_search_pane(self: &Rc<Self>) -> WindowSearchPane {
|
|
||||||
let mut pane = WindowSearchPane {
|
|
||||||
state: self.state.clone(),
|
|
||||||
criterion: Default::default(),
|
|
||||||
matched: Rc::new(Matched {
|
|
||||||
slf: Rc::downgrade(self),
|
|
||||||
windows: Default::default(),
|
|
||||||
}),
|
|
||||||
leaf: Default::default(),
|
|
||||||
};
|
|
||||||
pane.update_matcher();
|
|
||||||
pane
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WindowSearchPane {
|
|
||||||
pub fn title(&self, res: &mut String) {
|
|
||||||
res.push_str("Window Search");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show(&mut self, behavior: &mut CcBehavior<'_>, ui: &mut Ui) {
|
|
||||||
let mut clear = false;
|
|
||||||
if self.criterion.show(ui) {
|
|
||||||
clear = self.update_matcher();
|
|
||||||
}
|
|
||||||
ui.separator();
|
|
||||||
let mut windows: Vec<_> = self.matched.windows.lock().keys().copied().collect();
|
|
||||||
windows.sort();
|
|
||||||
for id in windows {
|
|
||||||
let Some(window) = self.state.toplevels.get(&id).and_then(|v| v.upgrade()) else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
show_window_collapsible(behavior, ui, &window);
|
|
||||||
}
|
|
||||||
if clear {
|
|
||||||
self.matched.windows.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_matcher(&mut self) -> bool {
|
|
||||||
let mut clear = false;
|
|
||||||
let state = &self.state;
|
|
||||||
if let Some(new) = self.criterion.to_crit(state) {
|
|
||||||
clear = true;
|
|
||||||
let matched = self.matched.clone();
|
|
||||||
let leaf = state.tl_matcher_manager.leaf(&new, move |data| {
|
|
||||||
matched.windows.set(data, ());
|
|
||||||
matched.request_frame();
|
|
||||||
Box::new({
|
|
||||||
let matched = matched.clone();
|
|
||||||
move || {
|
|
||||||
matched.windows.remove(&data);
|
|
||||||
matched.request_frame();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
});
|
|
||||||
state.tl_matcher_manager.rematch_all(state);
|
|
||||||
if self.criterion.any(|c| matches!(c, WindowClit::Client(_))) {
|
|
||||||
state.cl_matcher_manager.rematch_all(state);
|
|
||||||
}
|
|
||||||
self.leaf = Some(leaf);
|
|
||||||
}
|
|
||||||
clear
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct WindowPane {
|
|
||||||
window: Rc<dyn ToplevelNode>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ControlCenterInner {
|
|
||||||
pub fn create_window_pane(self: &Rc<Self>, window: &Rc<dyn ToplevelNode>) -> WindowPane {
|
|
||||||
WindowPane {
|
|
||||||
window: window.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WindowPane {
|
|
||||||
pub fn title(&self, res: &mut String) {
|
|
||||||
res.push_str("Window");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show(&mut self, behavior: &mut CcBehavior<'_>, ui: &mut Ui) {
|
|
||||||
show_window(behavior, ui, &*self.window)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show_window_collapsible(
|
|
||||||
behavior: &mut CcBehavior,
|
|
||||||
ui: &mut Ui,
|
|
||||||
window: &Rc<dyn ToplevelNode>,
|
|
||||||
) {
|
|
||||||
let data = window.tl_data();
|
|
||||||
let mut layout_job = LayoutJob::default();
|
|
||||||
layout_job.append(
|
|
||||||
"Window",
|
|
||||||
0.0,
|
|
||||||
TextFormat {
|
|
||||||
color: ui.style().visuals.widgets.inactive.text_color(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
);
|
|
||||||
layout_job.append(
|
|
||||||
&data.title.borrow(),
|
|
||||||
10.0,
|
|
||||||
TextFormat {
|
|
||||||
color: ui.style().visuals.widgets.active.text_color(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
);
|
|
||||||
let closed = CollapsingHeader::new(layout_job)
|
|
||||||
.id_salt(("window", data.identifier.get()))
|
|
||||||
.show(ui, |ui| {
|
|
||||||
if icon_label(ICON_OPEN_IN_NEW)
|
|
||||||
.sense(Sense::CLICK)
|
|
||||||
.ui(ui)
|
|
||||||
.clicked()
|
|
||||||
{
|
|
||||||
behavior.open = Some(PaneType::Window(behavior.cc.create_window_pane(window)));
|
|
||||||
}
|
|
||||||
show_window(behavior, ui, &**window)
|
|
||||||
})
|
|
||||||
.fully_closed();
|
|
||||||
if closed {
|
|
||||||
ensure_listener(ui, behavior, data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show_window(behavior: &mut CcBehavior<'_>, ui: &mut Ui, window: &dyn ToplevelNode) {
|
|
||||||
let data = window.tl_data();
|
|
||||||
ensure_listener(ui, behavior, data);
|
|
||||||
grid(ui, ("window", data.identifier.get()), |ui| {
|
|
||||||
label(ui, "ID", &*data.identifier.get().to_string());
|
|
||||||
label(ui, "Title", &*data.title.borrow());
|
|
||||||
if let Some(w) = data.workspace.get() {
|
|
||||||
label(ui, "Workspace", &w.name);
|
|
||||||
}
|
|
||||||
match &data.kind {
|
|
||||||
ToplevelType::Container => {
|
|
||||||
label(ui, "Type", "Container");
|
|
||||||
}
|
|
||||||
ToplevelType::Placeholder(_) => {
|
|
||||||
label(ui, "Type", "Placeholder");
|
|
||||||
}
|
|
||||||
ToplevelType::XdgToplevel(t) => {
|
|
||||||
label(ui, "Type", "xdg_toplevel");
|
|
||||||
let tag = &*t.tag.borrow();
|
|
||||||
if tag.is_not_empty() {
|
|
||||||
label(ui, "Tag", tag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ToplevelType::XWindow(t) => {
|
|
||||||
label(ui, "Type", "X Window");
|
|
||||||
if let Some(class) = &*t.info.class.borrow() {
|
|
||||||
label(ui, "Class", class);
|
|
||||||
}
|
|
||||||
if let Some(instance) = &*t.info.instance.borrow() {
|
|
||||||
label(ui, "Instance", instance);
|
|
||||||
}
|
|
||||||
if let Some(role) = &*t.info.role.borrow() {
|
|
||||||
label(ui, "Role", role);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let app_id = &*data.app_id.borrow();
|
|
||||||
if app_id.is_not_empty() {
|
|
||||||
label(ui, "App ID", app_id);
|
|
||||||
}
|
|
||||||
read_only_bool(ui, "Floating", data.parent_is_float.get());
|
|
||||||
read_only_bool(ui, "Visible", data.visible.get());
|
|
||||||
read_only_bool(ui, "Urgent", data.wants_attention.get());
|
|
||||||
read_only_bool(ui, "Fullscreen", data.is_fullscreen.get());
|
|
||||||
if let Some(ct) = data.content_type.get() {
|
|
||||||
label(ui, "Content Type", ct.text());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if let Some(client) = &data.client {
|
|
||||||
show_client_collapsible(behavior, ui, client);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ensure_listener(ui: &mut Ui, behavior: &CcBehavior<'_>, data: &ToplevelData) {
|
|
||||||
ui.memory_mut(|m| {
|
|
||||||
m.caches
|
|
||||||
.cache::<WindowPropertyListeners>()
|
|
||||||
.ensure(behavior.cc, data);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
struct WindowPropertyListeners {
|
|
||||||
generation: u64,
|
|
||||||
listeners: AHashMap<NodeId, WindowPropertyListener>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct WindowPropertyListener {
|
|
||||||
_listener: EventListener<dyn LazyEventSourceListener>,
|
|
||||||
generation: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WindowPropertyListeners {
|
|
||||||
fn ensure(&mut self, cc: &Rc<ControlCenterInner>, data: &ToplevelData) {
|
|
||||||
let listener = self.listeners.entry(data.node_id).or_insert_with(|| {
|
|
||||||
let listener =
|
|
||||||
EventListener::new(Rc::downgrade(cc) as Weak<dyn LazyEventSourceListener>);
|
|
||||||
listener.attach(data.property_changed_source());
|
|
||||||
WindowPropertyListener {
|
|
||||||
_listener: listener,
|
|
||||||
generation: 0,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
listener.generation = self.generation;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Sync for WindowPropertyListeners {}
|
|
||||||
unsafe impl Send for WindowPropertyListeners {}
|
|
||||||
|
|
||||||
impl CacheTrait for WindowPropertyListeners {
|
|
||||||
fn update(&mut self) {
|
|
||||||
self.listeners
|
|
||||||
.retain(|_, m| m.generation == self.generation);
|
|
||||||
self.generation += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn len(&self) -> usize {
|
|
||||||
self.listeners.len()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn show_content_types(ui: &mut Ui, ct: &mut ContentType) -> bool {
|
|
||||||
let mut v = *ct;
|
|
||||||
let mut photo = (v & PHOTO_CONTENT).0 != 0;
|
|
||||||
let mut video = (v & VIDEO_CONTENT).0 != 0;
|
|
||||||
let mut game = (v & GAME_CONTENT).0 != 0;
|
|
||||||
ui.checkbox(&mut photo, "Photo");
|
|
||||||
ui.checkbox(&mut video, "Video");
|
|
||||||
ui.checkbox(&mut game, "Game");
|
|
||||||
v = NO_CONTENT_TYPE;
|
|
||||||
if photo {
|
|
||||||
v |= PHOTO_CONTENT;
|
|
||||||
}
|
|
||||||
if video {
|
|
||||||
v |= VIDEO_CONTENT;
|
|
||||||
}
|
|
||||||
if game {
|
|
||||||
v |= GAME_CONTENT;
|
|
||||||
}
|
|
||||||
mem::replace(ct, v) != v
|
|
||||||
}
|
|
||||||
|
|
@ -1,91 +0,0 @@
|
||||||
use {
|
|
||||||
crate::{
|
|
||||||
compositor::DISPLAY,
|
|
||||||
control_center::{
|
|
||||||
CcBehavior, ControlCenterInner, bool, cc_clients::show_client_collapsible,
|
|
||||||
combo_box_ui, grid, label, read_only_bool, tip,
|
|
||||||
},
|
|
||||||
state::State,
|
|
||||||
utils::{errorfmt::ErrorFmt, oserror::OsErrorExt, static_text::StaticText},
|
|
||||||
},
|
|
||||||
egui::Ui,
|
|
||||||
linearize::Linearize,
|
|
||||||
std::rc::Rc,
|
|
||||||
uapi::c,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct XwaylandPane {
|
|
||||||
state: Rc<State>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ControlCenterInner {
|
|
||||||
pub fn create_xwayland_pane(self: &Rc<Self>) -> XwaylandPane {
|
|
||||||
XwaylandPane {
|
|
||||||
state: self.state.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Linearize)]
|
|
||||||
enum ScalingMode {
|
|
||||||
Default,
|
|
||||||
Downscaled,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StaticText for ScalingMode {
|
|
||||||
fn text(&self) -> &'static str {
|
|
||||||
match self {
|
|
||||||
ScalingMode::Default => "default",
|
|
||||||
ScalingMode::Downscaled => "downscaled",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl XwaylandPane {
|
|
||||||
pub fn title(&self, res: &mut String) {
|
|
||||||
res.push_str("Xwayland");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show(&mut self, behavior: &mut CcBehavior<'_>, ui: &mut Ui) {
|
|
||||||
let s = &self.state;
|
|
||||||
grid(ui, "settings", |ui| {
|
|
||||||
bool(ui, "Enabled", s.xwayland.enabled.get(), |b| {
|
|
||||||
s.set_xwayland_enabled(b)
|
|
||||||
});
|
|
||||||
let mode = match self.state.xwayland.use_wire_scale.get() {
|
|
||||||
true => ScalingMode::Downscaled,
|
|
||||||
false => ScalingMode::Default,
|
|
||||||
};
|
|
||||||
combo_box_ui(
|
|
||||||
ui,
|
|
||||||
"Scaling Mode",
|
|
||||||
|ui| {
|
|
||||||
tip(ui, |ui| {
|
|
||||||
ui.label(r#"`downscaled` is known as "X applications scale themselves""#);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
mode,
|
|
||||||
|v| {
|
|
||||||
self.state
|
|
||||||
.set_xwayland_use_wire_scale(v == ScalingMode::Downscaled);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
if let Some(display) = self.state.xwayland.display.get() {
|
|
||||||
label(ui, DISPLAY, &*display);
|
|
||||||
}
|
|
||||||
read_only_bool(ui, "Running", self.state.xwayland.running.get());
|
|
||||||
if let Some(client) = self.state.xwayland.client.get() {
|
|
||||||
label(ui, "PID", client.pid_info.pid.to_string());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if let Some(client) = self.state.xwayland.client.get()
|
|
||||||
&& ui.button("Kill").clicked()
|
|
||||||
&& let Err(e) = uapi::kill(client.pid_info.pid, c::SIGTERM).to_os_error()
|
|
||||||
{
|
|
||||||
log::error!("Could not kill Xwayland: {}", ErrorFmt(e));
|
|
||||||
}
|
|
||||||
if let Some(client) = self.state.xwayland.client.get() {
|
|
||||||
show_client_collapsible(behavior, ui, &client);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -234,9 +234,6 @@ impl ClMatcherManager {
|
||||||
self.root(ClmMatchTag::new(string))
|
self.root(ClmMatchTag::new(string))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn id(&self, id: ClientId) -> Rc<ClmUpstreamNode> {
|
|
||||||
self.root(ClmMatchId(id))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CritTarget for Rc<Client> {
|
impl CritTarget for Rc<Client> {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
backend::HardwareCursorUpdate,
|
backend::HardwareCursorUpdate,
|
||||||
control_center::CCI_INPUT,
|
|
||||||
cursor::{Cursor, DEFAULT_CURSOR_SIZE, KnownCursor},
|
cursor::{Cursor, DEFAULT_CURSOR_SIZE, KnownCursor},
|
||||||
fixed::Fixed,
|
fixed::Fixed,
|
||||||
gfx_api::{AcquireSync, ReleaseSync},
|
gfx_api::{AcquireSync, ReleaseSync},
|
||||||
|
|
@ -184,7 +183,6 @@ impl CursorUserGroup {
|
||||||
self.remove_hardware_cursor();
|
self.remove_hardware_cursor();
|
||||||
self.state.cursor_user_group_hardware_cursor.take();
|
self.state.cursor_user_group_hardware_cursor.take();
|
||||||
}
|
}
|
||||||
self.state.trigger_cci(CCI_INPUT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hardware_cursor(&self) -> bool {
|
pub fn hardware_cursor(&self) -> bool {
|
||||||
|
|
@ -197,13 +195,9 @@ impl CursorUserGroup {
|
||||||
self.state.remove_cursor_size(old);
|
self.state.remove_cursor_size(old);
|
||||||
self.state.add_cursor_size(size);
|
self.state.add_cursor_size(size);
|
||||||
self.reload_known_cursor();
|
self.reload_known_cursor();
|
||||||
self.state.trigger_cci(CCI_INPUT);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cursor_size(&self) -> u32 {
|
|
||||||
self.size.get()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_center(&self, output: &Rc<OutputNode>) -> (Fixed, Fixed) {
|
fn output_center(&self, output: &Rc<OutputNode>) -> (Fixed, Fixed) {
|
||||||
let pos = output.global.pos.get();
|
let pos = output.global.pos.get();
|
||||||
|
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
pub mod egui_oklch;
|
|
||||||
pub mod egui_platform;
|
|
||||||
mod egui_vulkan;
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
use {
|
|
||||||
crate::{
|
|
||||||
cmm::cmm_eotf::Eotf,
|
|
||||||
theme::{Color, Oklab, Oklch},
|
|
||||||
},
|
|
||||||
egui::{Color32, Rgba},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub trait Color32Ext {
|
|
||||||
fn to_oklab(self) -> Oklab;
|
|
||||||
fn to_oklch(self) -> Oklch;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Color32Ext for Color32 {
|
|
||||||
fn to_oklab(self) -> Oklab {
|
|
||||||
let [r, g, b, a] = self.to_array();
|
|
||||||
Color::from_srgba_premultiplied(r, g, b, a).srgb_to_oklab()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_oklch(self) -> Oklch {
|
|
||||||
self.to_oklab().to_oklch()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<Color32> for Oklch {
|
|
||||||
fn into(self) -> Color32 {
|
|
||||||
self.to_oklab().into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<Color32> for Oklab {
|
|
||||||
fn into(self) -> Color32 {
|
|
||||||
let [r, g, b, a] = self.to_srgb().to_array(Eotf::Linear);
|
|
||||||
Rgba::from_rgba_premultiplied(r, g, b, a).into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Binary file not shown.
|
|
@ -1,13 +0,0 @@
|
||||||
#version 450
|
|
||||||
|
|
||||||
layout(location = 0) in vec4 color;
|
|
||||||
layout(location = 1) in vec2 pos;
|
|
||||||
|
|
||||||
layout(binding = 0, set = 0) uniform sampler2D tex;
|
|
||||||
|
|
||||||
layout(location = 0) out vec4 res;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
vec4 src = texture(tex, pos);
|
|
||||||
res = color * src;
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
#version 450
|
|
||||||
|
|
||||||
layout(location = 0) in vec2 if_pos;
|
|
||||||
layout(location = 1) in vec2 it_pos;
|
|
||||||
layout(location = 2) in vec4 i_color;
|
|
||||||
|
|
||||||
layout(location = 0) out vec4 o_color;
|
|
||||||
layout(location = 1) out vec2 ot_pos;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
o_color = i_color;
|
|
||||||
o_color.rgb = mix(
|
|
||||||
o_color.rgb / vec3(12.92),
|
|
||||||
pow((o_color.rgb + vec3(0.055)) / vec3(1.055), vec3(2.4)),
|
|
||||||
greaterThan(o_color.rgb, vec3(0.04045))
|
|
||||||
);
|
|
||||||
ot_pos = it_pos;
|
|
||||||
gl_Position = vec4(if_pos.x, if_pos.y, 0.0, 1.0);
|
|
||||||
}
|
|
||||||
Binary file not shown.
Binary file not shown.
|
|
@ -1,2 +0,0 @@
|
||||||
7eb8fae39ae513bc4f6973c12227aa4aa43734bdf34c90e1b3b69294ad98db87 src/egui_adapter/shaders/shader.frag
|
|
||||||
501f4d0c5c5f10a371659b89f12d87abb03e5b57a31dbae5f3c6ca5726e4db01 src/egui_adapter/shaders/shader.vert
|
|
||||||
|
|
@ -1,136 +0,0 @@
|
||||||
use {
|
|
||||||
crate::fontconfig::consts::{FC_MATCH_PATTERN, FC_RESULT_MATCH},
|
|
||||||
run_on_drop::on_drop,
|
|
||||||
std::{
|
|
||||||
borrow::Cow,
|
|
||||||
ffi::{CStr, OsStr, c_char},
|
|
||||||
os::{
|
|
||||||
raw::{c_int, c_uchar},
|
|
||||||
unix::ffi::OsStrExt,
|
|
||||||
},
|
|
||||||
path::PathBuf,
|
|
||||||
ptr,
|
|
||||||
},
|
|
||||||
thiserror::Error,
|
|
||||||
uapi::IntoUstr,
|
|
||||||
};
|
|
||||||
|
|
||||||
mod consts;
|
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/fontconfig_tys.rs"));
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
pub enum FontconfigError {
|
|
||||||
#[error("FcConfigGetCurrent returned NULL")]
|
|
||||||
Init,
|
|
||||||
#[error("Could not create a pattern")]
|
|
||||||
CreatePattern,
|
|
||||||
#[error("Could not find a match")]
|
|
||||||
NoMatch,
|
|
||||||
#[error("Match has no name")]
|
|
||||||
NoName,
|
|
||||||
#[error("Match has no file")]
|
|
||||||
NoFile,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Font {
|
|
||||||
pub fullname: String,
|
|
||||||
pub file: PathBuf,
|
|
||||||
pub index: Option<i32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn match_font(family: &str) -> Result<Font, FontconfigError> {
|
|
||||||
thread_local! {
|
|
||||||
static CONFIG: *mut FcConfig = FcConfigGetCurrent();
|
|
||||||
}
|
|
||||||
let config = CONFIG.with(|c| *c);
|
|
||||||
if config.is_null() {
|
|
||||||
return Err(FontconfigError::Init);
|
|
||||||
}
|
|
||||||
let family = family.into_ustr();
|
|
||||||
let p = FcPatternCreate();
|
|
||||||
if p.is_null() {
|
|
||||||
return Err(FontconfigError::CreatePattern);
|
|
||||||
}
|
|
||||||
let _destroy_pattern = on_drop(|| unsafe { FcPatternDestroy(p) });
|
|
||||||
let mut result = 0;
|
|
||||||
let p = unsafe {
|
|
||||||
FcPatternAddString(p, FC_FAMILY.as_ptr(), family.as_ptr() as _);
|
|
||||||
FcConfigSubstitute(config, p, FC_MATCH_PATTERN.0 as _);
|
|
||||||
FcDefaultSubstitute(p);
|
|
||||||
FcFontMatch(config, p, &mut result)
|
|
||||||
};
|
|
||||||
if p.is_null() {
|
|
||||||
return Err(FontconfigError::NoMatch);
|
|
||||||
}
|
|
||||||
let _destroy_pattern = on_drop(|| unsafe { FcPatternDestroy(p) });
|
|
||||||
if result != FC_RESULT_MATCH.0 as FcResult {
|
|
||||||
return Err(FontconfigError::NoMatch);
|
|
||||||
}
|
|
||||||
let get_cstr = |name: &CStr| {
|
|
||||||
let mut out = ptr::null_mut();
|
|
||||||
let res = unsafe { FcPatternGetString(p, name.as_ptr(), 0, &mut out) };
|
|
||||||
if res != FC_RESULT_MATCH.0 as FcResult || out.is_null() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let cstr = unsafe { CStr::from_ptr(out.cast()) };
|
|
||||||
Some(cstr)
|
|
||||||
};
|
|
||||||
let get_int = |name: &CStr| {
|
|
||||||
let mut out = 0;
|
|
||||||
let res = unsafe { FcPatternGetInteger(p, name.as_ptr(), 0, &mut out) };
|
|
||||||
if res != FC_RESULT_MATCH.0 as FcResult {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
Some(out as i32)
|
|
||||||
};
|
|
||||||
Ok(Font {
|
|
||||||
fullname: get_cstr(FC_FULLNAME)
|
|
||||||
.map(CStr::to_string_lossy)
|
|
||||||
.map(Cow::into_owned)
|
|
||||||
.ok_or(FontconfigError::NoName)?,
|
|
||||||
file: get_cstr(FC_FILE)
|
|
||||||
.map(CStr::to_bytes)
|
|
||||||
.map(OsStr::from_bytes)
|
|
||||||
.map(Into::into)
|
|
||||||
.ok_or(FontconfigError::NoFile)?,
|
|
||||||
index: get_int(FC_INDEX),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
type FcBool = c_int;
|
|
||||||
type FcPattern = u8;
|
|
||||||
type FcConfig = u8;
|
|
||||||
type FcChar8 = c_uchar;
|
|
||||||
const FC_FAMILY: &CStr = c"family";
|
|
||||||
const FC_FULLNAME: &CStr = c"fullname";
|
|
||||||
const FC_FILE: &CStr = c"file";
|
|
||||||
const FC_INDEX: &CStr = c"index";
|
|
||||||
|
|
||||||
#[link(name = "fontconfig")]
|
|
||||||
unsafe extern "C" {
|
|
||||||
safe fn FcConfigGetCurrent() -> *mut FcConfig;
|
|
||||||
safe fn FcPatternCreate() -> *mut FcPattern;
|
|
||||||
fn FcPatternDestroy(p: *mut FcPattern);
|
|
||||||
fn FcPatternAddString(p: *mut FcPattern, object: *const c_char, s: *const FcChar8) -> FcBool;
|
|
||||||
fn FcConfigSubstitute(config: *mut FcConfig, p: *mut FcPattern, kind: FcMatchKind) -> FcBool;
|
|
||||||
fn FcDefaultSubstitute(p: *mut FcPattern);
|
|
||||||
fn FcFontMatch(
|
|
||||||
config: *mut FcConfig,
|
|
||||||
p: *mut FcPattern,
|
|
||||||
result: *mut FcResult,
|
|
||||||
) -> *mut FcPattern;
|
|
||||||
fn FcPatternGetString(
|
|
||||||
p: *mut FcPattern,
|
|
||||||
object: *const c_char,
|
|
||||||
id: c_int,
|
|
||||||
s: *mut *mut FcChar8,
|
|
||||||
) -> FcResult;
|
|
||||||
fn FcPatternGetInteger(
|
|
||||||
p: *mut FcPattern,
|
|
||||||
object: *const c_char,
|
|
||||||
id: c_int,
|
|
||||||
i: *mut c_int,
|
|
||||||
) -> FcResult;
|
|
||||||
}
|
|
||||||
|
|
@ -21,7 +21,6 @@ pub mod jay_ei_session_builder;
|
||||||
pub mod jay_idle;
|
pub mod jay_idle;
|
||||||
pub mod jay_input;
|
pub mod jay_input;
|
||||||
pub mod jay_log_file;
|
pub mod jay_log_file;
|
||||||
pub mod jay_open_control_center_request;
|
|
||||||
pub mod jay_output;
|
pub mod jay_output;
|
||||||
pub mod jay_pointer;
|
pub mod jay_pointer;
|
||||||
pub mod jay_popup_ext_manager_v1;
|
pub mod jay_popup_ext_manager_v1;
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ use {
|
||||||
wire::JayHeadManagerSessionV1Id,
|
wire::JayHeadManagerSessionV1Id,
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, Ref, RefCell},
|
cell::{Cell, RefCell},
|
||||||
collections::hash_map::Entry,
|
collections::hash_map::Entry,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
},
|
},
|
||||||
|
|
@ -103,16 +103,6 @@ pub struct HeadState {
|
||||||
pub persistent_state: Option<RcEq<PersistentOutputState>>,
|
pub persistent_state: Option<RcEq<PersistentOutputState>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ReadOnlyHeadState {
|
|
||||||
state: Rc<RefCell<HeadState>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ReadOnlyHeadState {
|
|
||||||
pub fn borrow(&self) -> Ref<'_, HeadState> {
|
|
||||||
self.state.borrow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HeadState {
|
impl HeadState {
|
||||||
pub fn update_in_compositor_space(&mut self, state: &State, wl_output: Option<GlobalName>) {
|
pub fn update_in_compositor_space(&mut self, state: &State, wl_output: Option<GlobalName>) {
|
||||||
self.in_compositor_space = false;
|
self.in_compositor_space = false;
|
||||||
|
|
@ -269,12 +259,6 @@ impl HeadManagers {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn state(&self) -> ReadOnlyHeadState {
|
|
||||||
ReadOnlyHeadState {
|
|
||||||
state: self.state.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn handle_removed(&self) {
|
pub fn handle_removed(&self) {
|
||||||
for head in self.managers.lock().drain_values() {
|
for head in self.managers.lock().drain_values() {
|
||||||
skip_in_transaction!(head);
|
skip_in_transaction!(head);
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ use {
|
||||||
jay_idle::JayIdle,
|
jay_idle::JayIdle,
|
||||||
jay_input::JayInput,
|
jay_input::JayInput,
|
||||||
jay_log_file::JayLogFile,
|
jay_log_file::JayLogFile,
|
||||||
jay_open_control_center_request::JayOpenControlCenterRequest,
|
|
||||||
jay_output::JayOutput,
|
jay_output::JayOutput,
|
||||||
jay_pointer::JayPointer,
|
jay_pointer::JayPointer,
|
||||||
jay_randr::JayRandr,
|
jay_randr::JayRandr,
|
||||||
|
|
@ -544,24 +543,6 @@ impl JayCompositorRequestHandler for JayCompositor {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open_control_center(
|
|
||||||
&self,
|
|
||||||
req: OpenControlCenter,
|
|
||||||
_slf: &Rc<Self>,
|
|
||||||
) -> Result<(), Self::Error> {
|
|
||||||
let obj = Rc::new(JayOpenControlCenterRequest {
|
|
||||||
id: req.id,
|
|
||||||
client: self.client.clone(),
|
|
||||||
tracker: Default::default(),
|
|
||||||
version: self.version,
|
|
||||||
});
|
|
||||||
track!(self.client, obj);
|
|
||||||
self.client.add_client_obj(&obj)?;
|
|
||||||
if let Err(e) = self.client.state.open_control_center() {
|
|
||||||
obj.send_failed(e);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object_base! {
|
object_base! {
|
||||||
|
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
use {
|
|
||||||
crate::{
|
|
||||||
client::{Client, ClientError},
|
|
||||||
leaks::Tracker,
|
|
||||||
object::{Object, Version},
|
|
||||||
utils::errorfmt::ErrorFmt,
|
|
||||||
wire::{JayOpenControlCenterRequestId, jay_open_control_center_request::*},
|
|
||||||
},
|
|
||||||
std::{error::Error, rc::Rc},
|
|
||||||
thiserror::Error,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct JayOpenControlCenterRequest {
|
|
||||||
pub id: JayOpenControlCenterRequestId,
|
|
||||||
pub client: Rc<Client>,
|
|
||||||
pub tracker: Tracker<Self>,
|
|
||||||
pub version: Version,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl JayOpenControlCenterRequest {
|
|
||||||
pub fn send_failed(&self, err: impl Error) {
|
|
||||||
let msg = &ErrorFmt(err).to_string();
|
|
||||||
self.client.event(Failed {
|
|
||||||
self_id: self.id,
|
|
||||||
msg,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl JayOpenControlCenterRequestRequestHandler for JayOpenControlCenterRequest {
|
|
||||||
type Error = JayOpenControlCenterRequestError;
|
|
||||||
|
|
||||||
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
|
||||||
self.client.remove_obj(self)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object_base! {
|
|
||||||
self = JayOpenControlCenterRequest;
|
|
||||||
version = self.version;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Object for JayOpenControlCenterRequest {}
|
|
||||||
|
|
||||||
simple_add_obj!(JayOpenControlCenterRequest);
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
pub enum JayOpenControlCenterRequestError {
|
|
||||||
#[error(transparent)]
|
|
||||||
ClientError(Box<ClientError>),
|
|
||||||
}
|
|
||||||
efrom!(JayOpenControlCenterRequestError, ClientError);
|
|
||||||
|
|
@ -28,7 +28,6 @@ use {
|
||||||
ButtonState, InputDeviceAccelProfile, InputDeviceClickMethod, Leds, TransformMatrix,
|
ButtonState, InputDeviceAccelProfile, InputDeviceClickMethod, Leds, TransformMatrix,
|
||||||
},
|
},
|
||||||
client::{Client, ClientError, ClientId},
|
client::{Client, ClientError, ClientId},
|
||||||
control_center::CCI_INPUT,
|
|
||||||
cursor_user::{CursorUser, CursorUserGroup, CursorUserOwner},
|
cursor_user::{CursorUser, CursorUserGroup, CursorUserOwner},
|
||||||
ei::ei_ifs::ei_seat::EiSeat,
|
ei::ei_ifs::ei_seat::EiSeat,
|
||||||
fixed::Fixed,
|
fixed::Fixed,
|
||||||
|
|
@ -141,9 +140,6 @@ const MISSING_CAPABILITY: u32 = 0;
|
||||||
|
|
||||||
pub const BTN_LEFT: u32 = 0x110;
|
pub const BTN_LEFT: u32 = 0x110;
|
||||||
pub const BTN_RIGHT: u32 = 0x111;
|
pub const BTN_RIGHT: u32 = 0x111;
|
||||||
pub const BTN_MIDDLE: u32 = 0x112;
|
|
||||||
pub const BTN_SIDE: u32 = 0x113;
|
|
||||||
pub const BTN_EXTRA: u32 = 0x114;
|
|
||||||
|
|
||||||
pub const SEAT_NAME_SINCE: Version = Version(2);
|
pub const SEAT_NAME_SINCE: Version = Version(2);
|
||||||
|
|
||||||
|
|
@ -788,7 +784,6 @@ impl WlSeatGlobal {
|
||||||
if let Some(grab) = self.input_method_grab.get() {
|
if let Some(grab) = self.input_method_grab.get() {
|
||||||
grab.on_repeat_info();
|
grab.on_repeat_info();
|
||||||
}
|
}
|
||||||
self.state.trigger_cci(CCI_INPUT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close(self: &Rc<Self>) {
|
pub fn close(self: &Rc<Self>) {
|
||||||
|
|
@ -1034,20 +1029,10 @@ impl WlSeatGlobal {
|
||||||
|
|
||||||
pub fn focus_history_set_visible(&self, visible: bool) {
|
pub fn focus_history_set_visible(&self, visible: bool) {
|
||||||
self.focus_history_visible_only.set(visible);
|
self.focus_history_visible_only.set(visible);
|
||||||
self.state.trigger_cci(CCI_INPUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn focus_history_visible(&self) -> bool {
|
|
||||||
self.focus_history_visible_only.get()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn focus_history_set_same_workspace(&self, same_workspace: bool) {
|
pub fn focus_history_set_same_workspace(&self, same_workspace: bool) {
|
||||||
self.focus_history_same_workspace.set(same_workspace);
|
self.focus_history_same_workspace.set(same_workspace);
|
||||||
self.state.trigger_cci(CCI_INPUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn focus_history_same_workspace(&self) -> bool {
|
|
||||||
self.focus_history_same_workspace.get()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn focus_layer_rel<LI, SI>(
|
fn focus_layer_rel<LI, SI>(
|
||||||
|
|
@ -1585,16 +1570,10 @@ impl WlSeatGlobal {
|
||||||
|
|
||||||
pub fn set_focus_follows_mouse(&self, focus_follows_mouse: bool) {
|
pub fn set_focus_follows_mouse(&self, focus_follows_mouse: bool) {
|
||||||
self.focus_follows_mouse.set(focus_follows_mouse);
|
self.focus_follows_mouse.set(focus_follows_mouse);
|
||||||
self.state.trigger_cci(CCI_INPUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn focus_follows_mouse(&self) -> bool {
|
|
||||||
self.focus_follows_mouse.get()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_mouse_follows_focus(&self, enabled: bool) {
|
pub fn set_mouse_follows_focus(&self, enabled: bool) {
|
||||||
self.mouse_follows_focus.set(enabled);
|
self.mouse_follows_focus.set(enabled);
|
||||||
self.state.trigger_cci(CCI_INPUT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mouse_follows_focus(&self) -> bool {
|
pub fn mouse_follows_focus(&self) -> bool {
|
||||||
|
|
@ -1603,11 +1582,6 @@ impl WlSeatGlobal {
|
||||||
|
|
||||||
pub fn set_fallback_output_mode(&self, fallback_output_mode: FallbackOutputMode) {
|
pub fn set_fallback_output_mode(&self, fallback_output_mode: FallbackOutputMode) {
|
||||||
self.fallback_output_mode.set(fallback_output_mode);
|
self.fallback_output_mode.set(fallback_output_mode);
|
||||||
self.state.trigger_cci(CCI_INPUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fallback_output_mode(&self) -> FallbackOutputMode {
|
|
||||||
self.fallback_output_mode.get()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_window_management_enabled(self: &Rc<Self>, enabled: bool) {
|
pub fn set_window_management_enabled(self: &Rc<Self>, enabled: bool) {
|
||||||
|
|
@ -1725,12 +1699,8 @@ impl WlSeatGlobal {
|
||||||
|
|
||||||
pub fn set_pointer_revert_key(&self, key: KeySym) {
|
pub fn set_pointer_revert_key(&self, key: KeySym) {
|
||||||
self.revert_key.set(key);
|
self.revert_key.set(key);
|
||||||
self.state.trigger_cci(CCI_INPUT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pointer_revert_key(&self) -> KeySym {
|
|
||||||
self.revert_key.get()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CursorUserOwner for WlSeatGlobal {
|
impl CursorUserOwner for WlSeatGlobal {
|
||||||
|
|
@ -1924,7 +1894,7 @@ pub fn collect_kb_foci(node: Rc<dyn Node>) -> SmallVec<[Rc<WlSeatGlobal>; 3]> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DeviceHandlerData {
|
impl DeviceHandlerData {
|
||||||
pub fn set_seat(&self, state: &State, seat: Option<Rc<WlSeatGlobal>>) {
|
pub fn set_seat(&self, _state: &State, seat: Option<Rc<WlSeatGlobal>>) {
|
||||||
if let Some(new) = &seat {
|
if let Some(new) = &seat {
|
||||||
if let Some(old) = self.seat.get()
|
if let Some(old) = self.seat.get()
|
||||||
&& old.id() == new.id()
|
&& old.id() == new.id()
|
||||||
|
|
@ -1963,7 +1933,6 @@ impl DeviceHandlerData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.attach_event_listeners();
|
self.attach_event_listeners();
|
||||||
state.trigger_cci(CCI_INPUT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn destroy_physical_keyboard_state(&self) {
|
fn destroy_physical_keyboard_state(&self) {
|
||||||
|
|
@ -1985,14 +1954,13 @@ impl DeviceHandlerData {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_keymap(&self, state: &State, keymap: Option<Rc<KbvmMap>>) {
|
pub fn set_keymap(&self, _state: &State, keymap: Option<Rc<KbvmMap>>) {
|
||||||
self.destroy_physical_keyboard_state();
|
self.destroy_physical_keyboard_state();
|
||||||
self.keymap.set(keymap);
|
self.keymap.set(keymap);
|
||||||
self.attach_event_listeners();
|
self.attach_event_listeners();
|
||||||
state.trigger_cci(CCI_INPUT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_output(&self, state: &State, output: Option<&WlOutputGlobal>) {
|
pub fn set_output(&self, _state: &State, output: Option<&WlOutputGlobal>) {
|
||||||
match output {
|
match output {
|
||||||
None => {
|
None => {
|
||||||
log::info!("Removing output mapping of {}", self.device.name());
|
log::info!("Removing output mapping of {}", self.device.name());
|
||||||
|
|
@ -2003,7 +1971,6 @@ impl DeviceHandlerData {
|
||||||
self.output.set(Some(o.opt.clone()));
|
self.output.set(Some(o.opt.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
state.trigger_cci(CCI_INPUT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_rect(&self, state: &State) -> Rect {
|
pub fn get_rect(&self, state: &State) -> Rect {
|
||||||
|
|
@ -2015,64 +1982,52 @@ impl DeviceHandlerData {
|
||||||
state.root.extents.get()
|
state.root.extents.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_accel_profile(&self, state: &State, v: InputDeviceAccelProfile) {
|
pub fn set_accel_profile(&self, _state: &State, v: InputDeviceAccelProfile) {
|
||||||
self.device.set_accel_profile(v);
|
self.device.set_accel_profile(v);
|
||||||
state.trigger_cci(CCI_INPUT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_accel_speed(&self, state: &State, v: f64) {
|
pub fn set_accel_speed(&self, _state: &State, v: f64) {
|
||||||
self.device.set_accel_speed(v);
|
self.device.set_accel_speed(v);
|
||||||
state.trigger_cci(CCI_INPUT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_tap_enabled(&self, state: &State, v: bool) {
|
pub fn set_tap_enabled(&self, _state: &State, v: bool) {
|
||||||
self.device.set_tap_enabled(v);
|
self.device.set_tap_enabled(v);
|
||||||
state.trigger_cci(CCI_INPUT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_drag_enabled(&self, state: &State, v: bool) {
|
pub fn set_drag_enabled(&self, _state: &State, v: bool) {
|
||||||
self.device.set_drag_enabled(v);
|
self.device.set_drag_enabled(v);
|
||||||
state.trigger_cci(CCI_INPUT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_drag_lock_enabled(&self, state: &State, v: bool) {
|
pub fn set_drag_lock_enabled(&self, _state: &State, v: bool) {
|
||||||
self.device.set_drag_lock_enabled(v);
|
self.device.set_drag_lock_enabled(v);
|
||||||
state.trigger_cci(CCI_INPUT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_left_handed(&self, state: &State, v: bool) {
|
pub fn set_left_handed(&self, _state: &State, v: bool) {
|
||||||
self.device.set_left_handed(v);
|
self.device.set_left_handed(v);
|
||||||
state.trigger_cci(CCI_INPUT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_natural_scrolling_enabled(&self, state: &State, v: bool) {
|
pub fn set_natural_scrolling_enabled(&self, _state: &State, v: bool) {
|
||||||
self.device.set_natural_scrolling_enabled(v);
|
self.device.set_natural_scrolling_enabled(v);
|
||||||
state.trigger_cci(CCI_INPUT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_px_per_scroll_wheel(&self, state: &State, v: f64) {
|
pub fn set_px_per_scroll_wheel(&self, _state: &State, v: f64) {
|
||||||
self.px_per_scroll_wheel.set(v);
|
self.px_per_scroll_wheel.set(v);
|
||||||
state.trigger_cci(CCI_INPUT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_transform_matrix(&self, state: &State, v: TransformMatrix) {
|
pub fn set_transform_matrix(&self, _state: &State, v: TransformMatrix) {
|
||||||
self.device.set_transform_matrix(v);
|
self.device.set_transform_matrix(v);
|
||||||
state.trigger_cci(CCI_INPUT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_calibration_matrix(&self, state: &State, v: [[f32; 3]; 2]) {
|
pub fn set_calibration_matrix(&self, _state: &State, v: [[f32; 3]; 2]) {
|
||||||
self.device.set_calibration_matrix(v);
|
self.device.set_calibration_matrix(v);
|
||||||
state.trigger_cci(CCI_INPUT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_click_method(&self, state: &State, v: InputDeviceClickMethod) {
|
pub fn set_click_method(&self, _state: &State, v: InputDeviceClickMethod) {
|
||||||
self.device.set_click_method(v);
|
self.device.set_click_method(v);
|
||||||
state.trigger_cci(CCI_INPUT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_middle_button_emulation_enabled(&self, state: &State, v: bool) {
|
pub fn set_middle_button_emulation_enabled(&self, _state: &State, v: bool) {
|
||||||
self.device.set_middle_button_emulation_enabled(v);
|
self.device.set_middle_button_emulation_enabled(v);
|
||||||
state.trigger_cci(CCI_INPUT);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
backend::KeyState,
|
backend::KeyState,
|
||||||
control_center::CCI_INPUT,
|
|
||||||
ifs::{
|
ifs::{
|
||||||
wl_seat::{
|
wl_seat::{
|
||||||
WlSeatGlobal,
|
WlSeatGlobal,
|
||||||
|
|
@ -90,7 +89,6 @@ impl WlSeatGlobal {
|
||||||
im.cancel_simple(self);
|
im.cancel_simple(self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.state.trigger_cci(CCI_INPUT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn simple_im_enabled(&self) -> bool {
|
pub fn simple_im_enabled(&self) -> bool {
|
||||||
|
|
|
||||||
|
|
@ -140,46 +140,6 @@ impl KnownCursor {
|
||||||
Some(cursor)
|
Some(cursor)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_shape(self) -> u32 {
|
|
||||||
match self {
|
|
||||||
KnownCursor::Default => DEFAULT,
|
|
||||||
KnownCursor::ContextMenu => CONTEXT_MENU,
|
|
||||||
KnownCursor::Help => HELP,
|
|
||||||
KnownCursor::Pointer => POINTER,
|
|
||||||
KnownCursor::Progress => PROGRESS,
|
|
||||||
KnownCursor::Wait => WAIT,
|
|
||||||
KnownCursor::Cell => CELL,
|
|
||||||
KnownCursor::Crosshair => CROSSHAIR,
|
|
||||||
KnownCursor::Text => TEXT,
|
|
||||||
KnownCursor::VerticalText => VERTICAL_TEXT,
|
|
||||||
KnownCursor::Alias => ALIAS,
|
|
||||||
KnownCursor::Copy => COPY,
|
|
||||||
KnownCursor::Move => MOVE,
|
|
||||||
KnownCursor::NoDrop => NO_DROP,
|
|
||||||
KnownCursor::NotAllowed => NOT_ALLOWED,
|
|
||||||
KnownCursor::Grab => GRAB,
|
|
||||||
KnownCursor::Grabbing => GRABBING,
|
|
||||||
KnownCursor::EResize => E_RESIZE,
|
|
||||||
KnownCursor::NResize => N_RESIZE,
|
|
||||||
KnownCursor::NeResize => NE_RESIZE,
|
|
||||||
KnownCursor::NwResize => NW_RESIZE,
|
|
||||||
KnownCursor::SResize => S_RESIZE,
|
|
||||||
KnownCursor::SeResize => SE_RESIZE,
|
|
||||||
KnownCursor::SwResize => SW_RESIZE,
|
|
||||||
KnownCursor::WResize => W_RESIZE,
|
|
||||||
KnownCursor::EwResize => EW_RESIZE,
|
|
||||||
KnownCursor::NsResize => NS_RESIZE,
|
|
||||||
KnownCursor::NeswResize => NESW_RESIZE,
|
|
||||||
KnownCursor::NwseResize => NWSE_RESIZE,
|
|
||||||
KnownCursor::ColResize => COL_RESIZE,
|
|
||||||
KnownCursor::RowResize => ROW_RESIZE,
|
|
||||||
KnownCursor::AllScroll => ALL_SCROLL,
|
|
||||||
KnownCursor::ZoomIn => ZOOM_IN,
|
|
||||||
KnownCursor::ZoomOut => ZOOM_OUT,
|
|
||||||
KnownCursor::DndAsk => DND_ASK,
|
|
||||||
KnownCursor::AllResize => ALL_RESIZE,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object_base! {
|
object_base! {
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,6 @@ pub struct KbvmMap {
|
||||||
pub id: KbvmMapId,
|
pub id: KbvmMapId,
|
||||||
pub state_machine: StateMachine,
|
pub state_machine: StateMachine,
|
||||||
pub lookup_table: LookupTable,
|
pub lookup_table: LookupTable,
|
||||||
pub map_text: String,
|
|
||||||
pub map: KeymapFd,
|
pub map: KeymapFd,
|
||||||
pub xwayland_map: KeymapFd,
|
pub xwayland_map: KeymapFd,
|
||||||
pub has_indicators: bool,
|
pub has_indicators: bool,
|
||||||
|
|
@ -161,12 +160,11 @@ impl KbvmContext {
|
||||||
}
|
}
|
||||||
let builder = map.to_builder();
|
let builder = map.to_builder();
|
||||||
let (_, xwayland_map) = create_keymap_memfd(&map, true).map_err(KbvmError::KeymapMemfd)?;
|
let (_, xwayland_map) = create_keymap_memfd(&map, true).map_err(KbvmError::KeymapMemfd)?;
|
||||||
let (map_text, map) = create_keymap_memfd(&map, false).map_err(KbvmError::KeymapMemfd)?;
|
let (_, map) = create_keymap_memfd(&map, false).map_err(KbvmError::KeymapMemfd)?;
|
||||||
Ok(Rc::new(KbvmMap {
|
Ok(Rc::new(KbvmMap {
|
||||||
id,
|
id,
|
||||||
state_machine: builder.build_state_machine(),
|
state_machine: builder.build_state_machine(),
|
||||||
map,
|
map,
|
||||||
map_text,
|
|
||||||
xwayland_map,
|
xwayland_map,
|
||||||
lookup_table: builder.build_lookup_table(),
|
lookup_table: builder.build_lookup_table(),
|
||||||
has_indicators,
|
has_indicators,
|
||||||
|
|
|
||||||
|
|
@ -96,10 +96,6 @@ impl Logger {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn level(&self) -> LogLevel {
|
|
||||||
self.level.load(Relaxed)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn path(&self) -> Arc<BString> {
|
pub fn path(&self) -> Arc<BString> {
|
||||||
self.path.lock().clone()
|
self.path.lock().clone()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,6 @@ mod clientmem;
|
||||||
mod cmm;
|
mod cmm;
|
||||||
mod compositor;
|
mod compositor;
|
||||||
mod config;
|
mod config;
|
||||||
mod control_center;
|
|
||||||
mod copy_device;
|
mod copy_device;
|
||||||
mod cpu_worker;
|
mod cpu_worker;
|
||||||
mod criteria;
|
mod criteria;
|
||||||
|
|
@ -68,11 +67,9 @@ mod damage;
|
||||||
mod dbus;
|
mod dbus;
|
||||||
mod drm_feedback;
|
mod drm_feedback;
|
||||||
mod edid;
|
mod edid;
|
||||||
mod egui_adapter;
|
|
||||||
mod ei;
|
mod ei;
|
||||||
mod eventfd_cache;
|
mod eventfd_cache;
|
||||||
mod fixed;
|
mod fixed;
|
||||||
mod fontconfig;
|
|
||||||
mod forker;
|
mod forker;
|
||||||
mod format;
|
mod format;
|
||||||
mod gfx_api;
|
mod gfx_api;
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
async_engine::AsyncEngine,
|
async_engine::AsyncEngine,
|
||||||
backend::HardwareCursor,
|
backend::HardwareCursor,
|
||||||
control_center::CCI_OUTPUTS,
|
|
||||||
ifs::wl_output::PersistentOutputState,
|
ifs::wl_output::PersistentOutputState,
|
||||||
io_uring::{IoUring, IoUringError},
|
io_uring::{IoUring, IoUringError},
|
||||||
state::{ConnectorData, State},
|
state::{ConnectorData, State},
|
||||||
|
|
@ -118,7 +117,7 @@ impl OutputSchedule {
|
||||||
self.trigger();
|
self.trigger();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_cursor_hz(&self, state: &State, hz: f64) {
|
pub fn set_cursor_hz(&self, _state: &State, hz: f64) {
|
||||||
let (hz, delta) = match map_cursor_hz(hz) {
|
let (hz, delta) = match map_cursor_hz(hz) {
|
||||||
None => {
|
None => {
|
||||||
log::warn!("Ignoring cursor frequency {hz}");
|
log::warn!("Ignoring cursor frequency {hz}");
|
||||||
|
|
@ -128,7 +127,6 @@ impl OutputSchedule {
|
||||||
};
|
};
|
||||||
self.persistent.vrr_cursor_hz.set(hz);
|
self.persistent.vrr_cursor_hz.set(hz);
|
||||||
self.connector.head_managers.handle_cursor_hz_change(hz);
|
self.connector.head_managers.handle_cursor_hz_change(hz);
|
||||||
state.trigger_cci(CCI_OUTPUTS);
|
|
||||||
self.cursor_delta_nsec.set(delta);
|
self.cursor_delta_nsec.set(delta);
|
||||||
self.trigger();
|
self.trigger();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,15 +42,6 @@ pub struct AcceptorMetadata {
|
||||||
pub tag: Option<String>,
|
pub tag: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AcceptorMetadata {
|
|
||||||
pub fn secure() -> Self {
|
|
||||||
Self {
|
|
||||||
secure: true,
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SecurityContextAcceptors {
|
impl SecurityContextAcceptors {
|
||||||
pub fn clear(&self) {
|
pub fn clear(&self) {
|
||||||
for acceptor in self.acceptors.lock().drain_values() {
|
for acceptor in self.acceptors.lock().drain_values() {
|
||||||
|
|
|
||||||
73
src/state.rs
73
src/state.rs
|
|
@ -19,10 +19,6 @@ use {
|
||||||
},
|
},
|
||||||
compositor::{LIBEI_SOCKET, LogLevel},
|
compositor::{LIBEI_SOCKET, LogLevel},
|
||||||
config::ConfigProxy,
|
config::ConfigProxy,
|
||||||
control_center::{
|
|
||||||
CCI_COLOR_MANAGEMENT, CCI_COMPOSITOR, CCI_GPUS, CCI_IDLE, CCI_LOOK_AND_FEEL,
|
|
||||||
CCI_OUTPUTS, CCI_XWAYLAND, ControlCenters,
|
|
||||||
},
|
|
||||||
copy_device::CopyDeviceRegistry,
|
copy_device::CopyDeviceRegistry,
|
||||||
cpu_worker::CpuWorker,
|
cpu_worker::CpuWorker,
|
||||||
criteria::{clm::ClMatcherManager, tlm::TlMatcherManager},
|
criteria::{clm::ClMatcherManager, tlm::TlMatcherManager},
|
||||||
|
|
@ -31,7 +27,6 @@ use {
|
||||||
damage::DamageVisualizer,
|
damage::DamageVisualizer,
|
||||||
dbus::Dbus,
|
dbus::Dbus,
|
||||||
drm_feedback::{DrmFeedback, DrmFeedbackIds},
|
drm_feedback::{DrmFeedback, DrmFeedbackIds},
|
||||||
egui_adapter::egui_platform::EggState,
|
|
||||||
ei::{
|
ei::{
|
||||||
ei_acceptor::EiAcceptor,
|
ei_acceptor::EiAcceptor,
|
||||||
ei_client::{EiClient, EiClients},
|
ei_client::{EiClient, EiClients},
|
||||||
|
|
@ -304,8 +299,6 @@ pub struct State {
|
||||||
pub eventfd_cache: Rc<EventfdCache>,
|
pub eventfd_cache: Rc<EventfdCache>,
|
||||||
pub lazy_event_sources: Rc<LazyEventSources>,
|
pub lazy_event_sources: Rc<LazyEventSources>,
|
||||||
pub bo_drop_queue: Rc<ObjectDropQueue<Rc<dyn BufferObject>>>,
|
pub bo_drop_queue: Rc<ObjectDropQueue<Rc<dyn BufferObject>>>,
|
||||||
pub egg_state: EggState,
|
|
||||||
pub control_centers: ControlCenters,
|
|
||||||
pub virtual_outputs: VirtualOutputs,
|
pub virtual_outputs: VirtualOutputs,
|
||||||
pub clean_logs_older_than: Cell<Option<SystemTime>>,
|
pub clean_logs_older_than: Cell<Option<SystemTime>>,
|
||||||
}
|
}
|
||||||
|
|
@ -366,10 +359,9 @@ impl IdleState {
|
||||||
self.timeout_changed(state);
|
self.timeout_changed(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn timeout_changed(&self, state: &State) {
|
fn timeout_changed(&self, _state: &State) {
|
||||||
self.timeout_changed.set(true);
|
self.timeout_changed.set(true);
|
||||||
self.change.trigger();
|
self.change.trigger();
|
||||||
state.trigger_cci(CCI_IDLE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_inhibitor(&self, state: &State, inhibitor: &Rc<ZwpIdleInhibitorV1>) {
|
pub fn add_inhibitor(&self, state: &State, inhibitor: &Rc<ZwpIdleInhibitorV1>) {
|
||||||
|
|
@ -385,10 +377,9 @@ impl IdleState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inhibitors_changed(&self, state: &State) {
|
fn inhibitors_changed(&self, _state: &State) {
|
||||||
self.inhibitors_changed.set(true);
|
self.inhibitors_changed.set(true);
|
||||||
self.change.trigger();
|
self.change.trigger();
|
||||||
state.trigger_cci(CCI_IDLE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resume_inhibited_notifications(&self) {
|
fn resume_inhibited_notifications(&self) {
|
||||||
|
|
@ -500,39 +491,30 @@ impl ConnectorData {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*self.state.borrow_mut() = s.clone();
|
*self.state.borrow_mut() = s.clone();
|
||||||
macro_rules! b {
|
if old.enabled != s.enabled {
|
||||||
($expr:expr) => {{
|
|
||||||
let e = $expr;
|
|
||||||
if e {
|
|
||||||
state.trigger_cci(CCI_OUTPUTS);
|
|
||||||
}
|
|
||||||
e
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
if b!(old.enabled != s.enabled) {
|
|
||||||
self.head_managers.handle_enabled_change(state, s.enabled);
|
self.head_managers.handle_enabled_change(state, s.enabled);
|
||||||
}
|
}
|
||||||
if b!(old.active != s.active) {
|
if old.active != s.active {
|
||||||
self.head_managers.handle_active_change(s.active);
|
self.head_managers.handle_active_change(s.active);
|
||||||
}
|
}
|
||||||
if b!(old.non_desktop_override != s.non_desktop_override) {
|
if old.non_desktop_override != s.non_desktop_override {
|
||||||
self.head_managers
|
self.head_managers
|
||||||
.handle_non_desktop_override_changed(s.non_desktop_override);
|
.handle_non_desktop_override_changed(s.non_desktop_override);
|
||||||
}
|
}
|
||||||
if b!(old.vrr != s.vrr) {
|
if old.vrr != s.vrr {
|
||||||
self.head_managers.handle_vrr_change(s.vrr);
|
self.head_managers.handle_vrr_change(s.vrr);
|
||||||
}
|
}
|
||||||
if b!(old.tearing != s.tearing) {
|
if old.tearing != s.tearing {
|
||||||
self.head_managers.handle_tearing_enabled_change(s.tearing);
|
self.head_managers.handle_tearing_enabled_change(s.tearing);
|
||||||
}
|
}
|
||||||
if b!(old.format != s.format) {
|
if old.format != s.format {
|
||||||
self.head_managers.handle_format_change(s.format);
|
self.head_managers.handle_format_change(s.format);
|
||||||
}
|
}
|
||||||
if b!((old.color_space, old.eotf) != (s.color_space, s.eotf)) {
|
if (old.color_space, old.eotf) != (s.color_space, s.eotf) {
|
||||||
self.head_managers
|
self.head_managers
|
||||||
.handle_colors_change(s.color_space, s.eotf);
|
.handle_colors_change(s.color_space, s.eotf);
|
||||||
}
|
}
|
||||||
if b!(old.mode != s.mode) {
|
if old.mode != s.mode {
|
||||||
self.head_managers.handle_mode_change(s.mode);
|
self.head_managers.handle_mode_change(s.mode);
|
||||||
for head in self.wlr_output_heads.lock().values() {
|
for head in self.wlr_output_heads.lock().values() {
|
||||||
head.handle_mode_change(s.mode);
|
head.handle_mode_change(s.mode);
|
||||||
|
|
@ -555,14 +537,12 @@ impl DrmDevData {
|
||||||
self.dev.clone().make_render_device();
|
self.dev.clone().make_render_device();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_direct_scanout_enabled(&self, state: &State, enabled: bool) {
|
pub fn set_direct_scanout_enabled(&self, _state: &State, enabled: bool) {
|
||||||
self.dev.set_direct_scanout_enabled(enabled);
|
self.dev.set_direct_scanout_enabled(enabled);
|
||||||
state.trigger_cci(CCI_GPUS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_flip_margin(&self, state: &State, margin: u64) {
|
pub fn set_flip_margin(&self, _state: &State, margin: u64) {
|
||||||
self.dev.set_flip_margin(margin);
|
self.dev.set_flip_margin(margin);
|
||||||
state.trigger_cci(CCI_GPUS);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -671,7 +651,6 @@ impl State {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_render_ctx(&self, ctx: Option<Rc<dyn GfxContext>>) {
|
pub fn set_render_ctx(&self, ctx: Option<Rc<dyn GfxContext>>) {
|
||||||
self.egg_state.clear();
|
|
||||||
self.explicit_sync_supported.set(false);
|
self.explicit_sync_supported.set(false);
|
||||||
self.render_ctx.set(ctx.clone());
|
self.render_ctx.set(ctx.clone());
|
||||||
self.render_ctx_version.fetch_add(1);
|
self.render_ctx_version.fetch_add(1);
|
||||||
|
|
@ -787,7 +766,6 @@ impl State {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.expose_new_singletons();
|
self.expose_new_singletons();
|
||||||
self.trigger_cci(CCI_COLOR_MANAGEMENT | CCI_GPUS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reload_cursors(&self) {
|
fn reload_cursors(&self) {
|
||||||
|
|
@ -1033,7 +1011,6 @@ impl State {
|
||||||
} else {
|
} else {
|
||||||
self.stop_xwayland();
|
self.stop_xwayland();
|
||||||
}
|
}
|
||||||
self.trigger_cci(CCI_XWAYLAND);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_xwayland_use_wire_scale(&self, use_wire_scale: bool) {
|
pub fn set_xwayland_use_wire_scale(&self, use_wire_scale: bool) {
|
||||||
|
|
@ -1041,7 +1018,6 @@ impl State {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.update_xwayland_wire_scale();
|
self.update_xwayland_wire_scale();
|
||||||
self.trigger_cci(CCI_XWAYLAND);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next_serial(&self, client: Option<&Client>) -> u64 {
|
pub fn next_serial(&self, client: Option<&Client>) -> u64 {
|
||||||
|
|
@ -1191,8 +1167,6 @@ impl State {
|
||||||
self.xdg_surface_configure_events.clear();
|
self.xdg_surface_configure_events.clear();
|
||||||
self.lazy_event_sources.clear();
|
self.lazy_event_sources.clear();
|
||||||
self.bo_drop_queue.kill();
|
self.bo_drop_queue.kill();
|
||||||
self.egg_state.clear();
|
|
||||||
self.control_centers.clear();
|
|
||||||
self.virtual_outputs.clear();
|
self.virtual_outputs.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1744,13 +1718,11 @@ impl State {
|
||||||
pub fn set_color_management_enabled(&self, enabled: bool) {
|
pub fn set_color_management_enabled(&self, enabled: bool) {
|
||||||
self.color_management_enabled.set(enabled);
|
self.color_management_enabled.set(enabled);
|
||||||
self.expose_new_singletons();
|
self.expose_new_singletons();
|
||||||
self.trigger_cci(CCI_COLOR_MANAGEMENT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_primary_selection_enabled(&self, enabled: bool) {
|
pub fn set_primary_selection_enabled(&self, enabled: bool) {
|
||||||
self.enable_primary_selection.set(enabled);
|
self.enable_primary_selection.set(enabled);
|
||||||
self.expose_new_singletons();
|
self.expose_new_singletons();
|
||||||
self.trigger_cci(CCI_LOOK_AND_FEEL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_explicit_sync_enabled(&self, enabled: bool) {
|
pub fn set_explicit_sync_enabled(&self, enabled: bool) {
|
||||||
|
|
@ -1761,7 +1733,6 @@ impl State {
|
||||||
pub fn set_log_level(&self, level: LogLevel) {
|
pub fn set_log_level(&self, level: LogLevel) {
|
||||||
if let Some(logger) = &self.logger {
|
if let Some(logger) = &self.logger {
|
||||||
logger.set_level(level);
|
logger.set_level(level);
|
||||||
self.trigger_cci(CCI_COMPOSITOR);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1794,7 +1765,6 @@ impl State {
|
||||||
self.root.clone().node_visit(&mut V);
|
self.root.clone().node_visit(&mut V);
|
||||||
self.damage(self.root.extents.get());
|
self.damage(self.root.extents.get());
|
||||||
self.icons.clear();
|
self.icons.clear();
|
||||||
self.trigger_cci(CCI_LOOK_AND_FEEL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset_colors(&self) {
|
pub fn reset_colors(&self) {
|
||||||
|
|
@ -1829,7 +1799,6 @@ impl State {
|
||||||
pub fn set_ei_socket_enabled(self: &Rc<Self>, enabled: bool) {
|
pub fn set_ei_socket_enabled(self: &Rc<Self>, enabled: bool) {
|
||||||
self.enable_ei_acceptor.set(enabled);
|
self.enable_ei_acceptor.set(enabled);
|
||||||
self.update_ei_acceptor();
|
self.update_ei_acceptor();
|
||||||
self.trigger_cci(CCI_COMPOSITOR);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_workspace_display_order(&self, order: WorkspaceDisplayOrder) {
|
pub fn set_workspace_display_order(&self, order: WorkspaceDisplayOrder) {
|
||||||
|
|
@ -1837,7 +1806,6 @@ impl State {
|
||||||
for output in self.root.outputs.lock().values() {
|
for output in self.root.outputs.lock().values() {
|
||||||
output.handle_workspace_display_order_update();
|
output.handle_workspace_display_order_update();
|
||||||
}
|
}
|
||||||
self.trigger_cci(CCI_COMPOSITOR);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spaces_changed(&self) {
|
fn spaces_changed(&self) {
|
||||||
|
|
@ -1859,7 +1827,6 @@ impl State {
|
||||||
self.root.clone().node_visit(&mut V);
|
self.root.clone().node_visit(&mut V);
|
||||||
self.damage(self.root.extents.get());
|
self.damage(self.root.extents.get());
|
||||||
self.icons.update_sizes(self);
|
self.icons.update_sizes(self);
|
||||||
self.trigger_cci(CCI_LOOK_AND_FEEL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_show_bar(&self, show: bool) {
|
pub fn set_show_bar(&self, show: bool) {
|
||||||
|
|
@ -1874,18 +1841,15 @@ impl State {
|
||||||
|
|
||||||
pub fn set_ui_drag_enabled(&self, enabled: bool) {
|
pub fn set_ui_drag_enabled(&self, enabled: bool) {
|
||||||
self.ui_drag_enabled.set(enabled);
|
self.ui_drag_enabled.set(enabled);
|
||||||
self.trigger_cci(CCI_LOOK_AND_FEEL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_ui_drag_threshold(&self, threshold: i32) {
|
pub fn set_ui_drag_threshold(&self, threshold: i32) {
|
||||||
self.ui_drag_threshold_squared
|
self.ui_drag_threshold_squared
|
||||||
.set(threshold.saturating_mul(threshold));
|
.set(threshold.saturating_mul(threshold));
|
||||||
self.trigger_cci(CCI_LOOK_AND_FEEL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_show_pin_icon(&self, show: bool) {
|
pub fn set_show_pin_icon(&self, show: bool) {
|
||||||
self.show_pin_icon.set(show);
|
self.show_pin_icon.set(show);
|
||||||
self.trigger_cci(CCI_LOOK_AND_FEEL);
|
|
||||||
for stacked in self.root.stacked.iter() {
|
for stacked in self.root.stacked.iter() {
|
||||||
if let Some(float) = stacked.deref().clone().node_into_float() {
|
if let Some(float) = stacked.deref().clone().node_into_float() {
|
||||||
float.schedule_render_titles();
|
float.schedule_render_titles();
|
||||||
|
|
@ -1895,7 +1859,6 @@ impl State {
|
||||||
|
|
||||||
pub fn set_float_above_fullscreen(&self, v: bool) {
|
pub fn set_float_above_fullscreen(&self, v: bool) {
|
||||||
self.float_above_fullscreen.set(v);
|
self.float_above_fullscreen.set(v);
|
||||||
self.trigger_cci(CCI_LOOK_AND_FEEL);
|
|
||||||
for seat in self.globals.seats.lock().values() {
|
for seat in self.globals.seats.lock().values() {
|
||||||
seat.emulate_cursor_moved();
|
seat.emulate_cursor_moved();
|
||||||
seat.trigger_tree_changed(false);
|
seat.trigger_tree_changed(false);
|
||||||
|
|
@ -1909,7 +1872,6 @@ impl State {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fonts_changed(&self) {
|
fn fonts_changed(&self) {
|
||||||
self.trigger_cci(CCI_LOOK_AND_FEEL);
|
|
||||||
struct V;
|
struct V;
|
||||||
impl NodeVisitorBase for V {
|
impl NodeVisitorBase for V {
|
||||||
fn visit_container(&mut self, node: &Rc<ContainerNode>) {
|
fn visit_container(&mut self, node: &Rc<ContainerNode>) {
|
||||||
|
|
@ -1933,7 +1895,6 @@ impl State {
|
||||||
theme.font.set(self.theme.default_font.clone());
|
theme.font.set(self.theme.default_font.clone());
|
||||||
theme.bar_font.set(None);
|
theme.bar_font.set(None);
|
||||||
theme.title_font.set(None);
|
theme.title_font.set(None);
|
||||||
self.egg_state.reset_fonts();
|
|
||||||
self.fonts_changed();
|
self.fonts_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1954,16 +1915,6 @@ impl State {
|
||||||
self.fonts_changed();
|
self.fonts_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_egui_fonts(&self, proportional: Option<Vec<&str>>, monospace: Option<Vec<&str>>) {
|
|
||||||
if let Some(fonts) = &proportional {
|
|
||||||
self.egg_state.set_proportional_fonts(fonts);
|
|
||||||
}
|
|
||||||
if let Some(fonts) = &monospace {
|
|
||||||
self.egg_state.set_monospace_fonts(fonts);
|
|
||||||
}
|
|
||||||
self.fonts_changed();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_bar_position(&self, p: BarPosition) {
|
pub fn set_bar_position(&self, p: BarPosition) {
|
||||||
self.theme.bar_position.set(p);
|
self.theme.bar_position.set(p);
|
||||||
self.spaces_changed();
|
self.spaces_changed();
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
backend::{Connector, ConnectorEvent, ConnectorId, MonitorInfo},
|
backend::{Connector, ConnectorEvent, ConnectorId, MonitorInfo},
|
||||||
control_center::CCI_OUTPUTS,
|
|
||||||
globals::GlobalName,
|
globals::GlobalName,
|
||||||
ifs::{
|
ifs::{
|
||||||
head_management::{HeadManagers, HeadState},
|
head_management::{HeadManagers, HeadState},
|
||||||
|
|
@ -95,7 +94,6 @@ pub fn handle(state: &Rc<State>, connector: &Rc<dyn Connector>) {
|
||||||
for mgr in state.head_managers.lock().values() {
|
for mgr in state.head_managers.lock().values() {
|
||||||
mgr.announce(&data);
|
mgr.announce(&data);
|
||||||
}
|
}
|
||||||
state.trigger_cci(CCI_OUTPUTS);
|
|
||||||
if state.connectors.set(id, data).is_some() {
|
if state.connectors.set(id, data).is_some() {
|
||||||
panic!("Connector id has been reused");
|
panic!("Connector id has been reused");
|
||||||
}
|
}
|
||||||
|
|
@ -135,7 +133,6 @@ impl ConnectorHandler {
|
||||||
self.data.handler.set(None);
|
self.data.handler.set(None);
|
||||||
self.state.connectors.remove(&self.id);
|
self.state.connectors.remove(&self.id);
|
||||||
self.data.head_managers.handle_removed();
|
self.data.head_managers.handle_removed();
|
||||||
self.state.trigger_cci(CCI_OUTPUTS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_connected(&self, info: MonitorInfo) {
|
async fn handle_connected(&self, info: MonitorInfo) {
|
||||||
|
|
@ -157,7 +154,6 @@ impl ConnectorHandler {
|
||||||
self.data
|
self.data
|
||||||
.head_managers
|
.head_managers
|
||||||
.handle_output_disconnected(&self.state);
|
.handle_output_disconnected(&self.state);
|
||||||
self.state.trigger_cci(CCI_OUTPUTS);
|
|
||||||
for head in self.data.wlr_output_heads.lock().drain_values() {
|
for head in self.data.wlr_output_heads.lock().drain_values() {
|
||||||
head.handle_disconnected();
|
head.handle_disconnected();
|
||||||
}
|
}
|
||||||
|
|
@ -304,7 +300,6 @@ impl ConnectorHandler {
|
||||||
self.data
|
self.data
|
||||||
.head_managers
|
.head_managers
|
||||||
.handle_output_connected(&self.state, &output_data);
|
.handle_output_connected(&self.state, &output_data);
|
||||||
self.state.trigger_cci(CCI_OUTPUTS);
|
|
||||||
self.state.wlr_output_managers.announce_head(&output_data);
|
self.state.wlr_output_managers.announce_head(&output_data);
|
||||||
global.add_damage_area(&global.pos.get());
|
global.add_damage_area(&global.pos.get());
|
||||||
self.data.damage();
|
self.data.damage();
|
||||||
|
|
@ -319,7 +314,6 @@ impl ConnectorHandler {
|
||||||
}
|
}
|
||||||
ConnectorEvent::FormatsChanged(formats) => {
|
ConnectorEvent::FormatsChanged(formats) => {
|
||||||
self.data.head_managers.handle_formats_change(&formats);
|
self.data.head_managers.handle_formats_change(&formats);
|
||||||
self.state.trigger_cci(CCI_OUTPUTS);
|
|
||||||
on.global.formats.set(formats);
|
on.global.formats.set(formats);
|
||||||
}
|
}
|
||||||
ConnectorEvent::State(state) => {
|
ConnectorEvent::State(state) => {
|
||||||
|
|
@ -433,7 +427,6 @@ impl ConnectorHandler {
|
||||||
self.data
|
self.data
|
||||||
.head_managers
|
.head_managers
|
||||||
.handle_output_connected(&self.state, &output_data);
|
.handle_output_connected(&self.state, &output_data);
|
||||||
self.state.trigger_cci(CCI_OUTPUTS);
|
|
||||||
self.state.wlr_output_managers.announce_head(&output_data);
|
self.state.wlr_output_managers.announce_head(&output_data);
|
||||||
'outer: loop {
|
'outer: loop {
|
||||||
while let Some(event) = self.data.connector.event() {
|
while let Some(event) = self.data.connector.event() {
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ use {
|
||||||
},
|
},
|
||||||
client::ClientId,
|
client::ClientId,
|
||||||
cmm::cmm_description::ColorDescription,
|
cmm::cmm_description::ColorDescription,
|
||||||
control_center::CCI_OUTPUTS,
|
|
||||||
cursor::KnownCursor,
|
cursor::KnownCursor,
|
||||||
fixed::Fixed,
|
fixed::Fixed,
|
||||||
gfx_api::{AcquireSync, BufferResv, GfxTexture, ReleaseSync},
|
gfx_api::{AcquireSync, BufferResv, GfxTexture, ReleaseSync},
|
||||||
|
|
@ -245,7 +244,6 @@ impl OutputNode {
|
||||||
.connector
|
.connector
|
||||||
.head_managers
|
.head_managers
|
||||||
.handle_tearing_active_change(tearing);
|
.handle_tearing_active_change(tearing);
|
||||||
self.state.trigger_cci(CCI_OUTPUTS);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -504,7 +502,6 @@ impl OutputNode {
|
||||||
.connector
|
.connector
|
||||||
.head_managers
|
.head_managers
|
||||||
.handle_scale_change(scale);
|
.handle_scale_change(scale);
|
||||||
self.state.trigger_cci(CCI_OUTPUTS);
|
|
||||||
for head in self.global.connector.wlr_output_heads.lock().values() {
|
for head in self.global.connector.wlr_output_heads.lock().values() {
|
||||||
head.handle_new_scale(scale);
|
head.handle_new_scale(scale);
|
||||||
}
|
}
|
||||||
|
|
@ -877,7 +874,6 @@ impl OutputNode {
|
||||||
.connector
|
.connector
|
||||||
.head_managers
|
.head_managers
|
||||||
.handle_transform_change(transform);
|
.handle_transform_change(transform);
|
||||||
self.state.trigger_cci(CCI_OUTPUTS);
|
|
||||||
for head in self.global.connector.wlr_output_heads.lock().values() {
|
for head in self.global.connector.wlr_output_heads.lock().values() {
|
||||||
head.hande_transform_change(transform);
|
head.hande_transform_change(transform);
|
||||||
}
|
}
|
||||||
|
|
@ -940,7 +936,6 @@ impl OutputNode {
|
||||||
.connector
|
.connector
|
||||||
.head_managers
|
.head_managers
|
||||||
.handle_position_size_change(self);
|
.handle_position_size_change(self);
|
||||||
self.state.trigger_cci(CCI_OUTPUTS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_state(self: &Rc<Self>, old: BackendConnectorState, state: BackendConnectorState) {
|
pub fn update_state(self: &Rc<Self>, old: BackendConnectorState, state: BackendConnectorState) {
|
||||||
|
|
@ -995,7 +990,6 @@ impl OutputNode {
|
||||||
.connector
|
.connector
|
||||||
.head_managers
|
.head_managers
|
||||||
.handle_brightness_change(brightness);
|
.handle_brightness_change(brightness);
|
||||||
self.state.trigger_cci(CCI_OUTPUTS);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1011,7 +1005,6 @@ impl OutputNode {
|
||||||
.connector
|
.connector
|
||||||
.head_managers
|
.head_managers
|
||||||
.handle_use_native_gamut_change(use_native_gamut);
|
.handle_use_native_gamut_change(use_native_gamut);
|
||||||
self.state.trigger_cci(CCI_OUTPUTS);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1023,7 +1016,6 @@ impl OutputNode {
|
||||||
.connector
|
.connector
|
||||||
.head_managers
|
.head_managers
|
||||||
.handle_blend_space_change(blend_space);
|
.handle_blend_space_change(blend_space);
|
||||||
self.state.trigger_cci(CCI_OUTPUTS);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn find_stacked_at(
|
fn find_stacked_at(
|
||||||
|
|
@ -1489,7 +1481,6 @@ impl OutputNode {
|
||||||
.connector
|
.connector
|
||||||
.head_managers
|
.head_managers
|
||||||
.handle_vrr_mode_change(mode);
|
.handle_vrr_mode_change(mode);
|
||||||
self.state.trigger_cci(CCI_OUTPUTS);
|
|
||||||
for head in self.global.connector.wlr_output_heads.lock().values() {
|
for head in self.global.connector.wlr_output_heads.lock().values() {
|
||||||
head.handle_vrr_mode_change(mode);
|
head.handle_vrr_mode_change(mode);
|
||||||
}
|
}
|
||||||
|
|
@ -1504,7 +1495,6 @@ impl OutputNode {
|
||||||
.connector
|
.connector
|
||||||
.head_managers
|
.head_managers
|
||||||
.handle_tearing_mode_change(mode);
|
.handle_tearing_mode_change(mode);
|
||||||
self.state.trigger_cci(CCI_OUTPUTS);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1554,7 +1544,6 @@ impl OutputNode {
|
||||||
|
|
||||||
pub fn set_flip_margin(&self, margin_ns: u64) {
|
pub fn set_flip_margin(&self, margin_ns: u64) {
|
||||||
self.flip_margin_ns.set(Some(margin_ns));
|
self.flip_margin_ns.set(Some(margin_ns));
|
||||||
self.state.trigger_cci(CCI_OUTPUTS);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -948,10 +948,6 @@ impl ToplevelData {
|
||||||
parent.node_is_workspace()
|
parent.node_is_workspace()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn property_changed_source(&self) -> &Rc<LazyEventSource> {
|
|
||||||
self.property_changed_source
|
|
||||||
.get_or_init(|| self.state.lazy_event_sources.create_source())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for ToplevelData {
|
impl Drop for ToplevelData {
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn load(&self, ordering: Ordering) -> T {
|
pub fn load(&self, ordering: Ordering) -> T {
|
||||||
unsafe { T::from_linear_unchecked(self.v.load(ordering)) }
|
unsafe { T::from_linear_unchecked(self.v.load(ordering)) }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -141,6 +141,7 @@ impl LazyEventSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LazyEventSources {
|
impl LazyEventSources {
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn create_source(self: &Rc<Self>) -> Rc<LazyEventSource> {
|
pub fn create_source(self: &Rc<Self>) -> Rc<LazyEventSource> {
|
||||||
Rc::new(LazyEventSource {
|
Rc::new(LazyEventSource {
|
||||||
sources: self.clone(),
|
sources: self.clone(),
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ use {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct ObjectDropQueue<T> {
|
pub struct ObjectDropQueue<T> {
|
||||||
|
#[allow(dead_code)]
|
||||||
ring: Rc<IoUring>,
|
ring: Rc<IoUring>,
|
||||||
killed: Cell<bool>,
|
killed: Cell<bool>,
|
||||||
pending: RefCell<Vec<Option<(T, PendingPoll)>>>,
|
pending: RefCell<Vec<Option<(T, PendingPoll)>>>,
|
||||||
|
|
@ -32,6 +33,7 @@ impl<T> ObjectDropQueue<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn push(self: &Rc<Self>, fd: &Rc<OwnedFd>, t: T)
|
pub fn push(self: &Rc<Self>, fd: &Rc<OwnedFd>, t: T)
|
||||||
where
|
where
|
||||||
T: 'static,
|
T: 'static,
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ pub fn pipe() -> Result<Pipe<OwnedFd, OwnedFd>, OsError> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<L, R> Pipe<L, R> {
|
impl<L, R> Pipe<L, R> {
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn map_read<Lprime>(self, map: impl FnOnce(L) -> Lprime) -> Pipe<Lprime, R> {
|
pub fn map_read<Lprime>(self, map: impl FnOnce(L) -> Lprime) -> Pipe<Lprime, R> {
|
||||||
Pipe {
|
Pipe {
|
||||||
read: map(self.read),
|
read: map(self.read),
|
||||||
|
|
@ -21,6 +22,7 @@ impl<L, R> Pipe<L, R> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn map_write<Rprime>(self, map: impl FnOnce(R) -> Rprime) -> Pipe<L, Rprime> {
|
pub fn map_write<Rprime>(self, map: impl FnOnce(R) -> Rprime) -> Pipe<L, Rprime> {
|
||||||
Pipe {
|
Pipe {
|
||||||
read: self.read,
|
read: self.read,
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,8 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
format::Format,
|
format::Format,
|
||||||
gfx_api::SyncFile,
|
|
||||||
utils::{compat::IoctlNumber, oserror::OsError},
|
utils::{compat::IoctlNumber, oserror::OsError},
|
||||||
video::{
|
video::{LINEAR_MODIFIER, Modifier},
|
||||||
LINEAR_MODIFIER, Modifier,
|
|
||||||
drm::{DrmError, syncobj::merge_sync_files},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
arrayvec::ArrayVec,
|
arrayvec::ArrayVec,
|
||||||
std::{cell::OnceCell, rc::Rc, sync::OnceLock},
|
std::{cell::OnceCell, rc::Rc, sync::OnceLock},
|
||||||
|
|
@ -118,21 +114,6 @@ impl DmaBuf {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn export_sync_file(&self, flags: u32) -> Result<Option<SyncFile>, DrmError> {
|
|
||||||
let mut sf = PlaneVec::new();
|
|
||||||
for plane in &self.planes {
|
|
||||||
sf.push(
|
|
||||||
dma_buf_export_sync_file(&plane.fd, flags)
|
|
||||||
.map(Rc::new)
|
|
||||||
.map(SyncFile)
|
|
||||||
.map_err(DrmError::ExportSyncFile)?,
|
|
||||||
);
|
|
||||||
if self.is_one_file() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
merge_sync_files(sf.iter())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const DMA_BUF_BASE: u64 = b'b' as _;
|
const DMA_BUF_BASE: u64 = b'b' as _;
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ use {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
cmm::{cmm_description::ColorDescription, cmm_primaries::Primaries},
|
cmm::{cmm_description::ColorDescription, cmm_primaries::Primaries},
|
||||||
control_center::CCI_VIRTUAL_OUTPUTS,
|
|
||||||
format::{Format, XRGB8888},
|
format::{Format, XRGB8888},
|
||||||
gfx_api::{
|
gfx_api::{
|
||||||
AcquireSync, BufferResv, DirectScanoutPosition, FdSync, GfxBlendBuffer, GfxContext,
|
AcquireSync, BufferResv, DirectScanoutPosition, FdSync, GfxBlendBuffer, GfxContext,
|
||||||
|
|
@ -285,18 +284,16 @@ impl VirtualOutputs {
|
||||||
self.outputs.set(name.to_string(), vo.clone());
|
self.outputs.set(name.to_string(), vo.clone());
|
||||||
vo.flip_task
|
vo.flip_task
|
||||||
.set(Some(state.eng.spawn("vo-flip", vo.clone().flip_task())));
|
.set(Some(state.eng.spawn("vo-flip", vo.clone().flip_task())));
|
||||||
state.trigger_cci(CCI_VIRTUAL_OUTPUTS);
|
|
||||||
vo
|
vo
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_output(&self, state: &Rc<State>, name: &str) {
|
pub fn remove_output(&self, _state: &Rc<State>, name: &str) {
|
||||||
let Some(o) = self.outputs.remove(name) else {
|
let Some(o) = self.outputs.remove(name) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
o.clear();
|
o.clear();
|
||||||
o.events.send_event(ConnectorEvent::Disconnected);
|
o.events.send_event(ConnectorEvent::Disconnected);
|
||||||
o.events.send_event(ConnectorEvent::Removed);
|
o.events.send_event(ConnectorEvent::Removed);
|
||||||
state.trigger_cci(CCI_VIRTUAL_OUTPUTS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(&self) {
|
pub fn clear(&self) {
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,8 @@ use {
|
||||||
usr_jay_screencast::UsrJayScreencast,
|
usr_jay_screencast::UsrJayScreencast,
|
||||||
usr_jay_select_toplevel::UsrJaySelectToplevel,
|
usr_jay_select_toplevel::UsrJaySelectToplevel,
|
||||||
usr_jay_select_workspace::UsrJaySelectWorkspace,
|
usr_jay_select_workspace::UsrJaySelectWorkspace,
|
||||||
usr_jay_sync_file_surface::UsrJaySyncFileSurface,
|
|
||||||
usr_jay_workspace_watcher::UsrJayWorkspaceWatcher, usr_wl_output::UsrWlOutput,
|
usr_jay_workspace_watcher::UsrJayWorkspaceWatcher, usr_wl_output::UsrWlOutput,
|
||||||
usr_wl_seat::UsrWlSeat, usr_wl_surface::UsrWlSurface,
|
usr_wl_seat::UsrWlSeat,
|
||||||
},
|
},
|
||||||
usr_object::UsrObject,
|
usr_object::UsrObject,
|
||||||
},
|
},
|
||||||
|
|
@ -189,20 +188,6 @@ impl UsrJayCompositor {
|
||||||
obj
|
obj
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_sync_file_surface(&self, surface: &UsrWlSurface) -> Rc<UsrJaySyncFileSurface> {
|
|
||||||
let obj = Rc::new(UsrJaySyncFileSurface {
|
|
||||||
id: self.con.id(),
|
|
||||||
con: self.con.clone(),
|
|
||||||
version: self.version,
|
|
||||||
});
|
|
||||||
self.con.request(GetSyncFileSurface {
|
|
||||||
self_id: self.id,
|
|
||||||
id: obj.id,
|
|
||||||
surface: surface.id,
|
|
||||||
});
|
|
||||||
self.con.add_object(obj.clone());
|
|
||||||
obj
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JayCompositorEventHandler for UsrJayCompositor {
|
impl JayCompositorEventHandler for UsrJayCompositor {
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,8 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
gfx_api::FdSync,
|
|
||||||
object::Version,
|
object::Version,
|
||||||
wire::{JaySyncFileSurfaceId, jay_sync_file_surface::*},
|
wire::{JaySyncFileSurfaceId, jay_sync_file_surface::*},
|
||||||
wl_usr::{
|
wl_usr::{UsrCon, usr_object::UsrObject},
|
||||||
UsrCon, usr_ifs::usr_jay_sync_file_release::UsrJaySyncFileRelease,
|
|
||||||
usr_object::UsrObject,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
std::{convert::Infallible, rc::Rc},
|
std::{convert::Infallible, rc::Rc},
|
||||||
};
|
};
|
||||||
|
|
@ -17,37 +13,6 @@ pub struct UsrJaySyncFileSurface {
|
||||||
pub version: Version,
|
pub version: Version,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UsrJaySyncFileSurface {
|
|
||||||
pub fn set_acquire(&self, sf: Option<&FdSync>) {
|
|
||||||
match sf.and_then(|s| s.get_sync_file()) {
|
|
||||||
None => {
|
|
||||||
self.con.request(SetAcquireImmediate { self_id: self.id });
|
|
||||||
}
|
|
||||||
Some(sf) => {
|
|
||||||
self.con.request(SetAcquireAsync {
|
|
||||||
self_id: self.id,
|
|
||||||
sync_file: sf.0.clone(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_release(&self) -> Rc<UsrJaySyncFileRelease> {
|
|
||||||
let obj = Rc::new(UsrJaySyncFileRelease {
|
|
||||||
id: self.con.id(),
|
|
||||||
con: self.con.clone(),
|
|
||||||
owner: Default::default(),
|
|
||||||
version: self.version,
|
|
||||||
});
|
|
||||||
self.con.request(GetRelease {
|
|
||||||
self_id: self.id,
|
|
||||||
release: obj.id,
|
|
||||||
});
|
|
||||||
self.con.add_object(obj.clone());
|
|
||||||
obj
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl JaySyncFileSurfaceEventHandler for UsrJaySyncFileSurface {
|
impl JaySyncFileSurfaceEventHandler for UsrJaySyncFileSurface {
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use {
|
||||||
wire::{WlDataDeviceId, wl_data_device::*},
|
wire::{WlDataDeviceId, wl_data_device::*},
|
||||||
wl_usr::{
|
wl_usr::{
|
||||||
UsrCon,
|
UsrCon,
|
||||||
usr_ifs::{usr_wl_data_offer::UsrWlDataOffer, usr_wl_data_source::UsrWlDataSource},
|
usr_ifs::usr_wl_data_offer::UsrWlDataOffer,
|
||||||
usr_object::UsrObject,
|
usr_object::UsrObject,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -20,16 +20,6 @@ pub struct UsrWlDataDevice {
|
||||||
pub selection: CloneCell<Option<Rc<UsrWlDataOffer>>>,
|
pub selection: CloneCell<Option<Rc<UsrWlDataOffer>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UsrWlDataDevice {
|
|
||||||
pub fn set_selection(&self, serial: u32, source: &UsrWlDataSource) {
|
|
||||||
self.con.request(SetSelection {
|
|
||||||
self_id: self.id,
|
|
||||||
source: source.id,
|
|
||||||
serial,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WlDataDeviceEventHandler for UsrWlDataDevice {
|
impl WlDataDeviceEventHandler for UsrWlDataDevice {
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,7 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
object::Version,
|
object::Version,
|
||||||
wire::{WlDataDeviceManagerId, wl_data_device_manager::*},
|
wire::{WlDataDeviceManagerId, wl_data_device_manager::*},
|
||||||
wl_usr::{
|
wl_usr::{UsrCon, usr_object::UsrObject},
|
||||||
UsrCon,
|
|
||||||
usr_ifs::{
|
|
||||||
usr_wl_data_device::UsrWlDataDevice, usr_wl_data_source::UsrWlDataSource,
|
|
||||||
usr_wl_seat::UsrWlSeat,
|
|
||||||
},
|
|
||||||
usr_object::UsrObject,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
std::{convert::Infallible, rc::Rc},
|
std::{convert::Infallible, rc::Rc},
|
||||||
};
|
};
|
||||||
|
|
@ -20,40 +13,6 @@ pub struct UsrWlDataDeviceManager {
|
||||||
pub version: Version,
|
pub version: Version,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UsrWlDataDeviceManager {
|
|
||||||
pub fn create_data_source(&self) -> Rc<UsrWlDataSource> {
|
|
||||||
let obj = Rc::new(UsrWlDataSource {
|
|
||||||
id: self.con.id(),
|
|
||||||
con: self.con.clone(),
|
|
||||||
owner: Default::default(),
|
|
||||||
version: self.version,
|
|
||||||
});
|
|
||||||
self.con.request(CreateDataSource {
|
|
||||||
self_id: self.id,
|
|
||||||
id: obj.id,
|
|
||||||
});
|
|
||||||
self.con.add_object(obj.clone());
|
|
||||||
obj
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_data_device(&self, seat: &UsrWlSeat) -> Rc<UsrWlDataDevice> {
|
|
||||||
let obj = Rc::new(UsrWlDataDevice {
|
|
||||||
id: self.con.id(),
|
|
||||||
con: self.con.clone(),
|
|
||||||
version: self.version,
|
|
||||||
offer: Default::default(),
|
|
||||||
selection: Default::default(),
|
|
||||||
});
|
|
||||||
self.con.request(GetDataDevice {
|
|
||||||
self_id: self.id,
|
|
||||||
id: obj.id,
|
|
||||||
seat: seat.id,
|
|
||||||
});
|
|
||||||
self.con.add_object(obj.clone());
|
|
||||||
obj
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WlDataDeviceManagerEventHandler for UsrWlDataDeviceManager {
|
impl WlDataDeviceManagerEventHandler for UsrWlDataDeviceManager {
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ use {
|
||||||
},
|
},
|
||||||
ahash::AHashSet,
|
ahash::AHashSet,
|
||||||
std::{cell::RefCell, convert::Infallible, rc::Rc},
|
std::{cell::RefCell, convert::Infallible, rc::Rc},
|
||||||
uapi::OwnedFd,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct UsrWlDataOffer {
|
pub struct UsrWlDataOffer {
|
||||||
|
|
@ -16,16 +15,6 @@ pub struct UsrWlDataOffer {
|
||||||
pub mime_types: RefCell<AHashSet<String>>,
|
pub mime_types: RefCell<AHashSet<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UsrWlDataOffer {
|
|
||||||
pub fn receive(&self, mime_type: &str, fd: &Rc<OwnedFd>) {
|
|
||||||
self.con.request(Receive {
|
|
||||||
self_id: self.id,
|
|
||||||
mime_type,
|
|
||||||
fd: fd.clone(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WlDataOfferEventHandler for UsrWlDataOffer {
|
impl WlDataOfferEventHandler for UsrWlDataOffer {
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,15 +20,6 @@ pub trait UsrWlDataSourceOwner {
|
||||||
fn send(&self, mime_type: &str, fd: Rc<OwnedFd>);
|
fn send(&self, mime_type: &str, fd: Rc<OwnedFd>);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UsrWlDataSource {
|
|
||||||
pub fn offer(&self, mime_type: &str) {
|
|
||||||
self.con.request(Offer {
|
|
||||||
self_id: self.id,
|
|
||||||
mime_type,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WlDataSourceEventHandler for UsrWlDataSource {
|
impl WlDataSourceEventHandler for UsrWlDataSource {
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ use {
|
||||||
ifs::wl_seat::wl_pointer::PendingScroll,
|
ifs::wl_seat::wl_pointer::PendingScroll,
|
||||||
object::Version,
|
object::Version,
|
||||||
utils::clonecell::CloneCell,
|
utils::clonecell::CloneCell,
|
||||||
wire::{WlPointerId, WlSurfaceId, wl_pointer::*},
|
wire::{WlPointerId, wl_pointer::*},
|
||||||
wl_usr::{UsrCon, usr_ifs::usr_wl_surface::UsrWlSurface, usr_object::UsrObject},
|
wl_usr::{UsrCon, usr_object::UsrObject},
|
||||||
},
|
},
|
||||||
std::{cell::Cell, convert::Infallible, rc::Rc},
|
std::{cell::Cell, convert::Infallible, rc::Rc},
|
||||||
};
|
};
|
||||||
|
|
@ -40,18 +40,6 @@ pub trait UsrWlPointerOwner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UsrWlPointer {
|
|
||||||
pub fn set_cursor(&self, serial: u32, cursor: Option<&UsrWlSurface>, hot_x: i32, hot_y: i32) {
|
|
||||||
self.con.request(SetCursor {
|
|
||||||
self_id: self.id,
|
|
||||||
serial,
|
|
||||||
surface: cursor.map(|c| c.id).unwrap_or(WlSurfaceId::NONE),
|
|
||||||
hotspot_x: hot_x,
|
|
||||||
hotspot_y: hot_y,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WlPointerEventHandler for UsrWlPointer {
|
impl WlPointerEventHandler for UsrWlPointer {
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use {
|
||||||
wire::{WlSeatId, wl_seat::*},
|
wire::{WlSeatId, wl_seat::*},
|
||||||
wl_usr::{
|
wl_usr::{
|
||||||
UsrCon,
|
UsrCon,
|
||||||
usr_ifs::{usr_wl_keyboard::UsrWlKeyboard, usr_wl_pointer::UsrWlPointer},
|
usr_ifs::usr_wl_pointer::UsrWlPointer,
|
||||||
usr_object::UsrObject,
|
usr_object::UsrObject,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -47,21 +47,6 @@ impl UsrWlSeat {
|
||||||
ptr
|
ptr
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_keyboard(&self) -> Rc<UsrWlKeyboard> {
|
|
||||||
let kb = Rc::new(UsrWlKeyboard {
|
|
||||||
id: self.con.id(),
|
|
||||||
con: self.con.clone(),
|
|
||||||
keyboard: Default::default(),
|
|
||||||
owner: Default::default(),
|
|
||||||
version: self.version,
|
|
||||||
});
|
|
||||||
self.con.add_object(kb.clone());
|
|
||||||
self.con.request(GetKeyboard {
|
|
||||||
self_id: self.id,
|
|
||||||
id: kb.id,
|
|
||||||
});
|
|
||||||
kb
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WlSeatEventHandler for UsrWlSeat {
|
impl WlSeatEventHandler for UsrWlSeat {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
cursor::KnownCursor,
|
|
||||||
object::Version,
|
object::Version,
|
||||||
wire::{WpCursorShapeDeviceV1Id, wp_cursor_shape_device_v1::*},
|
wire::{WpCursorShapeDeviceV1Id, wp_cursor_shape_device_v1::*},
|
||||||
wl_usr::{UsrCon, usr_object::UsrObject},
|
wl_usr::{UsrCon, usr_object::UsrObject},
|
||||||
|
|
@ -14,16 +13,6 @@ pub struct UsrWpCursorShapeDeviceV1 {
|
||||||
pub version: Version,
|
pub version: Version,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UsrWpCursorShapeDeviceV1 {
|
|
||||||
pub fn set_shape(&self, serial: u32, cursor: KnownCursor) {
|
|
||||||
self.con.request(SetShape {
|
|
||||||
self_id: self.id,
|
|
||||||
serial,
|
|
||||||
shape: cursor.to_shape(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WpCursorShapeDeviceV1EventHandler for UsrWpCursorShapeDeviceV1 {
|
impl WpCursorShapeDeviceV1EventHandler for UsrWpCursorShapeDeviceV1 {
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,7 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
object::Version,
|
object::Version,
|
||||||
wire::{WpCursorShapeManagerV1Id, wp_cursor_shape_manager_v1::*},
|
wire::{WpCursorShapeManagerV1Id, wp_cursor_shape_manager_v1::*},
|
||||||
wl_usr::{
|
wl_usr::{UsrCon, usr_object::UsrObject},
|
||||||
UsrCon,
|
|
||||||
usr_ifs::{
|
|
||||||
usr_wl_pointer::UsrWlPointer,
|
|
||||||
usr_wp_cursor_shape_device_v1::UsrWpCursorShapeDeviceV1,
|
|
||||||
},
|
|
||||||
usr_object::UsrObject,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
std::{convert::Infallible, rc::Rc},
|
std::{convert::Infallible, rc::Rc},
|
||||||
};
|
};
|
||||||
|
|
@ -20,23 +13,6 @@ pub struct UsrWpCursorShapeManagerV1 {
|
||||||
pub version: Version,
|
pub version: Version,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UsrWpCursorShapeManagerV1 {
|
|
||||||
pub fn get_pointer(&self, pointer: &UsrWlPointer) -> Rc<UsrWpCursorShapeDeviceV1> {
|
|
||||||
let obj = Rc::new(UsrWpCursorShapeDeviceV1 {
|
|
||||||
id: self.con.id(),
|
|
||||||
con: self.con.clone(),
|
|
||||||
version: self.version,
|
|
||||||
});
|
|
||||||
self.con.request(GetPointer {
|
|
||||||
self_id: self.id,
|
|
||||||
cursor_shape_device: obj.id,
|
|
||||||
pointer: pointer.id,
|
|
||||||
});
|
|
||||||
self.con.add_object(obj.clone());
|
|
||||||
obj
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WpCursorShapeManagerV1EventHandler for UsrWpCursorShapeManagerV1 {
|
impl WpCursorShapeManagerV1EventHandler for UsrWpCursorShapeManagerV1 {
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use {
|
||||||
object::Version,
|
object::Version,
|
||||||
utils::clonecell::CloneCell,
|
utils::clonecell::CloneCell,
|
||||||
wire::{XdgSurfaceId, xdg_surface::*},
|
wire::{XdgSurfaceId, xdg_surface::*},
|
||||||
wl_usr::{UsrCon, usr_ifs::usr_xdg_toplevel::UsrXdgToplevel, usr_object::UsrObject},
|
wl_usr::{UsrCon, usr_object::UsrObject},
|
||||||
},
|
},
|
||||||
std::{convert::Infallible, rc::Rc},
|
std::{convert::Infallible, rc::Rc},
|
||||||
};
|
};
|
||||||
|
|
@ -21,23 +21,6 @@ pub trait UsrXdgSurfaceOwner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UsrXdgSurface {
|
|
||||||
pub fn get_toplevel(&self) -> Rc<UsrXdgToplevel> {
|
|
||||||
let obj = Rc::new(UsrXdgToplevel {
|
|
||||||
id: self.con.id(),
|
|
||||||
con: self.con.clone(),
|
|
||||||
owner: Default::default(),
|
|
||||||
version: self.version,
|
|
||||||
});
|
|
||||||
self.con.request(GetToplevel {
|
|
||||||
self_id: self.id,
|
|
||||||
id: obj.id,
|
|
||||||
});
|
|
||||||
self.con.add_object(obj.clone());
|
|
||||||
obj
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl XdgSurfaceEventHandler for UsrXdgSurface {
|
impl XdgSurfaceEventHandler for UsrXdgSurface {
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
object::Version,
|
object::Version,
|
||||||
utils::clonecell::CloneCell,
|
utils::clonecell::CloneCell,
|
||||||
wire::{WlOutputId, XdgToplevelId, xdg_toplevel::*},
|
wire::{XdgToplevelId, xdg_toplevel::*},
|
||||||
wl_usr::{UsrCon, usr_object::UsrObject},
|
wl_usr::{UsrCon, usr_object::UsrObject},
|
||||||
},
|
},
|
||||||
std::{convert::Infallible, rc::Rc},
|
std::{convert::Infallible, rc::Rc},
|
||||||
|
|
@ -15,29 +15,6 @@ pub struct UsrXdgToplevel {
|
||||||
pub version: Version,
|
pub version: Version,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UsrXdgToplevel {
|
|
||||||
pub fn set_title(&self, title: &str) {
|
|
||||||
self.con.request(SetTitle {
|
|
||||||
self_id: self.id,
|
|
||||||
title,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_fullscreen(&self, fullscreen: bool) {
|
|
||||||
match fullscreen {
|
|
||||||
true => {
|
|
||||||
self.con.request(SetFullscreen {
|
|
||||||
self_id: self.id,
|
|
||||||
output: WlOutputId::NONE,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
false => {
|
|
||||||
self.con.request(UnsetFullscreen { self_id: self.id });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait UsrXdgToplevelOwner {
|
pub trait UsrXdgToplevelOwner {
|
||||||
fn configure(&self, width: i32, height: i32) {
|
fn configure(&self, width: i32, height: i32) {
|
||||||
let _ = width;
|
let _ = width;
|
||||||
|
|
@ -49,8 +26,6 @@ pub trait UsrXdgToplevelOwner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UsrXdgToplevel {}
|
|
||||||
|
|
||||||
impl XdgToplevelEventHandler for UsrXdgToplevel {
|
impl XdgToplevelEventHandler for UsrXdgToplevel {
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,7 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
object::Version,
|
object::Version,
|
||||||
wire::{XdgWmBaseId, xdg_wm_base::*},
|
wire::{XdgWmBaseId, xdg_wm_base::*},
|
||||||
wl_usr::{
|
wl_usr::{UsrCon, usr_object::UsrObject},
|
||||||
UsrCon,
|
|
||||||
usr_ifs::{usr_wl_surface::UsrWlSurface, usr_xdg_surface::UsrXdgSurface},
|
|
||||||
usr_object::UsrObject,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
std::{convert::Infallible, rc::Rc},
|
std::{convert::Infallible, rc::Rc},
|
||||||
};
|
};
|
||||||
|
|
@ -17,24 +13,6 @@ pub struct UsrXdgWmBase {
|
||||||
pub version: Version,
|
pub version: Version,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UsrXdgWmBase {
|
|
||||||
pub fn get_xdg_surface(&self, surface: &UsrWlSurface) -> Rc<UsrXdgSurface> {
|
|
||||||
let obj = Rc::new(UsrXdgSurface {
|
|
||||||
id: self.con.id(),
|
|
||||||
con: self.con.clone(),
|
|
||||||
owner: Default::default(),
|
|
||||||
version: self.version,
|
|
||||||
});
|
|
||||||
self.con.request(GetXdgSurface {
|
|
||||||
self_id: self.id,
|
|
||||||
id: obj.id,
|
|
||||||
surface: surface.id,
|
|
||||||
});
|
|
||||||
self.con.add_object(obj.clone());
|
|
||||||
obj
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl XdgWmBaseEventHandler for UsrXdgWmBase {
|
impl XdgWmBaseEventHandler for UsrXdgWmBase {
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,10 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
format::Format,
|
|
||||||
object::Version,
|
object::Version,
|
||||||
video::Modifier,
|
|
||||||
wire::{ZwpLinuxBufferParamsV1Id, zwp_linux_buffer_params_v1::*},
|
wire::{ZwpLinuxBufferParamsV1Id, zwp_linux_buffer_params_v1::*},
|
||||||
wl_usr::{UsrCon, usr_ifs::usr_wl_buffer::UsrWlBuffer, usr_object::UsrObject},
|
wl_usr::{UsrCon, usr_object::UsrObject},
|
||||||
},
|
},
|
||||||
std::{convert::Infallible, rc::Rc},
|
std::{convert::Infallible, rc::Rc},
|
||||||
uapi::OwnedFd,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct UsrZwpLinuxBufferParamsV1 {
|
pub struct UsrZwpLinuxBufferParamsV1 {
|
||||||
|
|
@ -16,45 +13,6 @@ pub struct UsrZwpLinuxBufferParamsV1 {
|
||||||
pub version: Version,
|
pub version: Version,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UsrZwpLinuxBufferParamsV1 {
|
|
||||||
pub fn add(
|
|
||||||
&self,
|
|
||||||
fd: &Rc<OwnedFd>,
|
|
||||||
plane_idx: usize,
|
|
||||||
offset: u32,
|
|
||||||
stride: u32,
|
|
||||||
modifier: Modifier,
|
|
||||||
) {
|
|
||||||
self.con.request(Add {
|
|
||||||
self_id: self.id,
|
|
||||||
fd: fd.clone(),
|
|
||||||
plane_idx: plane_idx as u32,
|
|
||||||
offset,
|
|
||||||
stride,
|
|
||||||
modifier,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_immed(&self, width: i32, height: i32, format: &Format) -> Rc<UsrWlBuffer> {
|
|
||||||
let obj = Rc::new(UsrWlBuffer {
|
|
||||||
id: self.con.id(),
|
|
||||||
con: self.con.clone(),
|
|
||||||
owner: Default::default(),
|
|
||||||
version: self.version,
|
|
||||||
});
|
|
||||||
self.con.request(CreateImmed {
|
|
||||||
self_id: self.id,
|
|
||||||
buffer_id: obj.id,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
format: format.drm,
|
|
||||||
flags: 0,
|
|
||||||
});
|
|
||||||
self.con.add_object(obj.clone());
|
|
||||||
obj
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ZwpLinuxBufferParamsV1EventHandler for UsrZwpLinuxBufferParamsV1 {
|
impl ZwpLinuxBufferParamsV1EventHandler for UsrZwpLinuxBufferParamsV1 {
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,8 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
object::Version,
|
object::Version,
|
||||||
video::dmabuf::DmaBuf,
|
|
||||||
wire::{ZwpLinuxDmabufV1Id, zwp_linux_dmabuf_v1::*},
|
wire::{ZwpLinuxDmabufV1Id, zwp_linux_dmabuf_v1::*},
|
||||||
wl_usr::{
|
wl_usr::{UsrCon, usr_object::UsrObject},
|
||||||
UsrCon,
|
|
||||||
usr_ifs::{
|
|
||||||
usr_wl_buffer::UsrWlBuffer,
|
|
||||||
usr_zwp_linux_buffer_params_v1::UsrZwpLinuxBufferParamsV1,
|
|
||||||
},
|
|
||||||
usr_object::UsrObject,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
std::{convert::Infallible, rc::Rc},
|
std::{convert::Infallible, rc::Rc},
|
||||||
};
|
};
|
||||||
|
|
@ -21,27 +13,6 @@ pub struct UsrZwpLinuxDmabufV1 {
|
||||||
pub version: Version,
|
pub version: Version,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UsrZwpLinuxDmabufV1 {
|
|
||||||
pub fn create_buffer(&self, buffer: &DmaBuf) -> Rc<UsrWlBuffer> {
|
|
||||||
let params = Rc::new(UsrZwpLinuxBufferParamsV1 {
|
|
||||||
id: self.con.id(),
|
|
||||||
con: self.con.clone(),
|
|
||||||
version: self.version,
|
|
||||||
});
|
|
||||||
self.con.request(CreateParams {
|
|
||||||
self_id: self.id,
|
|
||||||
params_id: params.id,
|
|
||||||
});
|
|
||||||
self.con.add_object(params.clone());
|
|
||||||
for (idx, plane) in buffer.planes.iter().enumerate() {
|
|
||||||
params.add(&plane.fd, idx, plane.offset, plane.stride, buffer.modifier);
|
|
||||||
}
|
|
||||||
let obj = params.create_immed(buffer.width, buffer.height, &buffer.format);
|
|
||||||
self.con.remove_obj(&*params);
|
|
||||||
obj
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ZwpLinuxDmabufV1EventHandler for UsrZwpLinuxDmabufV1 {
|
impl ZwpLinuxDmabufV1EventHandler for UsrZwpLinuxDmabufV1 {
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
client::{ClientCaps, ClientError},
|
client::{ClientCaps, ClientError},
|
||||||
compositor::DISPLAY,
|
compositor::DISPLAY,
|
||||||
control_center::CCI_XWAYLAND,
|
|
||||||
forker::{ForkerError, ForkerProxy},
|
forker::{ForkerError, ForkerProxy},
|
||||||
ifs::{
|
ifs::{
|
||||||
ipc::{DataOfferId, DataSourceId, IpcLocation, x_data_offer::XDataOffer},
|
ipc::{DataOfferId, DataSourceId, IpcLocation, x_data_offer::XDataOffer},
|
||||||
|
|
@ -118,11 +117,9 @@ pub async fn manage(state: Rc<State>) {
|
||||||
let display = Rc::new(format!(":{}", xsocket.id));
|
let display = Rc::new(format!(":{}", xsocket.id));
|
||||||
forker.setenv(DISPLAY.as_bytes(), display.as_bytes());
|
forker.setenv(DISPLAY.as_bytes(), display.as_bytes());
|
||||||
state.xwayland.display.set(Some(display.clone()));
|
state.xwayland.display.set(Some(display.clone()));
|
||||||
state.trigger_cci(CCI_XWAYLAND);
|
|
||||||
let _unsetenv = on_drop(|| {
|
let _unsetenv = on_drop(|| {
|
||||||
forker.unsetenv(DISPLAY.as_bytes());
|
forker.unsetenv(DISPLAY.as_bytes());
|
||||||
state.xwayland.display.take();
|
state.xwayland.display.take();
|
||||||
state.trigger_cci(CCI_XWAYLAND);
|
|
||||||
});
|
});
|
||||||
log::info!("Allocated display :{} for Xwayland", xsocket.id);
|
log::info!("Allocated display :{} for Xwayland", xsocket.id);
|
||||||
log::info!("Waiting for connection attempt");
|
log::info!("Waiting for connection attempt");
|
||||||
|
|
@ -209,11 +206,9 @@ async fn run(
|
||||||
state.xwayland.queue.clear();
|
state.xwayland.queue.clear();
|
||||||
state.xwayland.pidfd.set(Some(pidfd.clone()));
|
state.xwayland.pidfd.set(Some(pidfd.clone()));
|
||||||
state.xwayland.client.set(Some(client.clone()));
|
state.xwayland.client.set(Some(client.clone()));
|
||||||
state.trigger_cci(CCI_XWAYLAND);
|
|
||||||
let _remove_pidfd = on_drop(|| {
|
let _remove_pidfd = on_drop(|| {
|
||||||
state.xwayland.pidfd.take();
|
state.xwayland.pidfd.take();
|
||||||
state.xwayland.client.take();
|
state.xwayland.client.take();
|
||||||
state.trigger_cci(CCI_XWAYLAND);
|
|
||||||
});
|
});
|
||||||
{
|
{
|
||||||
let shared = Rc::new(XwmShared::default());
|
let shared = Rc::new(XwmShared::default());
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,6 @@ pub enum SimpleCommand {
|
||||||
ToggleSimpleImEnabled,
|
ToggleSimpleImEnabled,
|
||||||
ReloadSimpleIm,
|
ReloadSimpleIm,
|
||||||
EnableUnicodeInput,
|
EnableUnicodeInput,
|
||||||
OpenControlCenter,
|
|
||||||
WarpMouseToFocus,
|
WarpMouseToFocus,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -226,12 +225,6 @@ pub struct Theme {
|
||||||
pub bar_separator_width: Option<i32>,
|
pub bar_separator_width: Option<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
|
||||||
pub struct Egui {
|
|
||||||
pub proportional_fonts: Option<Vec<String>>,
|
|
||||||
pub monospace_fonts: Option<Vec<String>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Status {
|
pub struct Status {
|
||||||
pub format: MessageFormat,
|
pub format: MessageFormat,
|
||||||
|
|
@ -532,7 +525,6 @@ pub struct Config {
|
||||||
pub log_level: Option<LogLevel>,
|
pub log_level: Option<LogLevel>,
|
||||||
pub clean_logs_older_than: Option<Duration>,
|
pub clean_logs_older_than: Option<Duration>,
|
||||||
pub theme: Theme,
|
pub theme: Theme,
|
||||||
pub egui: Egui,
|
|
||||||
pub gfx_api: Option<GfxApi>,
|
pub gfx_api: Option<GfxApi>,
|
||||||
pub direct_scanout_enabled: Option<bool>,
|
pub direct_scanout_enabled: Option<bool>,
|
||||||
pub drm_devices: Vec<ConfigDrmDevice>,
|
pub drm_devices: Vec<ConfigDrmDevice>,
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ mod connector_match;
|
||||||
mod content_type;
|
mod content_type;
|
||||||
mod drm_device;
|
mod drm_device;
|
||||||
mod drm_device_match;
|
mod drm_device_match;
|
||||||
mod egui;
|
|
||||||
mod env;
|
mod env;
|
||||||
pub mod exec;
|
pub mod exec;
|
||||||
mod fallback_output_mode;
|
mod fallback_output_mode;
|
||||||
|
|
|
||||||
|
|
@ -168,7 +168,6 @@ impl ActionParser<'_> {
|
||||||
"toggle-simple-im-enabled" => ToggleSimpleImEnabled,
|
"toggle-simple-im-enabled" => ToggleSimpleImEnabled,
|
||||||
"reload-simple-im" => ReloadSimpleIm,
|
"reload-simple-im" => ReloadSimpleIm,
|
||||||
"enable-unicode-input" => EnableUnicodeInput,
|
"enable-unicode-input" => EnableUnicodeInput,
|
||||||
"open-control-center" => OpenControlCenter,
|
|
||||||
"warp-mouse-to-focus" => WarpMouseToFocus,
|
"warp-mouse-to-focus" => WarpMouseToFocus,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(
|
return Err(
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
config::{
|
config::{
|
||||||
Action, Config, Egui, Libei, Theme, UiDrag,
|
Action, Config, Libei, Theme, UiDrag,
|
||||||
context::Context,
|
context::Context,
|
||||||
extractor::{Extractor, ExtractorError, arr, bol, int, opt, recover, str, val},
|
extractor::{Extractor, ExtractorError, arr, bol, int, opt, recover, str, val},
|
||||||
parser::{DataType, ParseResult, Parser, UnexpectedDataType},
|
parser::{DataType, ParseResult, Parser, UnexpectedDataType},
|
||||||
|
|
@ -14,7 +14,6 @@ use {
|
||||||
connector::ConnectorsParser,
|
connector::ConnectorsParser,
|
||||||
drm_device::DrmDevicesParser,
|
drm_device::DrmDevicesParser,
|
||||||
drm_device_match::DrmDeviceMatchParser,
|
drm_device_match::DrmDeviceMatchParser,
|
||||||
egui::EguiParser,
|
|
||||||
env::EnvParser,
|
env::EnvParser,
|
||||||
fallback_output_mode::FallbackOutputModeParser,
|
fallback_output_mode::FallbackOutputModeParser,
|
||||||
float::FloatParser,
|
float::FloatParser,
|
||||||
|
|
@ -152,7 +151,6 @@ impl Parser for ConfigParser<'_> {
|
||||||
simple_im_val,
|
simple_im_val,
|
||||||
show_titles,
|
show_titles,
|
||||||
fallback_output_mode_val,
|
fallback_output_mode_val,
|
||||||
egui_val,
|
|
||||||
clean_logs_older_than_val,
|
clean_logs_older_than_val,
|
||||||
mouse_follows_focus,
|
mouse_follows_focus,
|
||||||
),
|
),
|
||||||
|
|
@ -213,7 +211,6 @@ impl Parser for ConfigParser<'_> {
|
||||||
opt(val("simple-im")),
|
opt(val("simple-im")),
|
||||||
recover(opt(bol("show-titles"))),
|
recover(opt(bol("show-titles"))),
|
||||||
opt(val("fallback-output-mode")),
|
opt(val("fallback-output-mode")),
|
||||||
opt(val("egui")),
|
|
||||||
opt(val("clean-logs-older-than")),
|
opt(val("clean-logs-older-than")),
|
||||||
recover(opt(bol("unstable-mouse-follows-focus"))),
|
recover(opt(bol("unstable-mouse-follows-focus"))),
|
||||||
),
|
),
|
||||||
|
|
@ -332,15 +329,6 @@ impl Parser for ConfigParser<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut egui = Egui::default();
|
|
||||||
if let Some(value) = egui_val {
|
|
||||||
match value.parse(&mut EguiParser(self.0)) {
|
|
||||||
Ok(v) => egui = v,
|
|
||||||
Err(e) => {
|
|
||||||
log::warn!("Could not parse the egui settings: {}", self.0.error(e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let mut gfx_api = None;
|
let mut gfx_api = None;
|
||||||
if let Some(value) = gfx_api_val {
|
if let Some(value) = gfx_api_val {
|
||||||
match value.parse(&mut GfxApiParser) {
|
match value.parse(&mut GfxApiParser) {
|
||||||
|
|
@ -585,7 +573,6 @@ impl Parser for ConfigParser<'_> {
|
||||||
log_level,
|
log_level,
|
||||||
clean_logs_older_than,
|
clean_logs_older_than,
|
||||||
theme,
|
theme,
|
||||||
egui,
|
|
||||||
gfx_api,
|
gfx_api,
|
||||||
drm_devices,
|
drm_devices,
|
||||||
direct_scanout_enabled: direct_scanout.despan(),
|
direct_scanout_enabled: direct_scanout.despan(),
|
||||||
|
|
|
||||||
|
|
@ -1,63 +0,0 @@
|
||||||
use {
|
|
||||||
crate::{
|
|
||||||
config::{
|
|
||||||
Egui,
|
|
||||||
context::Context,
|
|
||||||
extractor::{Extractor, ExtractorError, arr, opt},
|
|
||||||
parser::{DataType, ParseResult, Parser, UnexpectedDataType},
|
|
||||||
},
|
|
||||||
toml::{
|
|
||||||
toml_span::{Span, Spanned},
|
|
||||||
toml_value::Value,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
indexmap::IndexMap,
|
|
||||||
thiserror::Error,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct EguiParser<'a>(pub &'a Context<'a>);
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
pub enum EguiParserError {
|
|
||||||
#[error(transparent)]
|
|
||||||
Expected(#[from] UnexpectedDataType),
|
|
||||||
#[error(transparent)]
|
|
||||||
Extractor(#[from] ExtractorError),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parser for EguiParser<'_> {
|
|
||||||
type Value = Egui;
|
|
||||||
type Error = EguiParserError;
|
|
||||||
const EXPECTED: &'static [DataType] = &[DataType::Table];
|
|
||||||
|
|
||||||
fn parse_table(
|
|
||||||
&mut self,
|
|
||||||
span: Span,
|
|
||||||
table: &IndexMap<Spanned<String>, Spanned<Value>>,
|
|
||||||
) -> ParseResult<Self> {
|
|
||||||
let mut ext = Extractor::new(self.0, span, table);
|
|
||||||
let (proportional_fonts_arr, monospace_fonts_arr) =
|
|
||||||
ext.extract((opt(arr("proportional-fonts")), opt(arr("monospace-fonts"))))?;
|
|
||||||
let mut proportional_fonts = None;
|
|
||||||
let mut monospace_fonts = None;
|
|
||||||
for (out, f) in [
|
|
||||||
(&mut proportional_fonts, proportional_fonts_arr),
|
|
||||||
(&mut monospace_fonts, monospace_fonts_arr),
|
|
||||||
] {
|
|
||||||
if let Some(f) = f {
|
|
||||||
let fonts = out.insert(vec![]);
|
|
||||||
for f in f.value {
|
|
||||||
let Value::String(s) = &f.value else {
|
|
||||||
log::error!("Expected a string: {}", self.0.error3(f.span));
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
fonts.push(s.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(Egui {
|
|
||||||
proportional_fonts,
|
|
||||||
monospace_fonts,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -31,7 +31,6 @@ alt-m = "toggle-mono"
|
||||||
alt-u = "toggle-fullscreen"
|
alt-u = "toggle-fullscreen"
|
||||||
|
|
||||||
alt-f = "focus-parent"
|
alt-f = "focus-parent"
|
||||||
alt-c = "open-control-center"
|
|
||||||
alt-shift-c = "close"
|
alt-shift-c = "close"
|
||||||
alt-shift-f = "toggle-floating"
|
alt-shift-f = "toggle-floating"
|
||||||
Super_L = { type = "exec", exec = "alacritty" }
|
Super_L = { type = "exec", exec = "alacritty" }
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ use {
|
||||||
is_reload,
|
is_reload,
|
||||||
keyboard::Keymap,
|
keyboard::Keymap,
|
||||||
logging::{clean_logs_older_than, set_log_level},
|
logging::{clean_logs_older_than, set_log_level},
|
||||||
on_devices_enumerated, on_idle, on_unload, open_control_center, quit, reload,
|
on_devices_enumerated, on_idle, on_unload, quit, reload,
|
||||||
set_color_management_enabled, set_default_workspace_capture, set_explicit_sync_enabled,
|
set_color_management_enabled, set_default_workspace_capture, set_explicit_sync_enabled,
|
||||||
set_float_above_fullscreen, set_idle, set_idle_grace_period,
|
set_float_above_fullscreen, set_idle, set_idle_grace_period,
|
||||||
set_middle_click_paste_enabled, set_show_bar, set_show_float_pin_icon, set_show_titles,
|
set_middle_click_paste_enabled, set_show_bar, set_show_float_pin_icon, set_show_titles,
|
||||||
|
|
@ -45,8 +45,8 @@ use {
|
||||||
switch_to_vt,
|
switch_to_vt,
|
||||||
tasks::{self, JoinHandle},
|
tasks::{self, JoinHandle},
|
||||||
theme::{
|
theme::{
|
||||||
reset_colors, reset_font, reset_sizes, set_bar_font, set_bar_position,
|
reset_colors, reset_font, reset_sizes, set_bar_font, set_bar_position, set_font,
|
||||||
set_egui_monospace_fonts, set_egui_proportional_fonts, set_font, set_title_font,
|
set_title_font,
|
||||||
},
|
},
|
||||||
toggle_float_above_fullscreen, toggle_show_bar, toggle_show_titles,
|
toggle_float_above_fullscreen, toggle_show_bar, toggle_show_titles,
|
||||||
video::{
|
video::{
|
||||||
|
|
@ -250,7 +250,6 @@ impl Action {
|
||||||
let persistent = state.persistent.clone();
|
let persistent = state.persistent.clone();
|
||||||
b.new(move || persistent.seat.enable_unicode_input())
|
b.new(move || persistent.seat.enable_unicode_input())
|
||||||
}
|
}
|
||||||
SimpleCommand::OpenControlCenter => b.new(open_control_center),
|
|
||||||
SimpleCommand::WarpMouseToFocus => {
|
SimpleCommand::WarpMouseToFocus => {
|
||||||
let persistent = state.persistent.clone();
|
let persistent = state.persistent.clone();
|
||||||
b.new(move || persistent.seat.warp_mouse_to_focus())
|
b.new(move || persistent.seat.warp_mouse_to_focus())
|
||||||
|
|
@ -1662,12 +1661,6 @@ fn load_config(initial_load: bool, auto_reload: bool, persistent: &Rc<Persistent
|
||||||
if let Some(v) = config.fallback_output_mode {
|
if let Some(v) = config.fallback_output_mode {
|
||||||
persistent.seat.set_fallback_output_mode(v);
|
persistent.seat.set_fallback_output_mode(v);
|
||||||
}
|
}
|
||||||
if let Some(f) = &config.egui.proportional_fonts {
|
|
||||||
set_egui_proportional_fonts(f.iter().map(|s| &**s));
|
|
||||||
}
|
|
||||||
if let Some(f) = &config.egui.monospace_fonts {
|
|
||||||
set_egui_monospace_fonts(f.iter().map(|s| &**s));
|
|
||||||
}
|
|
||||||
if let Some(mouse_follows_focus) = config.mouse_follows_focus {
|
if let Some(mouse_follows_focus) = config.mouse_follows_focus {
|
||||||
#[expect(deprecated)]
|
#[expect(deprecated)]
|
||||||
persistent
|
persistent
|
||||||
|
|
|
||||||
|
|
@ -2056,7 +2056,6 @@
|
||||||
"toggle-simple-im-enabled",
|
"toggle-simple-im-enabled",
|
||||||
"reload-simple-im",
|
"reload-simple-im",
|
||||||
"enable-unicode-input",
|
"enable-unicode-input",
|
||||||
"open-control-center",
|
|
||||||
"warp-mouse-to-focus"
|
"warp-mouse-to-focus"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -4713,10 +4713,6 @@ The string should have one of the following values:
|
||||||
|
|
||||||
This has no effect if the simple IM is not currently active.
|
This has no effect if the simple IM is not currently active.
|
||||||
|
|
||||||
- `open-control-center`:
|
|
||||||
|
|
||||||
Opens the control center.
|
|
||||||
|
|
||||||
- `warp-mouse-to-focus`:
|
- `warp-mouse-to-focus`:
|
||||||
|
|
||||||
Warps the cursor to the center of the currently focused window.
|
Warps the cursor to the center of the currently focused window.
|
||||||
|
|
|
||||||
|
|
@ -1229,8 +1229,6 @@ SimpleActionName:
|
||||||
Enables Unicode input in the simple, XCompose based input method.
|
Enables Unicode input in the simple, XCompose based input method.
|
||||||
|
|
||||||
This has no effect if the simple IM is not currently active.
|
This has no effect if the simple IM is not currently active.
|
||||||
- value: open-control-center
|
|
||||||
description: Opens the control center.
|
|
||||||
- value: warp-mouse-to-focus
|
- value: warp-mouse-to-focus
|
||||||
description: |
|
description: |
|
||||||
Warps the cursor to the center of the currently focused window.
|
Warps the cursor to the center of the currently focused window.
|
||||||
|
|
|
||||||
|
|
@ -135,10 +135,6 @@ request get_pid (since = 27) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
request open_control_center (since = 28) {
|
|
||||||
id: id(jay_open_control_center_request),
|
|
||||||
}
|
|
||||||
|
|
||||||
# events
|
# events
|
||||||
|
|
||||||
event client_id {
|
event client_id {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
request destroy {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
event failed {
|
|
||||||
msg: str,
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue