Merge branch 'window_config_cleanup' into config_rework

This commit is contained in:
elkowar 2021-07-21 20:36:26 +02:00
commit 3efcafed84
No known key found for this signature in database
GPG key ID: E321AD71B1D1F27F
11 changed files with 943 additions and 231 deletions

View file

@ -10,9 +10,9 @@ checksum = "e8fd72866655d1904d6b0997d0b07ba561047d070fbe29de039031c641b61217"
[[package]]
name = "aho-corasick"
version = "0.7.15"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr",
]
@ -42,10 +42,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "595d3cfa7a60d4555cb5067b99f07142a08ea778de5cf993f7b75c7d8fabc486"
[[package]]
name = "arrayvec"
version = "0.5.2"
name = "ascii-canvas"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6"
dependencies = [
"term",
]
[[package]]
name = "async-stream"
@ -123,6 +126,12 @@ version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "474a626a67200bd107d44179bb3d4fc61891172d11696609264589be6a0e6a43"
[[package]]
name = "beef"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6736e2428df2ca2848d846c43e88745121a6654696e349ce0054a420815a7409"
[[package]]
name = "bincode"
version = "1.3.3"
@ -132,24 +141,27 @@ dependencies = [
"serde",
]
[[package]]
name = "bit-set"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de"
dependencies = [
"bit-vec",
]
[[package]]
name = "bit-vec"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
[[package]]
name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "bitvec"
version = "0.19.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321"
dependencies = [
"funty",
"radium",
"tap",
"wyz",
]
[[package]]
name = "bytes"
version = "1.0.1"
@ -215,6 +227,29 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e769b5c8c8283982a987c6e948e540254f1058d5a74b8794914d4ef5fc2a24"
[[package]]
name = "codespan-reporting"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
dependencies = [
"termcolor",
"unicode-width",
]
[[package]]
name = "console"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3993e6445baa160675931ec041a5e03ca84b9c6e32a056150d3aa2bdda0a1f45"
dependencies = [
"encode_unicode",
"lazy_static",
"libc",
"terminal_size",
"winapi",
]
[[package]]
name = "convert_case"
version = "0.4.0"
@ -271,6 +306,12 @@ dependencies = [
"lazy_static",
]
[[package]]
name = "crunchy"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]]
name = "ctor"
version = "0.1.20"
@ -310,12 +351,39 @@ version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499"
[[package]]
name = "dirs-next"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
dependencies = [
"cfg-if",
"dirs-sys-next",
]
[[package]]
name = "dirs-sys-next"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
dependencies = [
"libc",
"redox_users",
"winapi",
]
[[package]]
name = "doc-comment"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
[[package]]
name = "dtoa"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0"
[[package]]
name = "dyn-clone"
version = "1.0.4"
@ -328,6 +396,21 @@ version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "ena"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3"
dependencies = [
"log",
]
[[package]]
name = "encode_unicode"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
[[package]]
name = "env_logger"
version = "0.7.1"
@ -371,16 +454,15 @@ dependencies = [
"log",
"maplit",
"nix",
"nom",
"notify",
"num",
"pretty_assertions",
"pretty_env_logger",
"regex",
"roxmltree",
"serde",
"serde_json",
"simple-signal",
"simplexpr",
"smart-default",
"structopt",
"sysinfo",
@ -390,6 +472,7 @@ dependencies = [
"unescape",
"wait-timeout",
"x11rb",
"yuck",
]
[[package]]
@ -416,6 +499,18 @@ dependencies = [
"winapi",
]
[[package]]
name = "fixedbitset"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "fsevent-sys"
version = "4.0.0"
@ -425,12 +520,6 @@ dependencies = [
"libc",
]
[[package]]
name = "funty"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7"
[[package]]
name = "futures"
version = "0.3.15"
@ -647,7 +736,18 @@ checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
dependencies = [
"cfg-if",
"libc",
"wasi",
"wasi 0.9.0+wasi-snapshot-preview1",
]
[[package]]
name = "getrandom"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
dependencies = [
"cfg-if",
"libc",
"wasi 0.10.2+wasi-snapshot-preview1",
]
[[package]]
@ -746,7 +846,7 @@ version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "352df9cd46a5538323ba016fdbff8baee4a55011a7349120b0d7280992276fa7"
dependencies = [
"beef",
"beef 0.4.4",
"clap",
"codemap",
"indexmap",
@ -907,6 +1007,22 @@ dependencies = [
"libc",
]
[[package]]
name = "insta"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4a1b21a2971cea49ca4613c0e9fe8225ecaf5de64090fddc6002284726e9244"
dependencies = [
"console",
"lazy_static",
"ron",
"serde",
"serde_json",
"serde_yaml",
"similar",
"uuid",
]
[[package]]
name = "instant"
version = "0.1.10"
@ -940,6 +1056,38 @@ version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
[[package]]
name = "lalrpop"
version = "0.19.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15174f1c529af5bf1283c3bc0058266b483a67156f79589fab2a25e23cf8988"
dependencies = [
"ascii-canvas",
"atty",
"bit-set",
"diff",
"ena",
"itertools 0.10.1",
"lalrpop-util",
"petgraph",
"pico-args",
"regex",
"regex-syntax",
"string_cache",
"term",
"tiny-keccak",
"unicode-xid 0.2.2",
]
[[package]]
name = "lalrpop-util"
version = "0.19.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3e58cce361efcc90ba8a0a5f982c741ff86b603495bb15a998412e957dcd278"
dependencies = [
"regex",
]
[[package]]
name = "lasso"
version = "0.3.1"
@ -955,25 +1103,18 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "lexical-core"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe"
dependencies = [
"arrayvec",
"bitflags",
"cfg-if",
"ryu",
"static_assertions",
]
[[package]]
name = "libc"
version = "0.2.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790"
[[package]]
name = "linked-hash-map"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
[[package]]
name = "lock_api"
version = "0.4.4"
@ -992,6 +1133,30 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "logos"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "427e2abca5be13136da9afdbf874e6b34ad9001dd70f2b103b083a85daa7b345"
dependencies = [
"logos-derive",
]
[[package]]
name = "logos-derive"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56a7d287fd2ac3f75b11f19a1c8a874a7d55744bd91f7a1b3e7cf87d4343c36d"
dependencies = [
"beef 0.5.0",
"fnv",
"proc-macro2",
"quote 1.0.9",
"regex-syntax",
"syn 1.0.73",
"utf8-ranges",
]
[[package]]
name = "maplit"
version = "1.0.2"
@ -1000,9 +1165,9 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
[[package]]
name = "memchr"
version = "2.3.4"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
[[package]]
name = "memoffset"
@ -1035,6 +1200,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "new_debug_unreachable"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
[[package]]
name = "nix"
version = "0.20.0"
@ -1047,19 +1218,6 @@ dependencies = [
"libc",
]
[[package]]
name = "nom"
version = "6.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c5c51b9083a3c620fa67a2a635d1ce7d95b897e957d6b28ff9a5da960a103a6"
dependencies = [
"bitvec",
"funty",
"lexical-core",
"memchr",
"version_check",
]
[[package]]
name = "notify"
version = "5.0.0-pre.10"
@ -1280,6 +1438,16 @@ dependencies = [
"ucd-trie",
]
[[package]]
name = "petgraph"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7"
dependencies = [
"fixedbitset",
"indexmap",
]
[[package]]
name = "phf"
version = "0.8.0"
@ -1324,6 +1492,12 @@ dependencies = [
"siphasher",
]
[[package]]
name = "pico-args"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db8bcd96cb740d03149cbad5518db9fd87126a10ab519c011893b1754134c468"
[[package]]
name = "pin-project-lite"
version = "0.2.7"
@ -1348,6 +1522,12 @@ version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
[[package]]
name = "precomputed-hash"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
[[package]]
name = "pretty_assertions"
version = "0.7.2"
@ -1445,19 +1625,13 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "radium"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8"
[[package]]
name = "rand"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
dependencies = [
"getrandom",
"getrandom 0.1.16",
"libc",
"rand_chacha",
"rand_core",
@ -1481,7 +1655,7 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
dependencies = [
"getrandom",
"getrandom 0.1.16",
]
[[package]]
@ -1537,10 +1711,20 @@ dependencies = [
]
[[package]]
name = "regex"
version = "1.4.6"
name = "redox_users"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a26af418b574bd56588335b3a3659a65725d4e636eb1016c2f9e3b38c7cc759"
checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
dependencies = [
"getrandom 0.2.3",
"redox_syscall",
]
[[package]]
name = "regex"
version = "1.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
dependencies = [
"aho-corasick",
"memchr",
@ -1554,12 +1738,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "roxmltree"
version = "0.14.1"
name = "ron"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "921904a62e410e37e215c40381b7117f830d9d89ba60ab5236170541dd25646b"
checksum = "064ea8613fb712a19faf920022ec8ddf134984f100090764a4e1d768f3827f1f"
dependencies = [
"xmlparser",
"base64",
"bitflags",
"serde",
]
[[package]]
@ -1571,6 +1757,12 @@ dependencies = [
"semver",
]
[[package]]
name = "rustversion"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088"
[[package]]
name = "ryu"
version = "1.0.5"
@ -1641,6 +1833,18 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_yaml"
version = "0.8.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15654ed4ab61726bf918a39cb8d98a2e2995b002387807fa6ba58fdf7f59bb23"
dependencies = [
"dtoa",
"linked-hash-map",
"serde",
"yaml-rust",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.0"
@ -1650,6 +1854,12 @@ dependencies = [
"libc",
]
[[package]]
name = "similar"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad1d488a557b235fc46dae55512ffbfc429d2482b08b4d9435ab07384ca8aec"
[[package]]
name = "simple-signal"
version = "1.1.1"
@ -1660,6 +1870,23 @@ dependencies = [
"libc",
]
[[package]]
name = "simplexpr"
version = "0.1.0"
dependencies = [
"insta",
"itertools 0.10.1",
"lalrpop",
"lalrpop-util",
"logos",
"maplit",
"regex",
"serde",
"serde_json",
"strum 0.21.0",
"thiserror",
]
[[package]]
name = "siphasher"
version = "0.3.5"
@ -1695,6 +1922,18 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "string_cache"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ddb1139b5353f96e429e1a5e19fbaf663bddedaa06d1dbd49f82e352601209a"
dependencies = [
"lazy_static",
"new_debug_unreachable",
"phf_shared",
"precomputed-hash",
]
[[package]]
name = "strsim"
version = "0.8.0"
@ -1731,6 +1970,15 @@ version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57bd81eb48f4c437cadc685403cad539345bf703d78e63707418431cecd4522b"
[[package]]
name = "strum"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aaf86bbcfd1fa9670b7a129f64fc0c9fcbbfe4f1bc4210e9e98fe71ffc12cde2"
dependencies = [
"strum_macros 0.21.1",
]
[[package]]
name = "strum_macros"
version = "0.18.0"
@ -1743,6 +1991,18 @@ dependencies = [
"syn 1.0.73",
]
[[package]]
name = "strum_macros"
version = "0.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d06aaeeee809dbc59eb4556183dd927df67db1540de5be8d3ec0b6636358a5ec"
dependencies = [
"heck",
"proc-macro2",
"quote 1.0.9",
"syn 1.0.73",
]
[[package]]
name = "syn"
version = "0.11.11"
@ -1798,18 +2058,23 @@ checksum = "0f3ecc17269a19353b3558b313bba738b25d82993e30d62a18406a24aba4649b"
dependencies = [
"heck",
"pkg-config",
"strum",
"strum_macros",
"strum 0.18.0",
"strum_macros 0.18.0",
"thiserror",
"toml",
"version-compare",
]
[[package]]
name = "tap"
version = "1.0.1"
name = "term"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f"
dependencies = [
"dirs-next",
"rustversion",
"winapi",
]
[[package]]
name = "termcolor"
@ -1820,6 +2085,16 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "terminal_size"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "textwrap"
version = "0.11.0"
@ -1849,6 +2124,15 @@ dependencies = [
"syn 1.0.73",
]
[[package]]
name = "tiny-keccak"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
dependencies = [
"crunchy",
]
[[package]]
name = "tokio"
version = "1.8.2"
@ -1950,6 +2234,18 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "utf8-ranges"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4ae116fef2b7fea257ed6440d3cfcff7f190865f170cdad00bb6465bf18ecba"
[[package]]
name = "uuid"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
[[package]]
name = "vec_map"
version = "0.8.2"
@ -1994,6 +2290,12 @@ version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "winapi"
version = "0.3.9"
@ -2034,12 +2336,6 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "wyz"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214"
[[package]]
name = "x11"
version = "2.18.2"
@ -2063,7 +2359,34 @@ dependencies = [
]
[[package]]
name = "xmlparser"
version = "0.13.3"
name = "yaml-rust"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "114ba2b24d2167ef6d67d7d04c8cc86522b87f490025f39f0303b7db5bf5e3d8"
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
dependencies = [
"linked-hash-map",
]
[[package]]
name = "yuck"
version = "0.1.0"
dependencies = [
"anyhow",
"codespan-reporting",
"derive_more",
"insta",
"itertools 0.10.1",
"lalrpop",
"lalrpop-util",
"lazy_static",
"maplit",
"pretty_assertions",
"regex",
"serde",
"serde_json",
"simplexpr",
"smart-default",
"static_assertions",
"strum 0.21.0",
"thiserror",
]

View file

@ -231,7 +231,7 @@ impl App {
log::info!("Opening window {}", window_name);
let mut window_def = self.eww_config.get_window(window_name)?.clone();
window_def.geometry = window_def.geometry.override_if_given(anchor, pos, size);
window_def.geometry = window_def.geometry.map(|x| x.override_if_given(anchor, pos, size));
let root_widget =
window_def.widget.render(&mut self.eww_state, window_name, &self.eww_config.get_widget_definitions())?;
@ -245,8 +245,7 @@ impl App {
// initialize script var handlers for variables that where not used before opening this window.
// TODO somehow make this less shit
for newly_used_var in
self.variables_only_used_in(window_name).filter_map(|var| self.eww_config.get_script_var(var).ok())
for newly_used_var in self.variables_only_used_in(window_name).filter_map(|var| self.eww_config.get_script_var(var).ok())
{
self.script_var_handler.add(newly_used_var.clone());
}
@ -306,55 +305,53 @@ fn initialize_window(
root_widget: gtk::Widget,
window_def: config::EwwWindowDefinition,
) -> Result<EwwWindow> {
let actual_window_rect = window_def.geometry.get_window_rectangle(monitor_geometry);
if let Some(window) = display_backend::initialize_window(&window_def, monitor_geometry) {
window.set_title(&format!("Eww - {}", window_def.name));
let wm_class_name = format!("eww-{}", window_def.name);
window.set_wmclass(&wm_class_name, &wm_class_name);
window.set_position(gtk::WindowPosition::Center);
let window = display_backend::initialize_window(&window_def, monitor_geometry)
.with_context(|| format!("monitor {} is unavailable", window_def.screen_number.unwrap()))?;
window.set_title(&format!("Eww - {}", window_def.name));
window.set_position(gtk::WindowPosition::None);
window.set_gravity(gdk::Gravity::Center);
if let Some(geometry) = window_def.geometry {
let actual_window_rect = geometry.get_window_rectangle(monitor_geometry);
window.set_size_request(actual_window_rect.width, actual_window_rect.height);
window.set_default_size(actual_window_rect.width, actual_window_rect.height);
window.set_decorated(false);
// run on_screen_changed to set the visual correctly initially.
on_screen_changed(&window, None);
window.connect_screen_changed(on_screen_changed);
window.add(&root_widget);
window.show_all();
apply_window_position(window_def.clone(), monitor_geometry, &window)?;
let gdk_window = window.get_window().context("couldn't get gdk window from gtk window")?;
gdk_window.set_override_redirect(!window_def.focusable);
#[cfg(feature = "x11")]
display_backend::set_xprops(&window, monitor_geometry, &window_def)?;
// this should only be required on x11, as waylands layershell should manage the margins properly anways.
#[cfg(feature = "x11")]
window.connect_configure_event({
let window_def = window_def.clone();
move |window, _evt| {
let _ = apply_window_position(window_def.clone(), monitor_geometry, &window);
false
}
});
Ok(EwwWindow { name: window_def.name.clone(), definition: window_def, gtk_window: window })
} else {
Err(anyhow!("monitor {} is unavailable", window_def.screen_number.unwrap()))
}
window.set_decorated(false);
window.set_skip_taskbar_hint(true);
window.set_skip_pager_hint(true);
// run on_screen_changed to set the visual correctly initially.
on_screen_changed(&window, None);
window.connect_screen_changed(on_screen_changed);
window.add(&root_widget);
window.show_all();
#[cfg(feature = "x11")]
{
if let Some(geometry) = window_def.geometry {
let _ = apply_window_position(geometry, monitor_geometry, &window);
window.connect_configure_event(move |window, _| {
let _ = apply_window_position(geometry, monitor_geometry, &window);
false
});
}
display_backend::set_xprops(&window, monitor_geometry, &window_def)?;
}
Ok(EwwWindow { name: window_def.name.clone(), definition: window_def, gtk_window: window })
}
/// Apply the provided window-positioning rules to the window.
fn apply_window_position(
mut window_def: config::EwwWindowDefinition,
mut window_geometry: config::EwwWindowGeometry,
monitor_geometry: gdk::Rectangle,
window: &gtk::Window,
) -> Result<()> {
let (gtk_window_width, gtk_window_height) = window.get_size();
window_def.geometry.size = Coords { x: NumWithUnit::Pixels(gtk_window_width), y: NumWithUnit::Pixels(gtk_window_height) };
let gdk_window = window.get_window().context("Failed to get gdk window from gtk window")?;
let actual_window_rect = window_def.geometry.get_window_rectangle(monitor_geometry);
window_geometry.size = Coords::from_pixels(window.get_size());
let actual_window_rect = window_geometry.get_window_rectangle(monitor_geometry);
gdk_window.move_(actual_window_rect.x, actual_window_rect.y);
Ok(())
}
@ -367,11 +364,13 @@ fn on_screen_changed(window: &gtk::Window, _old_screen: Option<&gdk::Screen>) {
}
fn get_default_monitor_index() -> i32 {
#[allow(deprecated)]
gdk::Display::get_default().expect("could not get default display").get_default_screen().get_primary_monitor()
}
/// Get the monitor geometry of a given monitor number
fn get_monitor_geometry(n: i32) -> gdk::Rectangle {
#[allow(deprecated)]
gdk::Display::get_default().expect("could not get default display").get_default_screen().get_monitor_geometry(n)
}

View file

@ -0,0 +1,69 @@
use crate::config::xml_ext::XmlElement;
use anyhow::*;
pub use backend::*;
#[cfg(feature = "x11")]
mod backend {
use super::*;
use crate::config::{EwwWindowType, StrutDefinition};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BackendWindowOptions {
pub wm_ignore: bool,
pub sticky: bool,
pub window_type: EwwWindowType,
pub struts: StrutDefinition,
}
impl BackendWindowOptions {
pub fn from_xml_element(xml: &XmlElement) -> Result<Self> {
let struts: Option<StrutDefinition> = xml
.child("reserve")
.ok()
.map(StrutDefinition::from_xml_element)
.transpose()
.context("Failed to parse <reserve>")?;
let window_type = xml.parse_optional_attr("windowtype")?;
Ok(BackendWindowOptions {
wm_ignore: xml.parse_optional_attr("wm-ignore")?.unwrap_or(window_type.is_none() && struts.is_none()),
window_type: window_type.unwrap_or_default(),
sticky: xml.parse_optional_attr("sticky")?.unwrap_or(true),
struts: struts.unwrap_or_default(),
})
}
}
}
#[cfg(feature = "wayland")]
mod backend {
use super::*;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BackendWindowOptions {
pub exclusive: bool,
pub focusable: bool,
}
impl BackendWindowOptions {
pub fn from_xml_element(xml: &XmlElement) -> Result<Self> {
Ok(BackendWindowOptions {
exclusive: xml.parse_optional_attr("exclusive")?.unwrap_or(false),
focusable: xml.parse_optional_attr("focusable")?.unwrap_or(false),
})
}
}
}
#[cfg(feature = "no-x11-wayland")]
mod backend {
use super::*;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BackendWindowOptions;
impl BackendWindowOptions {
pub fn from_xml_element(xml: &XmlElement) -> Result<Self> {
Ok(BackendWindowOptions)
}
}
}

View file

@ -8,6 +8,7 @@ use anyhow::*;
use element::*;
use xml_ext::*;
pub mod backend_window_options;
pub mod element;
pub mod eww_config;
pub mod inbuilt;

View file

@ -9,12 +9,12 @@ use super::xml_ext::XmlElement;
#[derive(Debug, derive_more::Display, Clone, Copy, Eq, PartialEq, SmartDefault, Serialize, Deserialize)]
pub enum AnchorAlignment {
#[display("start")]
#[display(fmt = "start")]
#[default]
START,
#[display("center")]
#[display(fmt = "center")]
CENTER,
#[display("end")]
#[display(fmt = "end")]
END,
}
@ -117,7 +117,7 @@ impl EwwWindowGeometry {
})
}
pub fn override_if_given(&mut self, anchor_point: Option<AnchorPoint>, offset: Option<Coords>, size: Option<Coords>) -> Self {
pub fn override_if_given(&self, anchor_point: Option<AnchorPoint>, offset: Option<Coords>, size: Option<Coords>) -> Self {
EwwWindowGeometry {
anchor_point: anchor_point.unwrap_or(self.anchor_point),
offset: offset.unwrap_or(self.offset),

View file

@ -7,32 +7,13 @@ mod platform {
use gtk::{self, prelude::*};
pub fn initialize_window(window_def: &EwwWindowDefinition, _monitor: gdk::Rectangle) -> Option<gtk::Window> {
let window = if window_def.focusable {
gtk::Window::new(gtk::WindowType::Toplevel)
} else {
gtk::Window::new(gtk::WindowType::Popup)
};
window.set_resizable(true);
if !window_def.focusable {
window.set_type_hint(gdk::WindowTypeHint::Dock);
}
if window_def.stacking == WindowStacking::Foreground {
window.set_keep_above(true);
} else {
window.set_keep_below(true);
}
Some(window)
}
pub fn reserve_space_for(_window: &gtk::Window, _monitor: gdk::Rectangle, _strut_def: StrutDefinition) -> Result<()> {
Err(anyhow!("Cannot reserve space on non X11 or and wayland backends"))
Some(gtk::Window::new(gtk::WindowType::Toplevel))
}
}
#[cfg(feature = "wayland")]
mod platform {
use crate::config::{AnchorAlignment, EwwWindowDefinition, Side, WindowStacking};
use anyhow::*;
use crate::config::{AnchorAlignment, EwwWindowDefinition, WindowStacking};
use gdk;
use gtk::prelude::*;
@ -46,12 +27,12 @@ mod platform {
if let Some(monitor) = gdk::Display::get_default().expect("could not get default display").get_monitor(index) {
gtk_layer_shell::set_monitor(&window, &monitor);
} else {
return None
return None;
}
}
None => {},
None => {}
};
window.set_resizable(true);
window.set_resizable(window_def.resizable);
// Sets the layer where the layer shell surface will spawn
match window_def.stacking {
@ -62,44 +43,46 @@ mod platform {
}
// Sets the keyboard interactivity
gtk_layer_shell::set_keyboard_interactivity(&window, window_def.focusable);
// Positioning surface
let mut top = false;
let mut left = false;
let mut right = false;
let mut bottom = false;
gtk_layer_shell::set_keyboard_interactivity(&window, window_def.backend_options.focusable);
match window_def.geometry.anchor_point.x {
AnchorAlignment::START => left = true,
AnchorAlignment::CENTER => {}
AnchorAlignment::END => right = true,
if let Some(geometry) = window_def.geometry {
// Positioning surface
let mut top = false;
let mut left = false;
let mut right = false;
let mut bottom = false;
match geometry.anchor_point.x {
AnchorAlignment::START => left = true,
AnchorAlignment::CENTER => {}
AnchorAlignment::END => right = true,
}
match geometry.anchor_point.y {
AnchorAlignment::START => top = true,
AnchorAlignment::CENTER => {}
AnchorAlignment::END => bottom = true,
}
gtk_layer_shell::set_anchor(&window, gtk_layer_shell::Edge::Left, left);
gtk_layer_shell::set_anchor(&window, gtk_layer_shell::Edge::Right, right);
gtk_layer_shell::set_anchor(&window, gtk_layer_shell::Edge::Top, top);
gtk_layer_shell::set_anchor(&window, gtk_layer_shell::Edge::Bottom, bottom);
let xoffset = geometry.offset.x.relative_to(monitor.width);
let yoffset = geometry.offset.y.relative_to(monitor.height);
if left {
gtk_layer_shell::set_margin(&window, gtk_layer_shell::Edge::Left, xoffset);
} else {
gtk_layer_shell::set_margin(&window, gtk_layer_shell::Edge::Right, xoffset);
}
if bottom {
gtk_layer_shell::set_margin(&window, gtk_layer_shell::Edge::Bottom, yoffset);
} else {
gtk_layer_shell::set_margin(&window, gtk_layer_shell::Edge::Top, yoffset);
}
}
match window_def.geometry.anchor_point.y {
AnchorAlignment::START => top = true,
AnchorAlignment::CENTER => {}
AnchorAlignment::END => bottom = true,
}
gtk_layer_shell::set_anchor(&window, gtk_layer_shell::Edge::Left, left);
gtk_layer_shell::set_anchor(&window, gtk_layer_shell::Edge::Right, right);
gtk_layer_shell::set_anchor(&window, gtk_layer_shell::Edge::Top, top);
gtk_layer_shell::set_anchor(&window, gtk_layer_shell::Edge::Bottom, bottom);
let xoffset = window_def.geometry.offset.x.relative_to(monitor.width);
let yoffset = window_def.geometry.offset.y.relative_to(monitor.height);
if left {
gtk_layer_shell::set_margin(&window, gtk_layer_shell::Edge::Left, xoffset);
} else {
gtk_layer_shell::set_margin(&window, gtk_layer_shell::Edge::Right, xoffset);
}
if bottom {
gtk_layer_shell::set_margin(&window, gtk_layer_shell::Edge::Bottom, yoffset);
} else {
gtk_layer_shell::set_margin(&window, gtk_layer_shell::Edge::Top, yoffset);
}
if window_def.exclusive {
if window_def.backend_options.exclusive {
gtk_layer_shell::auto_exclusive_zone_enable(&window);
}
Some(window)
@ -122,19 +105,18 @@ mod platform {
};
pub fn initialize_window(window_def: &EwwWindowDefinition, _monitor: gdk::Rectangle) -> Option<gtk::Window> {
let window = if window_def.focusable {
gtk::Window::new(gtk::WindowType::Toplevel)
let window_type = if window_def.backend_options.wm_ignore { gtk::WindowType::Popup } else { gtk::WindowType::Toplevel };
let window = gtk::Window::new(window_type);
let wm_class_name = format!("eww-{}", window_def.name);
#[allow(deprecated)]
window.set_wmclass(&wm_class_name, &wm_class_name);
window.set_resizable(window_def.resizable);
window.set_keep_above(window_def.stacking == WindowStacking::Foreground);
window.set_keep_below(window_def.stacking == WindowStacking::Background);
if window_def.backend_options.sticky {
window.stick();
} else {
gtk::Window::new(gtk::WindowType::Popup)
};
window.set_resizable(true);
if !window_def.focusable {
window.set_type_hint(gdk::WindowTypeHint::Dock);
}
if window_def.stacking == WindowStacking::Foreground {
window.set_keep_above(true);
} else {
window.set_keep_below(true);
window.unstick();
}
Some(window)
}
@ -172,7 +154,7 @@ mod platform {
.ok()
.context("Failed to get x11 window for gtk window")?
.get_xid() as u32;
let strut_def = window_def.struts;
let strut_def = window_def.backend_options.struts;
let root_window_geometry = self.conn.get_geometry(self.root_window)?.reply()?;
let mon_end_x = (monitor_rect.x + monitor_rect.width) as u32 - 1u32;
@ -225,11 +207,12 @@ mod platform {
win_id,
self.atoms._NET_WM_WINDOW_TYPE,
self.atoms.ATOM,
&[match window_def.window_type {
&[match window_def.backend_options.window_type {
EwwWindowType::Dock => self.atoms._NET_WM_WINDOW_TYPE_DOCK,
EwwWindowType::Normal => self.atoms._NET_WM_WINDOW_TYPE_NORMAL,
EwwWindowType::Dialog => self.atoms._NET_WM_WINDOW_TYPE_DIALOG,
EwwWindowType::Toolbar => self.atoms._NET_WM_WINDOW_TYPE_TOOLBAR,
EwwWindowType::Utility => self.atoms._NET_WM_WINDOW_TYPE_UTILITY,
}],
)?
.check()?;
@ -245,6 +228,7 @@ mod platform {
_NET_WM_WINDOW_TYPE_DOCK,
_NET_WM_WINDOW_TYPE_DIALOG,
_NET_WM_WINDOW_TYPE_TOOLBAR,
_NET_WM_WINDOW_TYPE_UTILITY,
_NET_WM_STATE,
_NET_WM_STATE_STICKY,
_NET_WM_STATE_ABOVE,

View file

@ -3,23 +3,6 @@ use extend::ext;
use itertools::Itertools;
use std::path::Path;
#[macro_export]
macro_rules! impl_try_from {
($typ:ty {
$(
for $for:ty => |$arg:ident| $code:expr
);*;
}) => {
$(impl TryFrom<$typ> for $for {
type Error = anyhow::Error;
fn try_from($arg: $typ) -> Result<Self> {
$code
}
})*
};
}
#[macro_export]
macro_rules! try_logging_errors {
($context:expr => $code:block) => {{
@ -62,8 +45,8 @@ macro_rules! loop_select {
#[macro_export]
macro_rules! enum_parse {
($name:literal, $input:expr, $($($s:literal)|* => $val:expr),* $(,)?) => {
let input = $input;
match input {
let input = $input.to_lowercase();
match input.as_str() {
$( $( $s )|* => Ok($val) ),*,
_ => Err(anyhow!(concat!("Couldn't parse ", $name, ": '{}'. Possible values are ", $($($s),*),*), input))
}

View file

@ -76,7 +76,7 @@ impl fmt::Debug for Coords {
}
impl Coords {
pub fn from_pixels(x: i32, y: i32) -> Self {
pub fn from_pixels((x, y): (i32, i32)) -> Self {
Coords { x: NumWithUnit::Pixels(x), y: NumWithUnit::Pixels(y) }
}

View file

@ -206,7 +206,7 @@ The `<windows>` config should look something like this:
```xml
<windows>
<window name="main_window" stacking="fg" focusable="false" screen="1">
<window name="main_window" stacking="fg" screen="1" windowtype="dock">
<geometry anchor="top left" x="300px" y="50%" width="25%" height="20px"/>
<reserve side="left" distance="50px"/>
<widget>
@ -220,7 +220,7 @@ For Wayland users the `<reserve/>` block is replaced by the exclusive field in `
The previous `<window>` block would look like this.
```xml
<window name="main_window" stacking="fg" focusable="false" screen="1" exclusive="true" windowtype="normal">
<window name="main_window" stacking="fg" focusable="false" screen="1" exclusive="true">
<geometry anchor="top left" x="300px" y="50%" width="25%" height="20px"/>
<widget>
<main/>
@ -237,9 +237,6 @@ There are a couple things you can optionally configure on the window itself:
- `stacking`: stacking describes on what "layer" of the screen the window is shown.
Possible values on the X11 backend: `foreground "fg"`, `background "bg"`. Default: `"fg"`
Possible values on the Wayland backend: `foreground "fg"`, `bottom "bt"`, `background "bg"`, `overlay "ov"`. Default: `"fg"`
- `focusable`: whether the window should be focusable by the windowmanager.
This is necessary for things like text-input-fields to work properly.
Possible values: `"true"`, `"false"`. Default: `"false"`
- `screen`: Specifies on which display to show the window in a multi-monitor setup.
This can be any number, representing the index of your monitor.
- `exclusive`: Specifies whether or not a surface can be occupied by another.
@ -247,10 +244,34 @@ There are a couple things you can optionally configure on the window itself:
The details on how it is actually implemented are left to the compositor.
This option is only valid on Wayland.
Possible values: `"true"`, `"false"`. Default: `"false"`
- `focusable`: (Wayland only) whether the window should be able to capture keyboard input.
Possible values: `"true"`, `"false"`. Default: `"false"`
- `wm-ignore`: (X11 only) wether the window should be managed by the window manager.
For a centered widget setup this is recommended to be set to true. For a bar, set the windowtype to `dock` instead.
Note that setting `wm-ignore` will make some other options not work, as those rely on the window manager.
Possible values: `"true"`, `"false"`. Default: `"true"` except if `<reserve>` is set.
- `windowtype`: (X11 only) Can be used in determining the decoration, stacking position and other behavior of the window.
Window managers tend to interpret these differently, so play around with which one works for your usecase!
Possible values:
- `"normal"`: indicates that this is a normal, top-level window
- `"dock"`: indicates a dock or panel feature
- `"dock"`: indicates a bar, dock, or panel window
- `"utility"`: indicates a pinned utility window
- `"toolbar"`: toolbars "torn off" from the main application
- `"dialog"`: indicates that this is a dialog window
- Default: `"dock"` if reserve is set, else `"normal"`
- Default: `"dock"`
- `sticky`: (X11 only) If the window should show up on all workspaces. Note that this may not have any effect, depending on your window manager and the window type.
Possible values: `"true"`, `"false"`. Default: `"true"`
- `resizable`: (X11 only) If the window should be resizable. Note that this may not have any effect, depending on your window manager and the window type.
Possible values: `"true"`, `"false"`. Default: `"true"`
### Recommendations for different use-cases on X
Window positioning is... weird on X11. Different window-managers handle things differently, and some things are just not compatible.
Thus, the following setups are recommendations that will _probably_ work. If they don't try to play around with different settings for any of the X11 only properties.
- For a bar:
- Set `windowtype` to `dock`, and provide a `reserve` configuration to match your window geometry to make the WM reserve space.
- Set `wm-ignore` to `false`.
- For a centered, full-screen widget setup:
- Set `wm-ignore` to `true`.

View file

@ -0,0 +1,167 @@
use super::{backend_window_options::*, *};
use crate::{ensure_xml_tag_is, enum_parse, value::NumWithUnit, widgets::widget_node};
use derive_more::*;
use serde::{Deserialize, Serialize};
use smart_default::SmartDefault;
use std::{collections::HashMap, str::FromStr};
/// Full window-definition containing the fully expanded widget tree.
/// **Use this** rather than [RawEwwWindowDefinition].
#[derive(Debug, Clone)]
pub struct EwwWindowDefinition {
pub name: WindowName,
pub geometry: Option<EwwWindowGeometry>,
pub stacking: WindowStacking,
pub screen_number: Option<i32>,
pub widget: Box<dyn widget_node::WidgetNode>,
pub resizable: bool,
pub backend_options: BackendWindowOptions,
}
impl EwwWindowDefinition {
pub fn generate(defs: &HashMap<String, WidgetDefinition>, window: RawEwwWindowDefinition) -> Result<Self> {
Ok(EwwWindowDefinition {
name: window.name,
geometry: window.geometry,
stacking: window.stacking,
screen_number: window.screen_number,
resizable: window.resizable,
widget: widget_node::generate_generic_widget_node(defs, &HashMap::new(), window.widget)?,
backend_options: window.backend_options,
})
}
}
/// Window-definition storing the raw WidgetUse, as received directly from parsing.
#[derive(Debug, Clone, PartialEq)]
pub struct RawEwwWindowDefinition {
pub name: WindowName,
pub geometry: Option<EwwWindowGeometry>,
pub stacking: WindowStacking,
pub widget: WidgetUse,
pub resizable: bool,
pub backend_options: BackendWindowOptions,
pub screen_number: Option<i32>,
}
impl RawEwwWindowDefinition {
pub fn from_xml_element(xml: &XmlElement) -> Result<Self> {
ensure_xml_tag_is!(xml, "window");
let geometry = match xml.child("geometry") {
Ok(node) => Some(EwwWindowGeometry::from_xml_element(node)?),
Err(_) => None,
};
Ok(RawEwwWindowDefinition {
name: WindowName(xml.attr("name")?),
geometry,
widget: WidgetUse::from_xml_node(xml.child("widget")?.only_child()?)?,
stacking: xml.parse_optional_attr("stacking")?.unwrap_or_default(),
// TODO maybe rename this to monitor?
screen_number: xml.parse_optional_attr("screen")?,
resizable: xml.parse_optional_attr("resizable")?.unwrap_or(true),
backend_options: BackendWindowOptions::from_xml_element(xml)?,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, SmartDefault)]
pub enum EwwWindowType {
#[default]
Dock,
Dialog,
Toolbar,
Normal,
Utility,
}
impl FromStr for EwwWindowType {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
enum_parse! { "window type", s,
"dock" => Self::Dock,
"toolbar" => Self::Toolbar,
"dialog" => Self::Dialog,
"normal" => Self::Normal,
"utility" => Self::Utility,
}
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, smart_default::SmartDefault)]
pub enum Side {
#[default]
Top,
Left,
Right,
Bottom,
}
impl std::str::FromStr for Side {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Side> {
enum_parse! { "side", s,
"l" | "left" => Side::Left,
"r" | "right" => Side::Right,
"t" | "top" => Side::Top,
"b" | "bottom" => Side::Bottom,
}
}
}
// Surface definition if the backend for X11 is enable
#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
pub struct StrutDefinition {
pub side: Side,
pub dist: NumWithUnit,
}
impl StrutDefinition {
pub fn from_xml_element(xml: XmlElement) -> Result<Self> {
Ok(StrutDefinition { side: xml.attr("side")?.parse()?, dist: xml.attr("distance")?.parse()? })
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, derive_more::Display, SmartDefault)]
pub enum WindowStacking {
#[default]
Foreground,
Background,
Bottom,
Overlay,
}
impl std::str::FromStr for WindowStacking {
type Err = anyhow::Error;
#[cfg(not(feature = "wayland"))]
fn from_str(s: &str) -> Result<Self> {
enum_parse! { "WindowStacking", s,
"foreground" | "fg" | "f" => WindowStacking::Foreground,
"background" | "bg" | "b" => WindowStacking::Background,
}
}
#[cfg(feature = "wayland")]
fn from_str(s: &str) -> Result<Self> {
enum_parse! { "WindowStacking", s,
"foreground" | "fg" => WindowStacking::Foreground,
"background" | "bg" => WindowStacking::Background,
"bottom" | "bt" => WindowStacking::Bottom,
"overlay" | "ov" => WindowStacking::Overlay,
}
}
}
#[repr(transparent)]
#[derive(Clone, Hash, PartialEq, Eq, AsRef, FromStr, Display, Serialize, Deserialize, Default, From, DebugCustom)]
#[debug(fmt = "WindowName(\".0\")")]
pub struct WindowName(String);
impl std::borrow::Borrow<str> for WindowName {
fn borrow(&self) -> &str {
&self.0
}
}

165
src/value/primitive.rs Normal file
View file

@ -0,0 +1,165 @@
use anyhow::*;
use itertools::Itertools;
use serde::{Deserialize, Serialize};
use std::{convert::TryFrom, fmt, iter::FromIterator};
#[derive(Clone, Deserialize, Serialize, derive_more::From, Default)]
pub struct PrimVal(pub String);
impl fmt::Display for PrimVal {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl fmt::Debug for PrimVal {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "\"{}\"", self.0)
}
}
/// Manually implement equality, to allow for values in different formats (i.e. "1" and "1.0") to still be considered as equal.
impl std::cmp::PartialEq<Self> for PrimVal {
fn eq(&self, other: &Self) -> bool {
if let (Ok(a), Ok(b)) = (self.as_f64(), other.as_f64()) {
a == b
} else {
self.0 == other.0
}
}
}
impl FromIterator<PrimVal> for PrimVal {
fn from_iter<T: IntoIterator<Item = PrimVal>>(iter: T) -> Self {
PrimVal(iter.into_iter().join(""))
}
}
impl std::str::FromStr for PrimVal {
type Err = anyhow::Error;
/// parses the value, trying to turn it into a number and a boolean first,
/// before deciding that it is a string.
fn from_str(s: &str) -> Result<Self> {
Ok(PrimVal::from_string(s.to_string()))
}
}
macro_rules! impl_try_from {
(impl From<$typ:ty> {
$(for $for:ty => |$arg:ident| $code:expr);*;
}) => {
$(impl TryFrom<$typ> for $for {
type Error = anyhow::Error;
fn try_from($arg: $typ) -> Result<Self> { $code }
})*
};
}
macro_rules! impl_primval_from {
($($t:ty),*) => {
$(impl From<$t> for PrimVal {
fn from(x: $t) -> Self { PrimVal(x.to_string()) }
})*
};
}
impl_try_from!(impl From<PrimVal> {
for String => |x| x.as_string();
for f64 => |x| x.as_f64();
for bool => |x| x.as_bool();
for Vec<String> => |x| x.as_vec();
});
impl_primval_from!(bool, i32, u32, f32, u8, f64, &str);
impl From<&serde_json::Value> for PrimVal {
fn from(v: &serde_json::Value) -> Self {
PrimVal(
v.as_str()
.map(|x| x.to_string())
.or_else(|| serde_json::to_string(v).ok())
.unwrap_or_else(|| "<invalid json value>".to_string()),
)
}
}
impl PrimVal {
pub fn from_string(s: String) -> Self {
PrimVal(s)
}
pub fn into_inner(self) -> String {
self.0
}
/// This will never fail
pub fn as_string(&self) -> Result<String> {
Ok(self.0.to_owned())
}
pub fn as_f64(&self) -> Result<f64> {
self.0.parse().map_err(|e| anyhow!("couldn't convert {:?} to f64: {}", &self, e))
}
pub fn as_i32(&self) -> Result<i32> {
self.0.parse().map_err(|e| anyhow!("couldn't convert {:?} to i32: {}", &self, e))
}
pub fn as_bool(&self) -> Result<bool> {
self.0.parse().map_err(|e| anyhow!("couldn't convert {:?} to bool: {}", &self, e))
}
pub fn as_vec(&self) -> Result<Vec<String>> {
parse_vec(self.0.to_owned()).map_err(|e| anyhow!("Couldn't convert {:#?} to a vec: {}", &self, e))
}
pub fn as_json_value(&self) -> Result<serde_json::Value> {
serde_json::from_str::<serde_json::Value>(&self.0)
.with_context(|| format!("Couldn't convert {:#?} to a json object", &self))
}
}
fn parse_vec(a: String) -> Result<Vec<String>> {
match a.strip_prefix('[').and_then(|x| x.strip_suffix(']')) {
Some(content) => {
let mut items: Vec<String> = content.split(',').map(|x: &str| x.to_string()).collect();
let mut removed = 0;
for times_ran in 0..items.len() {
// escapes `,` if there's a `\` before em
if items[times_ran - removed].ends_with('\\') {
items[times_ran - removed].pop();
let it = items.remove((times_ran + 1) - removed);
items[times_ran - removed] += ",";
items[times_ran - removed] += &it;
removed += 1;
}
}
Ok(items)
}
None => Err(anyhow!("Is your array built like this: '[these,are,items]'?")),
}
}
#[cfg(test)]
mod test {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn test_parse_vec() {
assert_eq!(vec![""], parse_vec("[]".to_string()).unwrap(), "should be able to parse empty lists");
assert_eq!(vec!["hi"], parse_vec("[hi]".to_string()).unwrap(), "should be able to parse single element list");
assert_eq!(
vec!["hi", "ho", "hu"],
parse_vec("[hi,ho,hu]".to_string()).unwrap(),
"should be able to parse three element list"
);
assert_eq!(vec!["hi,ho"], parse_vec("[hi\\,ho]".to_string()).unwrap(), "should be able to parse list with escaped comma");
assert_eq!(
vec!["hi,ho", "hu"],
parse_vec("[hi\\,ho,hu]".to_string()).unwrap(),
"should be able to parse two element list with escaped comma"
);
assert!(parse_vec("".to_string()).is_err(), "Should fail when parsing empty string");
assert!(parse_vec("[a,b".to_string()).is_err(), "Should fail when parsing unclosed list");
assert!(parse_vec("a]".to_string()).is_err(), "Should fail when parsing unopened list");
}
}