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.
Possible values:
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");
}
}