More stuff
This commit is contained in:
Generated
+697
-64
@@ -9,14 +9,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "330223a1aecc308757b9926e9391c9b47f8ef2dbd8aea9df88312aea18c5e8d6"
|
checksum = "330223a1aecc308757b9926e9391c9b47f8ef2dbd8aea9df88312aea18c5e8d6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ahash"
|
name = "aho-corasick"
|
||||||
version = "0.7.6"
|
version = "0.7.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
|
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"memchr",
|
||||||
"once_cell",
|
|
||||||
"version_check",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -28,6 +26,89 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-broadcast"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b19760fa2b7301cf235360ffd6d3558b1ed4249edd16d6cca8d690cee265b95"
|
||||||
|
dependencies = [
|
||||||
|
"event-listener",
|
||||||
|
"futures-core",
|
||||||
|
"parking_lot",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-executor"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "17adb73da160dfb475c183343c8cccd80721ea5a605d3eb57125f0a7b7a92d0b"
|
||||||
|
dependencies = [
|
||||||
|
"async-lock",
|
||||||
|
"async-task",
|
||||||
|
"concurrent-queue",
|
||||||
|
"fastrand",
|
||||||
|
"futures-lite",
|
||||||
|
"slab",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-io"
|
||||||
|
version = "1.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8c374dda1ed3e7d8f0d9ba58715f924862c63eae6849c92d3a18e7fbde9e2794"
|
||||||
|
dependencies = [
|
||||||
|
"async-lock",
|
||||||
|
"autocfg",
|
||||||
|
"concurrent-queue",
|
||||||
|
"futures-lite",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"parking",
|
||||||
|
"polling",
|
||||||
|
"slab",
|
||||||
|
"socket2",
|
||||||
|
"waker-fn",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-lock"
|
||||||
|
version = "2.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c8101efe8695a6c17e02911402145357e718ac92d3ff88ae8419e84b1707b685"
|
||||||
|
dependencies = [
|
||||||
|
"event-listener",
|
||||||
|
"futures-lite",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-recursion"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3b015a331cc64ebd1774ba119538573603427eaace0a1950c423ab971f903796"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-task"
|
||||||
|
version = "4.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-trait"
|
||||||
|
version = "0.1.63"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eff18d764974428cf3a9328e23fc5c986f5fbed46e6cd4cdf42544df5d297ec1"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@@ -55,6 +136,18 @@ version = "3.11.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba"
|
checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytes"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "calloop"
|
name = "calloop"
|
||||||
version = "0.10.5"
|
version = "0.10.5"
|
||||||
@@ -105,6 +198,21 @@ dependencies = [
|
|||||||
"unicode-width",
|
"unicode-width",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "concurrent-queue"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c278839b831783b70278b14df4d45e1beb1aad306c07bb796637de9a0e323e8e"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "const-cstr"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ed3d0b5ff30645a68f35ece8cea4556ca14ef8a1651455f789a099a0513532a6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation-sys"
|
name = "core-foundation-sys"
|
||||||
version = "0.8.3"
|
version = "0.8.3"
|
||||||
@@ -120,6 +228,15 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-utils"
|
||||||
|
version = "0.8.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crypto-common"
|
name = "crypto-common"
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
@@ -175,14 +292,14 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dbus"
|
name = "derivative"
|
||||||
version = "0.9.6"
|
version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6f8bcdd56d2e5c4ed26a529c5a9029f5db8290d433497506f958eae3be148eb6"
|
checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"proc-macro2",
|
||||||
"libdbus-sys",
|
"quote",
|
||||||
"winapi",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -195,6 +312,26 @@ dependencies = [
|
|||||||
"crypto-common",
|
"crypto-common",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dirs"
|
||||||
|
version = "4.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
|
||||||
|
dependencies = [
|
||||||
|
"dirs-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dirs-sys"
|
||||||
|
version = "0.3.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"redox_users",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dlib"
|
name = "dlib"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
@@ -204,12 +341,6 @@ dependencies = [
|
|||||||
"libloading",
|
"libloading",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "dlv-list"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "downcast-rs"
|
name = "downcast-rs"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
@@ -223,10 +354,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0"
|
checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "enumflags2"
|
||||||
version = "1.8.0"
|
version = "0.7.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
|
checksum = "e75d4cd21b95383444831539909fbb14b9dc3fdceb2a6f5d36577329a1f55ccb"
|
||||||
|
dependencies = [
|
||||||
|
"enumflags2_derive",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "enumflags2_derive"
|
||||||
|
version = "0.7.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f58dc3c5e468259f19f2d46304a6b28f1c3d034442e14b322d2b850e36f6d5ae"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "event-listener"
|
||||||
|
version = "2.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastrand"
|
name = "fastrand"
|
||||||
@@ -237,6 +389,68 @@ dependencies = [
|
|||||||
"instant",
|
"instant",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fontconfig"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9b0653582d9c82645f95bacd0dc87b49a3126f7a9633be8cafa9c6d17d525847"
|
||||||
|
dependencies = [
|
||||||
|
"yeslogic-fontconfig-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-core"
|
||||||
|
version = "0.3.25"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-io"
|
||||||
|
version = "0.3.25"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-lite"
|
||||||
|
version = "1.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48"
|
||||||
|
dependencies = [
|
||||||
|
"fastrand",
|
||||||
|
"futures-core",
|
||||||
|
"futures-io",
|
||||||
|
"memchr",
|
||||||
|
"parking",
|
||||||
|
"pin-project-lite",
|
||||||
|
"waker-fn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-sink"
|
||||||
|
version = "0.3.25"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-task"
|
||||||
|
version = "0.3.25"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-util"
|
||||||
|
version = "0.3.25"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
"futures-task",
|
||||||
|
"pin-project-lite",
|
||||||
|
"pin-utils",
|
||||||
|
"slab",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fuzzy-matcher"
|
name = "fuzzy-matcher"
|
||||||
version = "0.3.7"
|
version = "0.3.7"
|
||||||
@@ -268,13 +482,10 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hex"
|
||||||
version = "0.12.3"
|
version = "0.4.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
dependencies = [
|
|
||||||
"ahash",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iana-time-zone"
|
name = "iana-time-zone"
|
||||||
@@ -319,15 +530,6 @@ dependencies = [
|
|||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "itertools"
|
|
||||||
version = "0.10.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
|
||||||
dependencies = [
|
|
||||||
"either",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.60"
|
version = "0.3.60"
|
||||||
@@ -349,15 +551,6 @@ version = "0.2.138"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
|
checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libdbus-sys"
|
|
||||||
version = "0.2.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c185b5b7ad900923ef3a8ff594083d4d9b5aea80bb4f32b8342363138c0d456b"
|
|
||||||
dependencies = [
|
|
||||||
"pkg-config",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libloading"
|
name = "libloading"
|
||||||
version = "0.7.4"
|
version = "0.7.4"
|
||||||
@@ -368,6 +561,33 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libpulse-binding"
|
||||||
|
version = "2.27.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1745b20bfc194ac12ef828f144f0ec2d4a7fe993281fa3567a0bd4969aee6890"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"libc",
|
||||||
|
"libpulse-sys",
|
||||||
|
"num-derive",
|
||||||
|
"num-traits",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libpulse-sys"
|
||||||
|
version = "1.20.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2191e6880818d1df4cf72eac8e91dce7a5a52ba0da4b2a5cdafabc22b937eadb"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"num-derive",
|
||||||
|
"num-traits",
|
||||||
|
"pkg-config",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "link-cplusplus"
|
name = "link-cplusplus"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
@@ -377,6 +597,16 @@ dependencies = [
|
|||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lock_api"
|
||||||
|
version = "0.4.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"scopeguard",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.17"
|
version = "0.4.17"
|
||||||
@@ -429,6 +659,18 @@ dependencies = [
|
|||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mio"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nix"
|
name = "nix"
|
||||||
version = "0.25.1"
|
version = "0.25.1"
|
||||||
@@ -440,6 +682,7 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"memoffset 0.6.5",
|
"memoffset 0.6.5",
|
||||||
|
"pin-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -477,6 +720,17 @@ dependencies = [
|
|||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-derive"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-integer"
|
name = "num-integer"
|
||||||
version = "0.1.45"
|
version = "0.1.45"
|
||||||
@@ -515,13 +769,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
|
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ordered-multimap"
|
name = "ordered-stream"
|
||||||
version = "0.4.3"
|
version = "0.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a"
|
checksum = "d4eb9ba3f3e42dbdd3b7b122de5ca169c81e93d561eb900da3a8c99bcfcf381a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dlv-list",
|
"futures-core",
|
||||||
"hashbrown",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -533,6 +787,35 @@ dependencies = [
|
|||||||
"ttf-parser",
|
"ttf-parser",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking_lot"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
|
||||||
|
dependencies = [
|
||||||
|
"lock_api",
|
||||||
|
"parking_lot_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking_lot_core"
|
||||||
|
version = "0.9.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ba1ef8814b5c993410bb3adfad7a5ed269563e4a2f90c41f5d85be7fb47133bf"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"redox_syscall",
|
||||||
|
"smallvec",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pest"
|
name = "pest"
|
||||||
version = "2.5.2"
|
version = "2.5.2"
|
||||||
@@ -577,6 +860,12 @@ dependencies = [
|
|||||||
"sha1",
|
"sha1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-project-lite"
|
||||||
|
version = "0.2.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-utils"
|
name = "pin-utils"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -589,6 +878,37 @@ version = "0.3.26"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
|
checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "polling"
|
||||||
|
version = "2.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "22122d5ec4f9fe1b3916419b76be1e80bcb93f618d071d2edf841b137b2a2bd6"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"wepoll-ffi",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ppv-lite86"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-crate"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
"thiserror",
|
||||||
|
"toml",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.47"
|
version = "1.0.47"
|
||||||
@@ -616,6 +936,36 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"rand_chacha",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rcalc_lib"
|
name = "rcalc_lib"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
@@ -641,6 +991,34 @@ dependencies = [
|
|||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_users"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
"redox_syscall",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.6.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "remove_dir_all"
|
name = "remove_dir_all"
|
||||||
version = "0.5.3"
|
version = "0.5.3"
|
||||||
@@ -650,16 +1028,6 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rust-ini"
|
|
||||||
version = "0.18.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f6d5f2436026b4f6e79dc829837d467cc7e9a55ee40e750d716713540715a2df"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"ordered-multimap",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rusttype"
|
name = "rusttype"
|
||||||
version = "0.9.3"
|
version = "0.9.3"
|
||||||
@@ -685,12 +1053,49 @@ version = "1.0.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
|
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scopeguard"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scratch"
|
name = "scratch"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898"
|
checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.152"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.152"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_repr"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a5ec9fa74a20ebbe5d9ac23dac1fc96ba0ecfe9f50f2843b52e537b10fbcb4e"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha1"
|
name = "sha1"
|
||||||
version = "0.10.5"
|
version = "0.10.5"
|
||||||
@@ -708,6 +1113,15 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
|
checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "slab"
|
||||||
|
version = "0.4.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slotmap"
|
name = "slotmap"
|
||||||
version = "1.0.6"
|
version = "1.0.6"
|
||||||
@@ -723,6 +1137,16 @@ version = "1.10.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
|
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "socket2"
|
||||||
|
version = "0.4.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "static_assertions"
|
name = "static_assertions"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@@ -803,6 +1227,75 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio"
|
||||||
|
version = "1.24.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "597a12a59981d9e3c38d216785b0c37399f6e415e8d0712047620f189371b0bb"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"bytes",
|
||||||
|
"libc",
|
||||||
|
"memchr",
|
||||||
|
"mio",
|
||||||
|
"pin-project-lite",
|
||||||
|
"socket2",
|
||||||
|
"tracing",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-stream"
|
||||||
|
version = "0.1.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d660770404473ccd7bc9f8b28494a811bc18542b915c0855c51e8f419d5223ce"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"pin-project-lite",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml"
|
||||||
|
version = "0.5.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing"
|
||||||
|
version = "0.1.37"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"pin-project-lite",
|
||||||
|
"tracing-attributes",
|
||||||
|
"tracing-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-attributes"
|
||||||
|
version = "0.1.23"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-core"
|
||||||
|
version = "0.1.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ttf-parser"
|
name = "ttf-parser"
|
||||||
version = "0.15.2"
|
version = "0.15.2"
|
||||||
@@ -821,6 +1314,16 @@ version = "0.1.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81"
|
checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uds_windows"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ce65604324d3cce9b966701489fbd0cf318cb1f7bd9dd07ac9a4ee6fb791930d"
|
||||||
|
dependencies = [
|
||||||
|
"tempfile",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.5"
|
version = "1.0.5"
|
||||||
@@ -839,6 +1342,17 @@ version = "0.1.10"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
|
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "upower_dbus"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b0b1d77de98ab2e5187f5fa2b045b8c4eecfc49e5ccd07f16f4c89f008116f8c"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"serde_repr",
|
||||||
|
"zbus",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vec_map"
|
name = "vec_map"
|
||||||
version = "0.8.2"
|
version = "0.8.2"
|
||||||
@@ -851,6 +1365,12 @@ version = "0.9.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "waker-fn"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "walkdir"
|
name = "walkdir"
|
||||||
version = "2.3.2"
|
version = "2.3.2"
|
||||||
@@ -991,6 +1511,15 @@ dependencies = [
|
|||||||
"pkg-config",
|
"pkg-config",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wepoll-ffi"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
@@ -1086,21 +1615,23 @@ dependencies = [
|
|||||||
"bitflags",
|
"bitflags",
|
||||||
"calloop",
|
"calloop",
|
||||||
"chrono",
|
"chrono",
|
||||||
"dbus",
|
"fontconfig",
|
||||||
"fuzzy-matcher",
|
"fuzzy-matcher",
|
||||||
"itertools",
|
"libpulse-binding",
|
||||||
"memmap",
|
"memmap",
|
||||||
"nix 0.26.1",
|
"nix 0.26.1",
|
||||||
"rcalc_lib",
|
"rcalc_lib",
|
||||||
"rust-ini",
|
|
||||||
"rusttype",
|
"rusttype",
|
||||||
"shlex",
|
"shlex",
|
||||||
"tempfile",
|
"tokio",
|
||||||
|
"tokio-stream",
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
|
"upower_dbus",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
"wayland-client",
|
"wayland-client",
|
||||||
"wayland-protocols",
|
"wayland-protocols",
|
||||||
"xkbcommon",
|
"xkbcommon",
|
||||||
|
"zbus",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1112,3 +1643,105 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"memmap2",
|
"memmap2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yeslogic-fontconfig-sys"
|
||||||
|
version = "4.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec657fd32bbcbeaef5c7bc8e10b3db95b143fab8db0a50079773dbf936fd4f73"
|
||||||
|
dependencies = [
|
||||||
|
"const-cstr",
|
||||||
|
"dlib",
|
||||||
|
"once_cell",
|
||||||
|
"pkg-config",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zbus"
|
||||||
|
version = "3.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "379d587c0ccb632d1179cf44082653f682842f0535f0fdfaefffc34849cc855e"
|
||||||
|
dependencies = [
|
||||||
|
"async-broadcast",
|
||||||
|
"async-executor",
|
||||||
|
"async-io",
|
||||||
|
"async-lock",
|
||||||
|
"async-recursion",
|
||||||
|
"async-task",
|
||||||
|
"async-trait",
|
||||||
|
"byteorder",
|
||||||
|
"derivative",
|
||||||
|
"dirs",
|
||||||
|
"enumflags2",
|
||||||
|
"event-listener",
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
"futures-util",
|
||||||
|
"hex",
|
||||||
|
"lazy_static",
|
||||||
|
"nix 0.25.1",
|
||||||
|
"once_cell",
|
||||||
|
"ordered-stream",
|
||||||
|
"rand",
|
||||||
|
"serde",
|
||||||
|
"serde_repr",
|
||||||
|
"sha1",
|
||||||
|
"static_assertions",
|
||||||
|
"tokio",
|
||||||
|
"tracing",
|
||||||
|
"uds_windows",
|
||||||
|
"winapi",
|
||||||
|
"zbus_macros",
|
||||||
|
"zbus_names",
|
||||||
|
"zvariant",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zbus_macros"
|
||||||
|
version = "3.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "66492a2e90c0df7190583eccb8424aa12eb7ff06edea415a4fff6688fae18cf8"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-crate",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"regex",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zbus_names"
|
||||||
|
version = "2.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f34f314916bd89bdb9934154627fab152f4f28acdda03e7c4c68181b214fe7e3"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"static_assertions",
|
||||||
|
"zvariant",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zvariant"
|
||||||
|
version = "3.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "576cc41e65c7f283e5460f5818073e68fb1f1631502b969ef228c2e03c862efb"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"enumflags2",
|
||||||
|
"libc",
|
||||||
|
"serde",
|
||||||
|
"static_assertions",
|
||||||
|
"zvariant_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zvariant_derive"
|
||||||
|
version = "3.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0fd4aafc0dee96ae7242a24249ce9babf21e1562822f03df650d4e68c20e41ed"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-crate",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|||||||
+11
-7
@@ -4,26 +4,25 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
|
#debug = true
|
||||||
lto = "fat"
|
lto = "fat"
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
[features]
|
||||||
|
fontloading = ["fontconfig"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wayland-client = { version = "0.30", features = ["calloop", "log"] }
|
wayland-client = { version = "0.30", features = ["calloop", "log"] }
|
||||||
wayland-protocols = { version = "0.30", features = ["client", "unstable", "staging"] }
|
wayland-protocols = { version = "0.30", features = ["client", "unstable", "staging"] }
|
||||||
tempfile = "3.3"
|
|
||||||
nix = "0.26"
|
nix = "0.26"
|
||||||
memmap = "0.7"
|
memmap = "0.7"
|
||||||
#fontconfig = "0.6.0"
|
fontconfig = { version = "0.6.0", optional = true }
|
||||||
rusttype = "^0.9"
|
rusttype = "0.9"
|
||||||
calloop = { version = "0.10" }
|
calloop = { version = "0.10" }
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
|
|
||||||
walkdir = "2.3"
|
walkdir = "2.3"
|
||||||
itertools = "0.10"
|
|
||||||
rust-ini = "0.18"
|
|
||||||
|
|
||||||
bitflags = "1.3"
|
bitflags = "1.3"
|
||||||
|
|
||||||
unicode-segmentation = "1.10"
|
unicode-segmentation = "1.10"
|
||||||
@@ -31,6 +30,11 @@ fuzzy-matcher = "0.3"
|
|||||||
shlex = "1.1"
|
shlex = "1.1"
|
||||||
|
|
||||||
xkbcommon = { version = "0.5", features = ["wayland"] }
|
xkbcommon = { version = "0.5", features = ["wayland"] }
|
||||||
dbus = "0.9"
|
upower_dbus = "0.3"
|
||||||
|
zbus = { version = "3.7", default-features = false, features = ["tokio"] }
|
||||||
|
tokio = { version = "1.24", default-features = false, features = ["rt"] }
|
||||||
|
tokio-stream = "0.1"
|
||||||
|
|
||||||
rcalc_lib = "1.0"
|
rcalc_lib = "1.0"
|
||||||
|
|
||||||
|
libpulse-binding = "2.26"
|
||||||
|
|||||||
+40
-80
@@ -170,20 +170,27 @@ impl BufferManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct BufferView<'a> {
|
pub struct BufferView<'a> {
|
||||||
buf: &'a mut MmapMut,
|
view: &'a mut [u32],
|
||||||
dimensions: (u32, u32),
|
dimensions: (u32, u32),
|
||||||
subdimensions: Option<(u32, u32, u32, u32)>,
|
subdimensions: Option<(u32, u32, u32, u32)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> BufferView<'a> {
|
impl<'a> BufferView<'a> {
|
||||||
pub fn new(buf: &'a mut MmapMut, dimensions: (u32, u32)) -> BufferView {
|
pub fn new(buf: &'a mut MmapMut, dimensions: (u32, u32)) -> BufferView {
|
||||||
|
let view = unsafe {
|
||||||
|
std::slice::from_raw_parts_mut(
|
||||||
|
buf.as_mut_ptr() as *mut u32,
|
||||||
|
(dimensions.0 * dimensions.1) as usize,
|
||||||
|
)
|
||||||
|
};
|
||||||
BufferView {
|
BufferView {
|
||||||
buf,
|
view,
|
||||||
dimensions,
|
dimensions,
|
||||||
subdimensions: None,
|
subdimensions: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn get_bounds(&self) -> (u32, u32, u32, u32) {
|
pub fn get_bounds(&self) -> (u32, u32, u32, u32) {
|
||||||
if let Some(subdim) = self.subdimensions {
|
if let Some(subdim) = self.subdimensions {
|
||||||
subdim
|
subdim
|
||||||
@@ -195,22 +202,16 @@ impl<'a> BufferView<'a> {
|
|||||||
pub fn subdimensions(
|
pub fn subdimensions(
|
||||||
&mut self,
|
&mut self,
|
||||||
subdimensions: (u32, u32, u32, u32),
|
subdimensions: (u32, u32, u32, u32),
|
||||||
) -> Result<BufferView, ::std::io::Error> {
|
) -> BufferView {
|
||||||
let bounds = self.get_bounds();
|
let bounds = self.get_bounds();
|
||||||
if subdimensions.0 + subdimensions.2 > bounds.2
|
if cfg!(debug_assertions) && (subdimensions.0 + subdimensions.2 > bounds.2
|
||||||
|| subdimensions.1 + subdimensions.3 > bounds.3
|
|| subdimensions.1 + subdimensions.3 > bounds.3)
|
||||||
{
|
{
|
||||||
return Err(::std::io::Error::new(
|
panic!("cannot create subdimensions larger than buffer: {:?} > {:?}", subdimensions, bounds);
|
||||||
::std::io::ErrorKind::Other,
|
|
||||||
format!(
|
|
||||||
"cannot create subdimensions larger than buffer: {:?} > {:?}",
|
|
||||||
subdimensions, bounds
|
|
||||||
),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(BufferView {
|
BufferView {
|
||||||
buf: self.buf,
|
view: self.view,
|
||||||
dimensions: self.dimensions,
|
dimensions: self.dimensions,
|
||||||
subdimensions: Some((
|
subdimensions: Some((
|
||||||
subdimensions.0 + bounds.0,
|
subdimensions.0 + bounds.0,
|
||||||
@@ -218,27 +219,21 @@ impl<'a> BufferView<'a> {
|
|||||||
subdimensions.2,
|
subdimensions.2,
|
||||||
subdimensions.3,
|
subdimensions.3,
|
||||||
)),
|
)),
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn subgeometry(&mut self, geo: Geometry) -> Result<BufferView, ::std::io::Error> {
|
pub fn subgeometry(&mut self, geo: Geometry) -> BufferView {
|
||||||
self.subdimensions((geo.x, geo.y, geo.width, geo.height))
|
self.subdimensions((geo.x, geo.y, geo.width, geo.height))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn offset(&mut self, offset: (u32, u32)) -> Result<BufferView, ::std::io::Error> {
|
pub fn offset(&mut self, offset: (u32, u32)) -> BufferView {
|
||||||
let bounds = self.get_bounds();
|
let bounds = self.get_bounds();
|
||||||
if offset.0 > bounds.2 || offset.1 > bounds.3 {
|
if cfg!(debug_assertions) && (offset.0 > bounds.2 || offset.1 > bounds.3) {
|
||||||
return Err(::std::io::Error::new(
|
panic!("cannot create offset outside buffer: {:?} > {:?}", offset, bounds);
|
||||||
::std::io::ErrorKind::Other,
|
|
||||||
format!(
|
|
||||||
"cannot create offset outside buffer: {:?} > {:?}",
|
|
||||||
offset, bounds
|
|
||||||
),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(BufferView {
|
BufferView {
|
||||||
buf: self.buf,
|
view: self.view,
|
||||||
dimensions: self.dimensions,
|
dimensions: self.dimensions,
|
||||||
subdimensions: Some((
|
subdimensions: Some((
|
||||||
offset.0 + bounds.0,
|
offset.0 + bounds.0,
|
||||||
@@ -246,82 +241,47 @@ impl<'a> BufferView<'a> {
|
|||||||
bounds.2 - offset.0,
|
bounds.2 - offset.0,
|
||||||
bounds.3 - offset.1,
|
bounds.3 - offset.1,
|
||||||
)),
|
)),
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn limit(&mut self, dimensions: (u32, u32)) -> Result<BufferView, ::std::io::Error> {
|
pub fn limit(&mut self, dimensions: (u32, u32)) -> BufferView {
|
||||||
let bounds = self.get_bounds();
|
let bounds = self.get_bounds();
|
||||||
if dimensions.0 > bounds.2 || dimensions.1 > bounds.3 {
|
if cfg!(debug_assertions) && (dimensions.0 > bounds.2 || dimensions.1 > bounds.3) {
|
||||||
return Err(::std::io::Error::new(
|
panic!("cannot create offset outside buffer: {:?} > {:?}", dimensions, bounds);
|
||||||
::std::io::ErrorKind::Other,
|
|
||||||
format!(
|
|
||||||
"cannot create offset outside buffer: {:?} > {:?}",
|
|
||||||
dimensions, bounds
|
|
||||||
),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(BufferView {
|
BufferView {
|
||||||
buf: self.buf,
|
view: self.view,
|
||||||
dimensions: self.dimensions,
|
dimensions: self.dimensions,
|
||||||
subdimensions: Some((bounds.0, bounds.1, dimensions.0, dimensions.1)),
|
subdimensions: Some((bounds.0, bounds.1, dimensions.0, dimensions.1)),
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn memset(&mut self, c: &Color) {
|
pub fn memset(&mut self, c: Color) {
|
||||||
let v = c.as_argb8888();
|
|
||||||
if let Some(subdim) = self.subdimensions {
|
if let Some(subdim) = self.subdimensions {
|
||||||
unsafe {
|
for y in subdim.1..(subdim.1 + subdim.3) {
|
||||||
let ptr = self.buf.as_mut_ptr();
|
for x in subdim.0..(subdim.0 + subdim.2) {
|
||||||
for y in subdim.1..(subdim.1 + subdim.3) {
|
self.view[(x + y * self.dimensions.0) as usize] = c.0;
|
||||||
for x in subdim.0..(subdim.0 + subdim.2) {
|
|
||||||
*((ptr as *mut u32).offset((x + y * self.dimensions.0) as isize)) = v;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unsafe {
|
self.view.fill(c.0);
|
||||||
let ptr = self.buf.as_mut_ptr();
|
|
||||||
for p in 0..(self.dimensions.0 * self.dimensions.1) {
|
|
||||||
*((ptr as *mut u32).offset(p as isize)) = v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn put(&mut self, pos: (u32, u32), c: &Color) -> Result<(), ::std::io::Error> {
|
pub fn put(&mut self, pos: (u32, u32), c: Color) {
|
||||||
let true_pos = if let Some(subdim) = self.subdimensions {
|
let true_pos = if let Some(subdim) = self.subdimensions {
|
||||||
if pos.0 >= subdim.2 || pos.1 >= subdim.3 {
|
if cfg!(debug_assertions) && (pos.0 >= subdim.2 || pos.1 >= subdim.3) {
|
||||||
return Err(::std::io::Error::new(
|
panic!("put({:?}) is not within subdimensions of buffer ({:?})", pos, subdim);
|
||||||
::std::io::ErrorKind::Other,
|
|
||||||
format!(
|
|
||||||
"put({:?}) is not within subdimensions of buffer ({:?})",
|
|
||||||
pos, subdim
|
|
||||||
),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
(pos.0 + subdim.0, pos.1 + subdim.1)
|
(pos.0 + subdim.0, pos.1 + subdim.1)
|
||||||
} else {
|
} else {
|
||||||
if pos.0 >= self.dimensions.0 || pos.1 >= self.dimensions.1 {
|
if cfg!(debug_assertions) && (pos.0 >= self.dimensions.0 || pos.1 >= self.dimensions.1) {
|
||||||
return Err(::std::io::Error::new(
|
panic!("put({:?}) is not within dimensions of buffer ({:?})", pos, self.dimensions);
|
||||||
::std::io::ErrorKind::Other,
|
|
||||||
format!(
|
|
||||||
"put({:?}) is not within dimensions of buffer ({:?})",
|
|
||||||
pos, self.dimensions
|
|
||||||
),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
pos
|
pos
|
||||||
};
|
};
|
||||||
|
|
||||||
unsafe {
|
self.view[(true_pos.0 + (true_pos.1 * self.dimensions.0)) as usize] = c.0;
|
||||||
let ptr = self
|
|
||||||
.buf
|
|
||||||
.as_mut_ptr()
|
|
||||||
.offset(4 * (true_pos.0 + (true_pos.1 * self.dimensions.0)) as isize);
|
|
||||||
*(ptr as *mut u32) = c.as_argb8888();
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+50
-1
@@ -1,5 +1,5 @@
|
|||||||
//use serde::{Deserialize, Serialize};
|
//use serde::{Deserialize, Serialize};
|
||||||
|
/*
|
||||||
//#[derive(Serialize, Deserialize, Debug, Clone, Copy, Default)]
|
//#[derive(Serialize, Deserialize, Debug, Clone, Copy, Default)]
|
||||||
pub struct Color {
|
pub struct Color {
|
||||||
red: f32,
|
red: f32,
|
||||||
@@ -37,6 +37,11 @@ impl Color {
|
|||||||
| ((255.0 * self.green) as u32 & 0xFF) << 8
|
| ((255.0 * self.green) as u32 & 0xFF) << 8
|
||||||
| ((255.0 * self.blue) as u32 & 0xFF)
|
| ((255.0 * self.blue) as u32 & 0xFF)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn as_integer(&self) -> IntegerColor {
|
||||||
|
IntegerColor(self.as_argb8888())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -69,3 +74,47 @@ fn clamp_f32(v: f32, a: f32, b: f32) -> f32 {
|
|||||||
fn blend_f32(a: f32, b: f32, r: f32) -> f32 {
|
fn blend_f32(a: f32, b: f32, r: f32) -> f32 {
|
||||||
a + ((b - a) * r)
|
a + ((b - a) * r)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
#[inline]
|
||||||
|
fn blend_u8(a: u8, b: u8, r: f32) -> u32 {
|
||||||
|
let af = a as f32;
|
||||||
|
let bf = b as f32;
|
||||||
|
(af + ((bf - af) * r)) as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct Color(pub u32);
|
||||||
|
|
||||||
|
impl Color {
|
||||||
|
pub const BLACK: Color = Color(0xFF000000);
|
||||||
|
pub const WHITE: Color = Color(0xFFFFFFFF);
|
||||||
|
pub const GREY50: Color = Color(0xFF7F7F7F);
|
||||||
|
pub const GREY75: Color = Color(0xFFBFBFBF);
|
||||||
|
pub const GREY80: Color = Color(0xFFCCCCCC);
|
||||||
|
pub const RED: Color = Color(0xFFFF0000);
|
||||||
|
pub const YELLOW: Color = Color(0xFFFFFF00);
|
||||||
|
pub const LIGHTGREEN: Color = Color(0xFF7FFF7F);
|
||||||
|
pub const LIGHTRED: Color = Color(0xFFFF7F7F);
|
||||||
|
pub const LIGHTORANGE: Color = Color(0xFFFFBF00);
|
||||||
|
pub const DARKORANGE: Color = Color(0xFFFF7F00);
|
||||||
|
pub const BUFF: Color = Color(0xFFFFBF7F);
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn new(red: u8, green: u8, blue: u8, opacity: u8) -> Color {
|
||||||
|
Color((opacity as u32) << 24 | (red as u32) << 16 | (green as u32) << 8 | (blue as u32))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opacity(self) -> u8 {((self.0 >> 24) & 0xFF) as u8 }
|
||||||
|
fn red(self) -> u8 {((self.0 >> 16) & 0xFF) as u8 }
|
||||||
|
fn green(self) -> u8 {((self.0 >> 8) & 0xFF) as u8 }
|
||||||
|
fn blue(self) -> u8 {(self.0 & 0xFF) as u8 }
|
||||||
|
|
||||||
|
pub fn blend(self, other: Color, ratio: f32) -> Color {
|
||||||
|
Color(
|
||||||
|
blend_u8(self.opacity(), other.opacity(), ratio) << 24 |
|
||||||
|
blend_u8(self.red(), other.red(), ratio) << 16 |
|
||||||
|
blend_u8(self.green(), other.green(), ratio) << 8 |
|
||||||
|
blend_u8(self.blue(), other.blue(), ratio)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+29
-23
@@ -47,7 +47,7 @@ impl CachedGlyph {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(&self, buf: &mut BufferView, pos: (i32, i32), bg: &Color, c: &Color) {
|
fn draw(&self, buf: &mut BufferView, pos: (i32, i32), bg: Color, c: Color) {
|
||||||
let mut x = 0;
|
let mut x = 0;
|
||||||
let mut y = 0;
|
let mut y = 0;
|
||||||
for v in &self.render {
|
for v in &self.render {
|
||||||
@@ -56,7 +56,7 @@ impl CachedGlyph {
|
|||||||
(x + pos.0 + self.origin.0) as u32,
|
(x + pos.0 + self.origin.0) as u32,
|
||||||
(y + pos.1 + self.origin.1) as u32,
|
(y + pos.1 + self.origin.1) as u32,
|
||||||
),
|
),
|
||||||
&bg.blend(&c, *v),
|
bg.blend(c, *v),
|
||||||
);
|
);
|
||||||
|
|
||||||
if x == self.dimensions.0 as i32 - 1 {
|
if x == self.dimensions.0 as i32 - 1 {
|
||||||
@@ -84,6 +84,12 @@ impl<'a> Font<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn height(&self) -> f32 {
|
||||||
|
let scale = Scale::uniform(self.size);
|
||||||
|
let m = self.font.v_metrics(scale);
|
||||||
|
m.ascent - m.descent
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_str_to_cache(&mut self, s: &str) {
|
pub fn add_str_to_cache(&mut self, s: &str) {
|
||||||
for ch in s.chars() {
|
for ch in s.chars() {
|
||||||
if self.glyphs.get(&ch).is_none() {
|
if self.glyphs.get(&ch).is_none() {
|
||||||
@@ -96,8 +102,8 @@ impl<'a> Font<'a> {
|
|||||||
pub fn draw_text(
|
pub fn draw_text(
|
||||||
&self,
|
&self,
|
||||||
buf: &mut BufferView,
|
buf: &mut BufferView,
|
||||||
bg: &Color,
|
bg: Color,
|
||||||
c: &Color,
|
c: Color,
|
||||||
s: &str,
|
s: &str,
|
||||||
) -> Result<(u32, u32), ::std::io::Error> {
|
) -> Result<(u32, u32), ::std::io::Error> {
|
||||||
let mut x_off = 0;
|
let mut x_off = 0;
|
||||||
@@ -129,8 +135,8 @@ impl<'a> Font<'a> {
|
|||||||
pub fn draw_text_with_cursor(
|
pub fn draw_text_with_cursor(
|
||||||
&self,
|
&self,
|
||||||
buf: &mut BufferView,
|
buf: &mut BufferView,
|
||||||
bg: &Color,
|
bg: Color,
|
||||||
c: &Color,
|
c: Color,
|
||||||
s: &str,
|
s: &str,
|
||||||
cursor: usize,
|
cursor: usize,
|
||||||
) -> Result<(u32, u32), ::std::io::Error> {
|
) -> Result<(u32, u32), ::std::io::Error> {
|
||||||
@@ -171,13 +177,13 @@ impl<'a> Font<'a> {
|
|||||||
pub fn draw_cursor(
|
pub fn draw_cursor(
|
||||||
&self,
|
&self,
|
||||||
buf: &mut BufferView,
|
buf: &mut BufferView,
|
||||||
c: &Color,
|
c: Color,
|
||||||
offset: u32,
|
offset: u32,
|
||||||
height: u32,
|
height: u32,
|
||||||
) -> Result<(), ::std::io::Error> {
|
) -> Result<(), ::std::io::Error> {
|
||||||
// draw cursor
|
// draw cursor
|
||||||
for i in 1..height {
|
for i in 1..height {
|
||||||
buf.put((offset, i), c)?
|
buf.put((offset, i), c);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -206,8 +212,8 @@ impl<'a> Font<'a> {
|
|||||||
pub fn auto_draw_text(
|
pub fn auto_draw_text(
|
||||||
&mut self,
|
&mut self,
|
||||||
buf: &mut BufferView,
|
buf: &mut BufferView,
|
||||||
bg: &Color,
|
bg: Color,
|
||||||
c: &Color,
|
c: Color,
|
||||||
s: &str,
|
s: &str,
|
||||||
) -> Result<(u32, u32), ::std::io::Error> {
|
) -> Result<(u32, u32), ::std::io::Error> {
|
||||||
self.add_str_to_cache(s);
|
self.add_str_to_cache(s);
|
||||||
@@ -217,8 +223,8 @@ impl<'a> Font<'a> {
|
|||||||
pub fn auto_draw_text_with_cursor(
|
pub fn auto_draw_text_with_cursor(
|
||||||
&mut self,
|
&mut self,
|
||||||
buf: &mut BufferView,
|
buf: &mut BufferView,
|
||||||
bg: &Color,
|
bg: Color,
|
||||||
c: &Color,
|
c: Color,
|
||||||
s: &str,
|
s: &str,
|
||||||
cursor: usize,
|
cursor: usize,
|
||||||
) -> Result<(u32, u32), ::std::io::Error> {
|
) -> Result<(u32, u32), ::std::io::Error> {
|
||||||
@@ -229,8 +235,8 @@ impl<'a> Font<'a> {
|
|||||||
pub fn draw_text_fixed_width(
|
pub fn draw_text_fixed_width(
|
||||||
&self,
|
&self,
|
||||||
buf: &mut BufferView,
|
buf: &mut BufferView,
|
||||||
bg: &Color,
|
bg: Color,
|
||||||
c: &Color,
|
c: Color,
|
||||||
distances: &[u32],
|
distances: &[u32],
|
||||||
s: &str,
|
s: &str,
|
||||||
) -> Result<(u32, u32), ::std::io::Error> {
|
) -> Result<(u32, u32), ::std::io::Error> {
|
||||||
@@ -263,7 +269,7 @@ impl<'a> Font<'a> {
|
|||||||
pub fn draw_text_individual_colors(
|
pub fn draw_text_individual_colors(
|
||||||
&self,
|
&self,
|
||||||
buf: &mut BufferView,
|
buf: &mut BufferView,
|
||||||
bg: &Color,
|
bg: Color,
|
||||||
color: &[Color],
|
color: &[Color],
|
||||||
s: &str,
|
s: &str,
|
||||||
) -> Result<(u32, u32), ::std::io::Error> {
|
) -> Result<(u32, u32), ::std::io::Error> {
|
||||||
@@ -286,7 +292,7 @@ impl<'a> Font<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (idx, glyph) in glyphs.into_iter().enumerate() {
|
for (idx, glyph) in glyphs.into_iter().enumerate() {
|
||||||
glyph.draw(buf, (x_off, -off), bg, &color[idx]);
|
glyph.draw(buf, (x_off, -off), bg, color[idx]);
|
||||||
x_off += glyph.advance;
|
x_off += glyph.advance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,7 +302,7 @@ impl<'a> Font<'a> {
|
|||||||
pub fn auto_draw_text_individual_colors(
|
pub fn auto_draw_text_individual_colors(
|
||||||
&mut self,
|
&mut self,
|
||||||
buf: &mut BufferView,
|
buf: &mut BufferView,
|
||||||
bg: &Color,
|
bg: Color,
|
||||||
color: &[Color],
|
color: &[Color],
|
||||||
s: &str,
|
s: &str,
|
||||||
) -> Result<(u32, u32), ::std::io::Error> {
|
) -> Result<(u32, u32), ::std::io::Error> {
|
||||||
@@ -305,14 +311,14 @@ impl<'a> Font<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_box(buf: &mut BufferView, c: &Color, dim: (u32, u32)) -> Result<(), ::std::io::Error> {
|
pub fn draw_box(buf: &mut BufferView, c: Color, dim: (u32, u32)) -> Result<(), ::std::io::Error> {
|
||||||
for x in 0..dim.0 {
|
for x in 0..dim.0 {
|
||||||
let _ = buf.put((x, 0), c);
|
buf.put((x, 0), c);
|
||||||
let _ = buf.put((x, dim.1 - 1), c);
|
buf.put((x, dim.1 - 1), c);
|
||||||
}
|
}
|
||||||
for y in 0..dim.1 {
|
for y in 0..dim.1 {
|
||||||
buf.put((0, y), c)?;
|
buf.put((0, y), c);
|
||||||
buf.put((dim.0 - 1, y), c)?;
|
buf.put((dim.0 - 1, y), c);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -320,7 +326,7 @@ pub fn draw_box(buf: &mut BufferView, c: &Color, dim: (u32, u32)) -> Result<(),
|
|||||||
|
|
||||||
pub fn draw_bar(
|
pub fn draw_bar(
|
||||||
buf: &mut BufferView,
|
buf: &mut BufferView,
|
||||||
color: &Color,
|
color: Color,
|
||||||
length: u32,
|
length: u32,
|
||||||
height: u32,
|
height: u32,
|
||||||
fill: f32,
|
fill: f32,
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
use calloop::ping::Ping;
|
||||||
|
|
||||||
|
use crate::keyboard::KeyEvent;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub enum PointerButton {
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
Middle,
|
||||||
|
ScrollVertical(f64),
|
||||||
|
ScrollHorizontal(f64),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PointerEvent {
|
||||||
|
pub button: PointerButton,
|
||||||
|
pub pos: (u32, u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Event {
|
||||||
|
NewMinute,
|
||||||
|
PowerUpdate,
|
||||||
|
LauncherUpdate,
|
||||||
|
AudioUpdate,
|
||||||
|
KeyEvent(KeyEvent),
|
||||||
|
PointerEvent(PointerEvent),
|
||||||
|
TokenUpdate(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Events {
|
||||||
|
dirty: bool,
|
||||||
|
events: Vec<Event>,
|
||||||
|
ping: Ping,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Events {
|
||||||
|
pub fn new(ping: Ping) -> Arc<Mutex<Events>> {
|
||||||
|
Arc::new(Mutex::new(Events {
|
||||||
|
dirty: false,
|
||||||
|
events: Vec::new(),
|
||||||
|
ping,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_event(&mut self, ev: Event) {
|
||||||
|
self.events.push(ev);
|
||||||
|
if !self.dirty {
|
||||||
|
self.dirty = true;
|
||||||
|
self.ping.ping();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn flush(&mut self) -> Vec<Event> {
|
||||||
|
self.dirty = false;
|
||||||
|
self.events.drain(..).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+37
-31
@@ -1,7 +1,6 @@
|
|||||||
//! Utility module for fonts
|
//! Utility module for fonts
|
||||||
|
|
||||||
use crate::draw;
|
use crate::draw;
|
||||||
//use fontconfig::Fontconfig as FontConfig;
|
|
||||||
use rusttype::Font;
|
use rusttype::Font;
|
||||||
use std::{
|
use std::{
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
@@ -10,7 +9,7 @@ use std::{
|
|||||||
hash,
|
hash,
|
||||||
io::Read,
|
io::Read,
|
||||||
mem,
|
mem,
|
||||||
path::{Path, PathBuf},
|
path::Path,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
thread,
|
thread,
|
||||||
};
|
};
|
||||||
@@ -18,19 +17,24 @@ use std::{
|
|||||||
/// FontRef is used to store Fonts on widgets.
|
/// FontRef is used to store Fonts on widgets.
|
||||||
pub type FontRef<'a> = &'a rusttype::Font<'a>;
|
pub type FontRef<'a> = &'a rusttype::Font<'a>;
|
||||||
|
|
||||||
/*
|
#[cfg(feature = "fontloading")]
|
||||||
/// FontSeeker is a marker struct that is used to look up fonts
|
mod fc {
|
||||||
pub(crate) struct FontSeeker;
|
use fontconfig::Fontconfig as FontConfig;
|
||||||
|
|
||||||
impl FontSeeker {
|
|
||||||
/// Acts like fc-match.
|
/// Acts like fc-match.
|
||||||
/// Given a string, it matches it to a font file and returns its path.
|
/// Given a string, it matches it to a font file and returns its path.
|
||||||
pub(crate) fn from_string(name: &str) -> PathBuf {
|
pub(crate) fn from_string(name: &str) -> String {
|
||||||
let fc = FontConfig::new().unwrap();
|
let fc = FontConfig::new().unwrap();
|
||||||
fc.find(name, None).unwrap().path
|
fc.find(name, None).unwrap().path.to_str().unwrap().to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
#[cfg(not(feature = "fontloading"))]
|
||||||
|
mod fc {
|
||||||
|
pub(crate) fn from_string(_name: &str) -> String {
|
||||||
|
panic!("fontloading feature not enabled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// FontLoader is a marker struct that is used to load files
|
/// FontLoader is a marker struct that is used to load files
|
||||||
pub(crate) struct FontLoader;
|
pub(crate) struct FontLoader;
|
||||||
|
|
||||||
@@ -77,51 +81,53 @@ impl Eq for ComparableF32 {}
|
|||||||
|
|
||||||
pub struct FontMap {
|
pub struct FontMap {
|
||||||
fonts: HashMap<(&'static str, ComparableF32), draw::Font<'static>>,
|
fonts: HashMap<(&'static str, ComparableF32), draw::Font<'static>>,
|
||||||
required_fonts: HashMap<&'static str, (&'static str, Vec<f32>)>,
|
font_paths: HashMap<&'static str, String>,
|
||||||
|
required_fonts: HashMap<&'static str, (&'static str, Vec<(f32, &'static str)>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FontMap {
|
impl FontMap {
|
||||||
pub fn new() -> FontMap {
|
pub fn new() -> FontMap {
|
||||||
FontMap {
|
FontMap {
|
||||||
fonts: HashMap::new(),
|
fonts: HashMap::new(),
|
||||||
|
font_paths: HashMap::new(),
|
||||||
required_fonts: HashMap::new(),
|
required_fonts: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn queue_font_name(&mut self, font_name: &'static str, size: f32) {
|
pub fn queue_font(&mut self, font_name: &'static str, size: f32, preload: &'static str) {
|
||||||
match self.required_fonts.get_mut(font_name) {
|
match self.required_fonts.get_mut(font_name) {
|
||||||
Some(v) => v.1.push(size),
|
Some(v) => v.1.push((size, preload)),
|
||||||
None => {
|
None => {
|
||||||
self.required_fonts
|
self.required_fonts.insert(font_name, (font_name, vec![(size, preload)]));
|
||||||
.insert(font_name, (font_name, vec![size]));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn queue_font_path(&mut self, font_name: &'static str, font_path: &'static str, size: f32) {
|
pub fn add_font_path(&mut self, font_name: &'static str, font_path: String) {
|
||||||
match self.required_fonts.get_mut(font_name) {
|
self.font_paths.insert(font_name, font_path);
|
||||||
Some(v) => v.1.push(size),
|
|
||||||
None => {
|
|
||||||
self.required_fonts
|
|
||||||
.insert(font_name, (font_path, vec![size]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_fonts(&mut self) {
|
pub fn load_fonts(&mut self) {
|
||||||
for (font_name, v) in self.required_fonts.iter() {
|
for (font_name, v) in self.required_fonts.iter() {
|
||||||
let path = if v.0.starts_with("/") {
|
let path = match self.font_paths.get(font_name) {
|
||||||
std::path::PathBuf::from(v.0)
|
Some(res) => res,
|
||||||
} else {
|
_ => {
|
||||||
//FontSeeker::from_string(v.0)
|
let s = fc::from_string(font_name);
|
||||||
panic!("required FontSeeker");
|
self.font_paths.insert(font_name, s);
|
||||||
|
self.font_paths.get(font_name).unwrap()
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let fontref = Box::leak(Box::new(
|
let fontref = Box::leak(Box::new(
|
||||||
FontLoader::from_path(path).expect("unable to load font"),
|
FontLoader::from_path(path).expect("unable to load font"),
|
||||||
));
|
));
|
||||||
for size in &v.1 {
|
for (size, preload) in &v.1 {
|
||||||
let font = draw::Font::new(fontref, *size);
|
if let Some(font) = self.fonts.get_mut(&(font_name, ComparableF32(*size))) {
|
||||||
self.fonts.insert((font_name, ComparableF32(*size)), font);
|
font.add_str_to_cache(preload);
|
||||||
|
} else {
|
||||||
|
let mut font = draw::Font::new(fontref, *size);
|
||||||
|
font.add_str_to_cache(preload);
|
||||||
|
self.fonts.insert((font_name, ComparableF32(*size)), font);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-2
@@ -12,8 +12,10 @@
|
|||||||
//! calloop event loop. Not doing so will prevent key repetition to work
|
//! calloop event loop. Not doing so will prevent key repetition to work
|
||||||
//! (but the rest of the functionnality will not be affected).
|
//! (but the rest of the functionnality will not be affected).
|
||||||
|
|
||||||
use std::default::Default;
|
use std::{
|
||||||
use std::os::unix::io::{AsRawFd, OwnedFd};
|
default::Default,
|
||||||
|
os::unix::io::{AsRawFd, OwnedFd},
|
||||||
|
};
|
||||||
|
|
||||||
use wayland_client::{protocol::wl_keyboard, WEnum};
|
use wayland_client::{protocol::wl_keyboard, WEnum};
|
||||||
use xkbcommon::xkb;
|
use xkbcommon::xkb;
|
||||||
@@ -24,6 +26,7 @@ mod state;
|
|||||||
use self::state::KbState;
|
use self::state::KbState;
|
||||||
pub use self::state::ModifiersState;
|
pub use self::state::ModifiersState;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct KeyEvent {
|
pub struct KeyEvent {
|
||||||
pub serial: u32,
|
pub serial: u32,
|
||||||
pub time: u32,
|
pub time: u32,
|
||||||
|
|||||||
@@ -50,6 +50,9 @@ impl ModifiersState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Safety: No.
|
||||||
|
unsafe impl Send for KbState {}
|
||||||
|
|
||||||
impl KbState {
|
impl KbState {
|
||||||
pub(crate) fn update_modifiers(
|
pub(crate) fn update_modifiers(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|||||||
+86
-63
@@ -6,6 +6,7 @@ mod keyboard;
|
|||||||
mod state;
|
mod state;
|
||||||
mod utils;
|
mod utils;
|
||||||
mod widgets;
|
mod widgets;
|
||||||
|
mod event;
|
||||||
|
|
||||||
use wayland_client::{Connection, QueueHandle, WaylandSource};
|
use wayland_client::{Connection, QueueHandle, WaylandSource};
|
||||||
|
|
||||||
@@ -18,44 +19,17 @@ use chrono::{Duration, Local, Timelike};
|
|||||||
use buffer::BufferView;
|
use buffer::BufferView;
|
||||||
use color::Color;
|
use color::Color;
|
||||||
use fonts::{FontMap, MaybeFontMap};
|
use fonts::{FontMap, MaybeFontMap};
|
||||||
use state::{Event, Events, State};
|
use state::State;
|
||||||
|
use event::{Event, Events};
|
||||||
use widgets::{
|
use widgets::{
|
||||||
Backlight, Battery, Calendar, Clock, Date, Geometry, HorizontalLayout, IndexedLayout,
|
Audio, Backlight, Battery, Calendar, Clock, Date, Geometry, HorizontalLayout, IndexedLayout,
|
||||||
Interface, InvertedHorizontalLayout, Line, Margin, VerticalLayout, Widget,
|
Interface, InvertedHorizontalLayout, Line, Margin, VerticalLayout, Widget,
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::{rc::Rc, thread};
|
use std::{rc::Rc, thread};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let font_thread = thread::spawn(move || {
|
// let now = Local::now();
|
||||||
let mut fm = FontMap::new();
|
|
||||||
// Hard-coding font paths make things a lot faster
|
|
||||||
fm.queue_font_path("sans", "/usr/share/fonts/noto/NotoSans-Regular.ttf", 128.);
|
|
||||||
fm.queue_font_path("sans", "/usr/share/fonts/noto/NotoSans-Regular.ttf", 48.);
|
|
||||||
fm.queue_font_path("sans", "/usr/share/fonts/noto/NotoSans-Regular.ttf", 24.);
|
|
||||||
fm.queue_font_path(
|
|
||||||
"monospace",
|
|
||||||
"/usr/share/fonts/noto/NotoSansMono-Regular.ttf",
|
|
||||||
32.,
|
|
||||||
);
|
|
||||||
fm.queue_font_path(
|
|
||||||
"monospace",
|
|
||||||
"/usr/share/fonts/noto/NotoSansMono-Regular.ttf",
|
|
||||||
12.,
|
|
||||||
);
|
|
||||||
fm.queue_font_path(
|
|
||||||
"monospace",
|
|
||||||
"/usr/share/fonts/noto/NotoSansMono-Regular.ttf",
|
|
||||||
12. * 1.5,
|
|
||||||
);
|
|
||||||
fm.queue_font_path(
|
|
||||||
"monospace",
|
|
||||||
"/usr/share/fonts/noto/NotoSansMono-Regular.ttf",
|
|
||||||
12. * 2.0,
|
|
||||||
);
|
|
||||||
fm.load_fonts();
|
|
||||||
fm
|
|
||||||
});
|
|
||||||
let conn = Connection::connect_to_env().unwrap();
|
let conn = Connection::connect_to_env().unwrap();
|
||||||
|
|
||||||
let event_queue = conn.new_event_queue();
|
let event_queue = conn.new_event_queue();
|
||||||
@@ -66,32 +40,6 @@ fn main() {
|
|||||||
|
|
||||||
let (ping_sender, ping_source) = calloop::ping::make_ping().unwrap();
|
let (ping_sender, ping_source) = calloop::ping::make_ping().unwrap();
|
||||||
|
|
||||||
let events = Events::new(ping_sender);
|
|
||||||
|
|
||||||
let clock = Box::new(Clock::new("sans", 128.));
|
|
||||||
// let calendar = Box::new(Calendar::new("monospace", 12.0, 1, -1));
|
|
||||||
let date = Box::new(Date::new("sans", 48.));
|
|
||||||
let line = Box::new(Line::new());
|
|
||||||
let launcher = Box::new(Interface::new("monospace", 32.));
|
|
||||||
let battery = Box::new(Battery::new(events.clone(), "sans", 24.));
|
|
||||||
let backlight = Box::new(Backlight::new("intel_backlight", "sans", 24.));
|
|
||||||
|
|
||||||
let widgets: Vec<Box<dyn Widget>> =
|
|
||||||
vec![clock, date, battery, backlight, line, launcher];
|
|
||||||
let layout = Rc::new(VerticalLayout::new(vec![
|
|
||||||
HorizontalLayout::new(vec![
|
|
||||||
IndexedLayout::new(0),
|
|
||||||
Margin::new(IndexedLayout::new(1), (16, 8, 0, 0)),
|
|
||||||
VerticalLayout::new(vec![
|
|
||||||
Margin::new(IndexedLayout::new(2), (16, 8, 8, 0)),
|
|
||||||
Margin::new(IndexedLayout::new(3), (16, 8, 8, 0)),
|
|
||||||
]),
|
|
||||||
]),
|
|
||||||
IndexedLayout::new(4),
|
|
||||||
IndexedLayout::new(5),
|
|
||||||
// InvertedHorizontalLayout::new(vec![IndexedLayout::new(5), IndexedLayout::new(6)]),
|
|
||||||
]));
|
|
||||||
|
|
||||||
let mut event_loop: EventLoop<State> =
|
let mut event_loop: EventLoop<State> =
|
||||||
EventLoop::try_new().expect("Failed to initialize the event loop!");
|
EventLoop::try_new().expect("Failed to initialize the event loop!");
|
||||||
|
|
||||||
@@ -136,6 +84,79 @@ fn main() {
|
|||||||
})
|
})
|
||||||
.expect("Failed to insert event source!");
|
.expect("Failed to insert event source!");
|
||||||
|
|
||||||
|
let events = Events::new(ping_sender);
|
||||||
|
|
||||||
|
let mut fm = FontMap::new();
|
||||||
|
|
||||||
|
// Todo: Cache in a file
|
||||||
|
fm.add_font_path("sans", "/usr/share/fonts/noto/NotoSans-Regular.ttf".to_string());
|
||||||
|
fm.add_font_path("monospace", "/usr/share/fonts/noto/NotoSansMono-Regular.ttf".to_string());
|
||||||
|
|
||||||
|
let clock = Box::new(Clock::new(&mut fm, "sans", 128.));
|
||||||
|
let calendar = Box::new(Calendar::new(&mut fm, "monospace", 12.0, 1, -1));
|
||||||
|
let date = Box::new(Date::new(&mut fm, "sans", 48.));
|
||||||
|
let line = Box::new(Line::new(1));
|
||||||
|
let launcher = Box::new(Interface::new(events.clone(), &mut fm, "monospace", 32.));
|
||||||
|
let battery = Box::new(Battery::new(events.clone(), &mut fm, "sans", 24.));
|
||||||
|
let backlight = Box::new(Backlight::new("intel_backlight", &mut fm, "sans", 24.));
|
||||||
|
let audio = Box::new(Audio::new(events.clone(), &mut fm, "sans", 24.));
|
||||||
|
|
||||||
|
let widgets: Vec<Box<dyn Widget>> =
|
||||||
|
vec![clock, date, battery, backlight, audio, line, calendar, launcher];
|
||||||
|
|
||||||
|
let layout = Rc::new(VerticalLayout::new(vec![
|
||||||
|
HorizontalLayout::new(vec![
|
||||||
|
IndexedLayout::new(0),
|
||||||
|
Margin::new(IndexedLayout::new(1), (16, 16, 0, 0)),
|
||||||
|
VerticalLayout::new(vec![
|
||||||
|
Margin::new(IndexedLayout::new(2), (16, 8, 8, 0)),
|
||||||
|
Margin::new(IndexedLayout::new(3), (16, 8, 8, 0)),
|
||||||
|
Margin::new(IndexedLayout::new(4), (16, 8, 8, 0)),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
IndexedLayout::new(5),
|
||||||
|
InvertedHorizontalLayout::new(vec![IndexedLayout::new(6), IndexedLayout::new(7)]),
|
||||||
|
]));
|
||||||
|
|
||||||
|
/* alt look
|
||||||
|
let clock = Box::new(Clock::new(&mut fm, "sans", 256.));
|
||||||
|
let date = Box::new(Date::new(&mut fm, "sans", 64.));
|
||||||
|
let calendar = Box::new(Calendar::new(&mut fm, "monospace", 16.0, 3, 1));
|
||||||
|
let launcher = Box::new(Interface::new(events.clone(), &mut fm, "monospace", 32.));
|
||||||
|
let battery = Box::new(Battery::new(events.clone(), &mut fm, "sans", 24.));
|
||||||
|
let backlight = Box::new(Backlight::new("intel_backlight", &mut fm, "sans", 24.));
|
||||||
|
|
||||||
|
let widgets: Vec<Box<dyn Widget>> =
|
||||||
|
vec![clock, date, battery, backlight, calendar];
|
||||||
|
|
||||||
|
let layout = Rc::new(Margin::new(
|
||||||
|
VerticalLayout::new(vec![
|
||||||
|
HorizontalLayout::new(vec![
|
||||||
|
VerticalLayout::new(vec![
|
||||||
|
IndexedLayout::new(1),
|
||||||
|
IndexedLayout::new(0),
|
||||||
|
]),
|
||||||
|
Margin::new(
|
||||||
|
VerticalLayout::new(vec![
|
||||||
|
Margin::new(IndexedLayout::new(2), (0, 0, 0, 8)),
|
||||||
|
Margin::new(IndexedLayout::new(3), (0, 0, 0, 8)),
|
||||||
|
]),
|
||||||
|
(88, 0, 0, 0),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
IndexedLayout::new(4),
|
||||||
|
//IndexedLayout::new(5),
|
||||||
|
]), (20, 20, 20, 20))
|
||||||
|
);
|
||||||
|
*/
|
||||||
|
|
||||||
|
let font_thread = thread::Builder::new()
|
||||||
|
.name("fontloader".to_string())
|
||||||
|
.spawn(move || {
|
||||||
|
fm.load_fonts();
|
||||||
|
fm
|
||||||
|
}).unwrap();
|
||||||
|
|
||||||
let mut state = State::new(widgets, layout, MaybeFontMap::Waiting(font_thread), events);
|
let mut state = State::new(widgets, layout, MaybeFontMap::Waiting(font_thread), events);
|
||||||
|
|
||||||
let mut damage = Vec::new();
|
let mut damage = Vec::new();
|
||||||
@@ -174,16 +195,16 @@ fn main() {
|
|||||||
(state.dimensions.0 as u32, state.dimensions.1 as u32),
|
(state.dimensions.0 as u32, state.dimensions.1 as u32),
|
||||||
);
|
);
|
||||||
|
|
||||||
let bg = Color::new(0., 0., 0., 1.);
|
// eprintln!("time: {}", (Local::now() - now).num_milliseconds());
|
||||||
|
|
||||||
let surface = state.base_surface.as_ref().unwrap().clone();
|
let surface = state.base_surface.as_ref().unwrap().clone();
|
||||||
if force {
|
if force {
|
||||||
|
// Other compositors probably need this.
|
||||||
|
//bufview.memset(Color::BLACK);
|
||||||
for (idx, widget) in state.widgets.iter_mut().enumerate() {
|
for (idx, widget) in state.widgets.iter_mut().enumerate() {
|
||||||
if force || widget.get_dirty() {
|
if force || widget.get_dirty() {
|
||||||
let geo = widget.geometry();
|
let geo = widget.geometry();
|
||||||
bufview.subgeometry(geo).unwrap().memset(&bg);
|
let mut subview = bufview.subgeometry(geo);
|
||||||
|
|
||||||
let mut subview = bufview.subgeometry(geo).unwrap();
|
|
||||||
damage[idx] = widget.draw(&mut state.fonts.unwrap().borrow_mut(), &mut subview);
|
damage[idx] = widget.draw(&mut state.fonts.unwrap().borrow_mut(), &mut subview);
|
||||||
//draw_box(&mut subview, &Color::new(1.0, 0.5, 0.0, 1.0), (geo.width, geo.height));
|
//draw_box(&mut subview, &Color::new(1.0, 0.5, 0.0, 1.0), (geo.width, geo.height));
|
||||||
}
|
}
|
||||||
@@ -196,10 +217,10 @@ fn main() {
|
|||||||
drew = true;
|
drew = true;
|
||||||
|
|
||||||
let old_damage = damage[idx];
|
let old_damage = damage[idx];
|
||||||
bufview.subgeometry(old_damage).unwrap().memset(&bg);
|
bufview.subgeometry(old_damage).memset(Color::BLACK);
|
||||||
|
|
||||||
let geo = widget.geometry();
|
let geo = widget.geometry();
|
||||||
let mut subview = bufview.subgeometry(geo).unwrap();
|
let mut subview = bufview.subgeometry(geo);
|
||||||
|
|
||||||
let new_damage =
|
let new_damage =
|
||||||
widget.draw(&mut state.fonts.unwrap().borrow_mut(), &mut subview);
|
widget.draw(&mut state.fonts.unwrap().borrow_mut(), &mut subview);
|
||||||
@@ -223,5 +244,7 @@ fn main() {
|
|||||||
|
|
||||||
surface.attach(Some(&buf.buffer), 0, 0);
|
surface.attach(Some(&buf.buffer), 0, 0);
|
||||||
surface.commit();
|
surface.commit();
|
||||||
|
// eprintln!("draw time: {}", (Local::now() - now).num_milliseconds());
|
||||||
|
// std::process::exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+86
-40
@@ -5,12 +5,10 @@ use std::{
|
|||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
use calloop::ping::Ping;
|
|
||||||
|
|
||||||
use wayland_client::{
|
use wayland_client::{
|
||||||
protocol::{
|
protocol::{
|
||||||
wl_buffer, wl_compositor, wl_keyboard, wl_registry, wl_seat, wl_shm, wl_shm_pool,
|
wl_buffer, wl_compositor, wl_keyboard, wl_registry, wl_seat, wl_shm, wl_shm_pool,
|
||||||
wl_surface,
|
wl_surface, wl_pointer,
|
||||||
},
|
},
|
||||||
Connection, Dispatch, QueueHandle, WEnum,
|
Connection, Dispatch, QueueHandle, WEnum,
|
||||||
};
|
};
|
||||||
@@ -23,46 +21,11 @@ use wayland_protocols::xdg::{
|
|||||||
use crate::{
|
use crate::{
|
||||||
buffer::BufferManager,
|
buffer::BufferManager,
|
||||||
fonts::{FontMap, MaybeFontMap},
|
fonts::{FontMap, MaybeFontMap},
|
||||||
keyboard::{KeyEvent, Keyboard},
|
keyboard::Keyboard,
|
||||||
widgets::{Geometry, Layout, Widget, WidgetUpdater},
|
widgets::{Geometry, Layout, Widget, WidgetUpdater},
|
||||||
|
event::{Event, Events, PointerEvent, PointerButton},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub enum Event {
|
|
||||||
NewMinute,
|
|
||||||
PowerUpdate,
|
|
||||||
KeyEvent(KeyEvent),
|
|
||||||
TokenUpdate(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Events {
|
|
||||||
dirty: bool,
|
|
||||||
events: Vec<Event>,
|
|
||||||
ping: Ping,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Events {
|
|
||||||
pub fn new(ping: Ping) -> Arc<Mutex<Events>> {
|
|
||||||
Arc::new(Mutex::new(Events {
|
|
||||||
dirty: false,
|
|
||||||
events: Vec::new(),
|
|
||||||
ping,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_event(&mut self, ev: Event) {
|
|
||||||
self.events.push(ev);
|
|
||||||
if !self.dirty {
|
|
||||||
self.dirty = true;
|
|
||||||
self.ping.ping();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn flush(&mut self) -> Vec<Event> {
|
|
||||||
self.dirty = false;
|
|
||||||
self.events.drain(..).collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct State {
|
pub struct State {
|
||||||
pub running: bool,
|
pub running: bool,
|
||||||
pub dirty: bool,
|
pub dirty: bool,
|
||||||
@@ -77,6 +40,7 @@ pub struct State {
|
|||||||
pub bufmgr: BufferManager,
|
pub bufmgr: BufferManager,
|
||||||
pub widgets: Vec<Box<dyn Widget>>,
|
pub widgets: Vec<Box<dyn Widget>>,
|
||||||
keyboard: Keyboard,
|
keyboard: Keyboard,
|
||||||
|
pointer: Option<(f64, f64)>,
|
||||||
pub fonts: MaybeFontMap,
|
pub fonts: MaybeFontMap,
|
||||||
pub events: Arc<Mutex<Events>>,
|
pub events: Arc<Mutex<Events>>,
|
||||||
layout: Rc<Box<dyn Layout>>,
|
layout: Rc<Box<dyn Layout>>,
|
||||||
@@ -102,6 +66,7 @@ impl State {
|
|||||||
dimensions: (320, 240),
|
dimensions: (320, 240),
|
||||||
bufmgr: BufferManager::new(),
|
bufmgr: BufferManager::new(),
|
||||||
keyboard: Keyboard::new(),
|
keyboard: Keyboard::new(),
|
||||||
|
pointer: None,
|
||||||
widgets,
|
widgets,
|
||||||
fonts,
|
fonts,
|
||||||
events,
|
events,
|
||||||
@@ -380,6 +345,9 @@ impl Dispatch<wl_seat::WlSeat, ()> for State {
|
|||||||
if capabilities.contains(wl_seat::Capability::Keyboard) {
|
if capabilities.contains(wl_seat::Capability::Keyboard) {
|
||||||
seat.get_keyboard(qh, ());
|
seat.get_keyboard(qh, ());
|
||||||
}
|
}
|
||||||
|
if capabilities.contains(wl_seat::Capability::Pointer) {
|
||||||
|
seat.get_pointer(qh, ());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -431,6 +399,84 @@ impl Dispatch<wl_keyboard::WlKeyboard, ()> for State {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const BTN_LEFT: u32 = 0x110;
|
||||||
|
const BTN_RIGHT: u32 = 0x111;
|
||||||
|
const BTN_MIDDLE: u32 = 0x112;
|
||||||
|
|
||||||
|
impl Dispatch<wl_pointer::WlPointer, ()> for State {
|
||||||
|
fn event(
|
||||||
|
state: &mut Self,
|
||||||
|
_: &wl_pointer::WlPointer,
|
||||||
|
event: wl_pointer::Event,
|
||||||
|
_: &(),
|
||||||
|
_: &Connection,
|
||||||
|
_: &QueueHandle<Self>,
|
||||||
|
) {
|
||||||
|
match event {
|
||||||
|
wl_pointer::Event::Enter { surface_x, surface_y, .. } => {
|
||||||
|
state.pointer = Some((surface_x, surface_y));
|
||||||
|
},
|
||||||
|
wl_pointer::Event::Motion { surface_x, surface_y, .. } => {
|
||||||
|
state.pointer = Some((surface_x, surface_y));
|
||||||
|
},
|
||||||
|
wl_pointer::Event::Leave { .. } => {
|
||||||
|
state.pointer = None
|
||||||
|
},
|
||||||
|
wl_pointer::Event::Axis { axis, value, .. } => match state.pointer {
|
||||||
|
Some((x, y)) => {
|
||||||
|
let axis = match axis {
|
||||||
|
WEnum::Value(wl_pointer::Axis::VerticalScroll) => PointerButton::ScrollVertical(value),
|
||||||
|
WEnum::Value(wl_pointer::Axis::HorizontalScroll) => PointerButton::ScrollHorizontal(value),
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
let pos = (x as u32, y as u32);
|
||||||
|
for widget in state.widgets.iter_mut() {
|
||||||
|
let geo = widget.geometry();
|
||||||
|
if geo.contains(pos) {
|
||||||
|
let pos = (pos.0 - geo.x, pos.1 - geo.y);
|
||||||
|
let ev = Event::PointerEvent(PointerEvent{
|
||||||
|
button: axis,
|
||||||
|
pos: pos,
|
||||||
|
});
|
||||||
|
widget.event(&ev);
|
||||||
|
state.dirty = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
|
},
|
||||||
|
wl_pointer::Event::Button { button, state: button_state, .. } => match (button, button_state, state.pointer) {
|
||||||
|
(button, WEnum::Value(wl_pointer::ButtonState::Pressed), Some((x, y))) => {
|
||||||
|
let button = match button {
|
||||||
|
BTN_LEFT => PointerButton::Left,
|
||||||
|
BTN_RIGHT => PointerButton::Right,
|
||||||
|
BTN_MIDDLE => PointerButton::Middle,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
let pos = (x as u32, y as u32);
|
||||||
|
for widget in state.widgets.iter_mut() {
|
||||||
|
let geo = widget.geometry();
|
||||||
|
if geo.contains(pos) {
|
||||||
|
|
||||||
|
let pos = (pos.0 - geo.x, pos.1 - geo.y);
|
||||||
|
let ev = Event::PointerEvent(PointerEvent{
|
||||||
|
button: button,
|
||||||
|
pos: pos,
|
||||||
|
});
|
||||||
|
widget.event(&ev);
|
||||||
|
state.dirty = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Dispatch<xdg_activation_v1::XdgActivationV1, ()> for State {
|
impl Dispatch<xdg_activation_v1::XdgActivationV1, ()> for State {
|
||||||
fn event(
|
fn event(
|
||||||
_: &mut Self,
|
_: &mut Self,
|
||||||
|
|||||||
+48
-48
@@ -1,12 +1,16 @@
|
|||||||
use ini::{Ini, ParseOption};
|
use std::{
|
||||||
use itertools::Itertools;
|
cmp::Ordering,
|
||||||
use std::cmp::Ordering;
|
collections::HashSet,
|
||||||
use std::env;
|
env,
|
||||||
use std::error::Error;
|
error::Error,
|
||||||
use std::io::Error as io_error;
|
fs::read_to_string,
|
||||||
use std::io::ErrorKind;
|
io::{Error as io_error, ErrorKind},
|
||||||
|
};
|
||||||
|
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
|
use crate::utils::inish;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, Hash)]
|
#[derive(Clone, Debug, Eq, Hash)]
|
||||||
pub struct Desktop {
|
pub struct Desktop {
|
||||||
pub entry_type: String,
|
pub entry_type: String,
|
||||||
@@ -21,23 +25,18 @@ pub struct Desktop {
|
|||||||
|
|
||||||
impl Desktop {
|
impl Desktop {
|
||||||
fn parse(f: &str) -> Result<Desktop, Box<dyn Error>> {
|
fn parse(f: &str) -> Result<Desktop, Box<dyn Error>> {
|
||||||
let file = Ini::load_from_file_opt(
|
let s = read_to_string(f)?;
|
||||||
f,
|
let config = inish::parse(&s)?;
|
||||||
ParseOption {
|
match config.get("Desktop Entry") {
|
||||||
enabled_quote: false,
|
Some(section) => Ok(Desktop {
|
||||||
enabled_escape: false,
|
entry_type: section.get("Type").unwrap_or(&"").to_string(),
|
||||||
},
|
name: section.get("Name").unwrap_or(&"").to_string(),
|
||||||
)?;
|
term: section.get("Terminal").unwrap_or(&"") == &"true",
|
||||||
match file.section(Some("Desktop Entry")) {
|
no_display: section.get("NoDisplay").unwrap_or(&"") == &"true",
|
||||||
Some(desktop) => Ok(Desktop {
|
hidden: section.get("Hidden").unwrap_or(&"") == &"true",
|
||||||
entry_type: desktop.get("Type").unwrap_or(&"".to_string()).to_string(),
|
exec: section.get("Exec").map(|x| x.to_string()),
|
||||||
name: desktop.get("Name").unwrap_or(&"".to_string()).to_string(),
|
url: section.get("URL").map(|x| x.to_string()),
|
||||||
term: desktop.get("Terminal").unwrap_or(&"".to_string()) == "true",
|
keywords: section
|
||||||
no_display: desktop.get("NoDisplay").unwrap_or(&"".to_string()) == "true",
|
|
||||||
hidden: desktop.get("Hidden").unwrap_or(&"".to_string()) == "true",
|
|
||||||
exec: desktop.get("Exec").map(|x| x.to_string()),
|
|
||||||
url: desktop.get("URL").map(|x| x.to_string()),
|
|
||||||
keywords: desktop
|
|
||||||
.get("Keywords")
|
.get("Keywords")
|
||||||
.map(|x| {
|
.map(|x| {
|
||||||
x.split(';')
|
x.split(';')
|
||||||
@@ -53,20 +52,6 @@ impl Desktop {
|
|||||||
))),
|
))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_dir(d: &str) -> Result<Vec<Desktop>, Box<dyn Error>> {
|
|
||||||
let mut files: Vec<Desktop> = Vec::with_capacity(16);
|
|
||||||
for entry in WalkDir::new(d) {
|
|
||||||
let entry = entry?;
|
|
||||||
let path = entry.path();
|
|
||||||
|
|
||||||
if let Ok(d) = Desktop::parse(path.to_str().unwrap()) {
|
|
||||||
files.push(d)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(files)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ord for Desktop {
|
impl Ord for Desktop {
|
||||||
@@ -99,14 +84,29 @@ pub fn load_desktop_files() -> Vec<Desktop> {
|
|||||||
None => "/usr/local/share:/usr/share".to_string(),
|
None => "/usr/local/share:/usr/share".to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
std::iter::once(xdg_data_home.as_str())
|
let dirs = std::iter::once(xdg_data_home.as_str()).chain(xdg_data_dirs.split(':'));
|
||||||
.chain(xdg_data_dirs.split(':'))
|
|
||||||
.map(|p| Desktop::parse_dir(&format!("{}/applications", p)))
|
let mut desktop: Vec<Desktop> = Vec::new();
|
||||||
.filter_map(Result::ok)
|
let mut seen: HashSet<String> = HashSet::new();
|
||||||
.flatten()
|
|
||||||
.filter(|d| {
|
for dir in dirs {
|
||||||
!d.hidden && !d.no_display && (d.entry_type == "Application" || d.entry_type == "Link")
|
for entry in WalkDir::new(format!("{}/applications", dir)) {
|
||||||
})
|
if let Ok(entry) = entry {
|
||||||
.unique_by(|x| x.name.clone())
|
if let Ok(d) = Desktop::parse(entry.path().to_str().unwrap()) {
|
||||||
.collect()
|
if d.hidden
|
||||||
|
|| d.no_display
|
||||||
|
|| (d.entry_type != "Application" && d.entry_type != "Link")
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if !seen.contains(&d.name) {
|
||||||
|
seen.insert(d.name.to_string());
|
||||||
|
desktop.push(d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
desktop
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,134 @@
|
|||||||
|
use std::{collections::HashMap, error::Error};
|
||||||
|
|
||||||
|
fn parse_field<'a>(line: &'a str) -> Result<(&'a str, &'a str), Box<dyn Error>> {
|
||||||
|
let split = match line.find('=') {
|
||||||
|
Some(v) => v,
|
||||||
|
None => return Err("expected equals sign on line, but found none".into()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let (key, value) = line.split_at(split);
|
||||||
|
let (key, value) = (key.trim(), value.trim_matches('=').trim());
|
||||||
|
|
||||||
|
Ok((key, value))
|
||||||
|
}
|
||||||
|
|
||||||
|
type InishSection<'a> = HashMap<&'a str, &'a str>;
|
||||||
|
type Inish<'a> = HashMap<&'a str, InishSection<'a>>;
|
||||||
|
|
||||||
|
pub fn parse<'a>(s: &'a str) -> Result<Inish<'a>, Box<dyn Error>> {
|
||||||
|
let mut sections: Inish<'a> = HashMap::new();
|
||||||
|
let mut current_section = HashMap::new();
|
||||||
|
let mut current_section_name = "";
|
||||||
|
|
||||||
|
for line in s.lines() {
|
||||||
|
let line = line.trim();
|
||||||
|
let mut chars = line.chars();
|
||||||
|
let start = chars.next();
|
||||||
|
let end = chars.last();
|
||||||
|
match (start, end) {
|
||||||
|
(Some('#'), _) => continue,
|
||||||
|
(Some('['), Some(']')) => {
|
||||||
|
sections.insert(current_section_name, current_section);
|
||||||
|
current_section = HashMap::new();
|
||||||
|
let len = line.bytes().count();
|
||||||
|
current_section_name = &line[1..len - 1].trim();
|
||||||
|
}
|
||||||
|
(Some('['), v) => {
|
||||||
|
return Err(format!(
|
||||||
|
"expected Some(']') to terminate section name, but got {:?}",
|
||||||
|
v
|
||||||
|
)
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
_ if line.is_empty() => continue,
|
||||||
|
_ => {
|
||||||
|
let (key, value) = parse_field(line)?;
|
||||||
|
current_section.insert(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sections.insert(current_section_name, current_section);
|
||||||
|
Ok(sections)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sections() {
|
||||||
|
let config = parse(
|
||||||
|
"
|
||||||
|
[section_a]
|
||||||
|
[section_b]
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.expect("config didn't parse");
|
||||||
|
|
||||||
|
if !config.contains_key("section_a") {
|
||||||
|
panic!("named section did not exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
if !config.contains_key("section_b") {
|
||||||
|
panic!("named section did not exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
if !config.contains_key("") {
|
||||||
|
panic!("unnamed section did not exist");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fields() {
|
||||||
|
let config = parse(
|
||||||
|
"
|
||||||
|
field_outside = 'hello'
|
||||||
|
[section_a]
|
||||||
|
field_a = 1234
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.expect("config didn't parse");
|
||||||
|
|
||||||
|
let section_a = match config.get("section_a") {
|
||||||
|
Some(v) => v,
|
||||||
|
None => panic!("named section did not exist"),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(section_a.get("field_a"), Some(&"1234"));
|
||||||
|
|
||||||
|
let section_unnamed = match config.get("") {
|
||||||
|
Some(v) => v,
|
||||||
|
None => panic!("unnamed section did not exist"),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(section_unnamed.get("field_outside"), Some(&"'hello'"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn whitespaces() {
|
||||||
|
let config = parse(
|
||||||
|
"
|
||||||
|
|
||||||
|
field outside = 'hello'
|
||||||
|
|
||||||
|
[ section a ]
|
||||||
|
field a = 1234 ",
|
||||||
|
)
|
||||||
|
.expect("config didn't parse");
|
||||||
|
|
||||||
|
let section_a = match config.get("section a") {
|
||||||
|
Some(v) => v,
|
||||||
|
None => panic!("named section did not exist"),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(section_a.get("field a"), Some(&"1234"));
|
||||||
|
|
||||||
|
let section_unnamed = match config.get("") {
|
||||||
|
Some(v) => v,
|
||||||
|
None => panic!("unnamed section did not exist"),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(section_unnamed.get("field outside"), Some(&"'hello'"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1 +1,2 @@
|
|||||||
pub mod desktop;
|
pub mod desktop;
|
||||||
|
mod inish;
|
||||||
|
|||||||
@@ -0,0 +1,238 @@
|
|||||||
|
|
||||||
|
use std::{
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
thread,
|
||||||
|
error::Error,
|
||||||
|
rc::Rc,
|
||||||
|
cell::RefCell,
|
||||||
|
os::fd::RawFd,
|
||||||
|
};
|
||||||
|
|
||||||
|
use nix::unistd::{
|
||||||
|
pipe, write, read,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
color::Color,
|
||||||
|
event::{Event, Events, PointerButton},
|
||||||
|
fonts::FontMap,
|
||||||
|
widgets::bar_widget::{BarWidget, BarWidgetImpl},
|
||||||
|
};
|
||||||
|
|
||||||
|
use libpulse_binding::volume::ChannelVolumes;
|
||||||
|
|
||||||
|
fn monitor(events: Arc<Mutex<Events>>, inner: Arc<Mutex<InnerAudio>>, pipe: RawFd) -> Result<(), Box<dyn Error>> {
|
||||||
|
use libpulse_binding::{
|
||||||
|
mainloop::{
|
||||||
|
self,
|
||||||
|
standard::{
|
||||||
|
IterateResult,
|
||||||
|
},
|
||||||
|
api::Mainloop,
|
||||||
|
events::io::FlagSet as IoFlagSet,
|
||||||
|
},
|
||||||
|
callbacks::ListResult,
|
||||||
|
context::{
|
||||||
|
Context,
|
||||||
|
FlagSet,
|
||||||
|
subscribe::{InterestMaskSet, Facility},
|
||||||
|
State,
|
||||||
|
},
|
||||||
|
proplist::{properties, Proplist},
|
||||||
|
volume::Volume,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut proplist = Proplist::new().unwrap();
|
||||||
|
proplist
|
||||||
|
.set_str(properties::APPLICATION_NAME, "wldash")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut mainloop = mainloop::standard::Mainloop::new().unwrap();
|
||||||
|
let context = Rc::new(RefCell::new(Context::new_with_proplist(&mainloop, "wldash_context", &proplist).unwrap()));
|
||||||
|
context.borrow_mut().connect(None, FlagSet::NOFLAGS, None)?;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
mainloop.iterate(false);
|
||||||
|
match context.borrow().get_state() {
|
||||||
|
State::Ready => break,
|
||||||
|
State::Failed | State::Terminated => panic!("damn"),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let local_context = context.clone();
|
||||||
|
let local_inner = inner.clone();
|
||||||
|
let local_events = events.clone();
|
||||||
|
context
|
||||||
|
.borrow_mut()
|
||||||
|
.set_subscribe_callback(Some(Box::new(move |facility, _operation, index| {
|
||||||
|
match facility {
|
||||||
|
Some(Facility::Sink) => {
|
||||||
|
let introspector = local_context.borrow_mut().introspect();
|
||||||
|
let inner = local_inner.clone();
|
||||||
|
let events = local_events.clone();
|
||||||
|
introspector.get_sink_info_by_index(index, move |res| {
|
||||||
|
match res {
|
||||||
|
ListResult::End | ListResult::Error => (),
|
||||||
|
ListResult::Item(sink_info) => if let Some(_) = &sink_info.name {
|
||||||
|
let avg = sink_info.volume.avg().0 as f32 / Volume::NORMAL.0 as f32;
|
||||||
|
let mut inner = inner.lock().unwrap();
|
||||||
|
inner.volume = avg;
|
||||||
|
inner.mute = sink_info.mute;
|
||||||
|
inner.dirty = true;
|
||||||
|
drop(inner);
|
||||||
|
let mut events = events.lock().unwrap();
|
||||||
|
events.add_event(Event::AudioUpdate);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
})));
|
||||||
|
|
||||||
|
context
|
||||||
|
.borrow_mut()
|
||||||
|
.subscribe(InterestMaskSet::SINK, |_| {});
|
||||||
|
|
||||||
|
let introspector = context.borrow_mut().introspect();
|
||||||
|
let local_inner = inner.clone();
|
||||||
|
introspector.get_sink_info_by_name("@DEFAULT_SINK@", move |res| {
|
||||||
|
match res {
|
||||||
|
ListResult::End | ListResult::Error => (),
|
||||||
|
ListResult::Item(sink_info) => if let Some(_) = &sink_info.name {
|
||||||
|
let avg = sink_info.volume.avg().0 as f32 / Volume::NORMAL.0 as f32;
|
||||||
|
let mut inner = local_inner.lock().unwrap();
|
||||||
|
inner.volume = avg;
|
||||||
|
inner.channel_volume = Some(sink_info.volume);
|
||||||
|
inner.mute = sink_info.mute;
|
||||||
|
inner.dirty = true;
|
||||||
|
drop(inner);
|
||||||
|
let mut events = events.lock().unwrap();
|
||||||
|
events.add_event(Event::AudioUpdate);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
drop(introspector);
|
||||||
|
|
||||||
|
let local_context = context.clone();
|
||||||
|
let local_inner = inner.clone();
|
||||||
|
let event_source = mainloop.new_io_event(pipe as i32, IoFlagSet::INPUT, Box::new(move |_, _, _| {
|
||||||
|
let mut buf = [0; 8];
|
||||||
|
_ = read(pipe, &mut buf);
|
||||||
|
|
||||||
|
let mut inner = local_inner.lock().unwrap();
|
||||||
|
let mut introspector = local_context.borrow_mut().introspect();
|
||||||
|
match inner.last_click.take() {
|
||||||
|
Some(Change::Volume(volume)) => {
|
||||||
|
// do something
|
||||||
|
let mut vol = inner.channel_volume.unwrap();
|
||||||
|
vol.scale(Volume((volume * Volume::NORMAL.0 as f32).round() as u32));
|
||||||
|
introspector.set_sink_volume_by_name("@DEFAULT_SINK@", &vol, None);
|
||||||
|
},
|
||||||
|
Some(Change::VolumeInc(value)) => {
|
||||||
|
let mut vol = inner.channel_volume.unwrap();
|
||||||
|
// apply step to volumes
|
||||||
|
let step = (value * Volume::NORMAL.0 as f32).round() as i32;
|
||||||
|
if step > 0 {
|
||||||
|
vol.inc_clamp(Volume(step as u32), Volume::NORMAL);
|
||||||
|
} else {
|
||||||
|
vol.decrease(Volume(-step as u32));
|
||||||
|
}
|
||||||
|
// HACK: It would be better to only update the volume from feedback, but axis
|
||||||
|
// events fire fast and require the last set volume immediately for reference.
|
||||||
|
inner.channel_volume = Some(vol);
|
||||||
|
introspector.set_sink_volume_by_name("@DEFAULT_SINK@", &vol, None);
|
||||||
|
},
|
||||||
|
Some(Change::ToggleMute) => {
|
||||||
|
introspector.set_sink_mute_by_name("@DEFAULT_SINK@", !inner.mute, None);
|
||||||
|
},
|
||||||
|
None => (),
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match mainloop.iterate(true) {
|
||||||
|
IterateResult::Quit(_) | IterateResult::Err(_) => break,
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need to keep the event source alive
|
||||||
|
_ = event_source;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_monitor(events: Arc<Mutex<Events>>, inner: Arc<Mutex<InnerAudio>>, pipe: RawFd) {
|
||||||
|
thread::Builder::new()
|
||||||
|
.name("audiomon".to_string())
|
||||||
|
.spawn(move || { monitor(events, inner, pipe).unwrap() })
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Change {
|
||||||
|
Volume(f32),
|
||||||
|
VolumeInc(f32),
|
||||||
|
ToggleMute,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct InnerAudio {
|
||||||
|
volume: f32,
|
||||||
|
channel_volume: Option<ChannelVolumes>,
|
||||||
|
mute: bool,
|
||||||
|
dirty: bool,
|
||||||
|
last_click: Option<Change>,
|
||||||
|
pipe: RawFd,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Audio {
|
||||||
|
inner: Arc<Mutex<InnerAudio>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Audio {
|
||||||
|
pub fn new(events: Arc<Mutex<Events>>, fm: &mut FontMap, font: &'static str, size: f32) -> BarWidget {
|
||||||
|
let (a, b) = pipe().unwrap();
|
||||||
|
let audio = Audio {
|
||||||
|
inner: Arc::new(Mutex::new(InnerAudio{
|
||||||
|
volume: 0.0,
|
||||||
|
channel_volume: None,
|
||||||
|
mute: false,
|
||||||
|
dirty: false,
|
||||||
|
last_click: None,
|
||||||
|
pipe: b,
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
start_monitor(events, audio.inner.clone(), a);
|
||||||
|
BarWidget::new(Box::new(audio), fm, font, size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BarWidgetImpl for Audio {
|
||||||
|
fn get_dirty(&self) -> bool {
|
||||||
|
self.inner.lock().unwrap().dirty
|
||||||
|
}
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"volume"
|
||||||
|
}
|
||||||
|
fn value(&self) -> f32 {
|
||||||
|
self.inner.lock().unwrap().volume
|
||||||
|
}
|
||||||
|
fn color(&self) -> Color {
|
||||||
|
match self.inner.lock().unwrap().mute {
|
||||||
|
true => Color::YELLOW,
|
||||||
|
false => Color::WHITE,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn click(&mut self, pos: f32, btn: PointerButton) {
|
||||||
|
let mut inner = self.inner.lock().unwrap();
|
||||||
|
inner.last_click = match btn {
|
||||||
|
PointerButton::Left => Some(Change::Volume(pos)),
|
||||||
|
PointerButton::Right => Some(Change::ToggleMute),
|
||||||
|
PointerButton::ScrollVertical(val) => Some(Change::VolumeInc((val / 512.) as f32)),
|
||||||
|
PointerButton::ScrollHorizontal(val) => Some(Change::VolumeInc((val / 100.) as f32)),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
_ = write(inner.pipe, &[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ use std::{
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
color::Color,
|
color::Color,
|
||||||
|
fonts::FontMap,
|
||||||
widgets::bar_widget::{BarWidget, BarWidgetImpl},
|
widgets::bar_widget::{BarWidget, BarWidgetImpl},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -28,7 +29,7 @@ impl Backlight {
|
|||||||
self.max = read_file_as_u64(self.device_path.join("max_brightness").as_path()).unwrap();
|
self.max = read_file_as_u64(self.device_path.join("max_brightness").as_path()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(path: &str, font: &'static str, size: f32) -> BarWidget {
|
pub fn new(path: &str, fm: &mut FontMap, font: &'static str, size: f32) -> BarWidget {
|
||||||
let mut dev = Backlight {
|
let mut dev = Backlight {
|
||||||
device_path: Path::new("/sys/class/backlight").to_path_buf().join(path),
|
device_path: Path::new("/sys/class/backlight").to_path_buf().join(path),
|
||||||
cur: 0,
|
cur: 0,
|
||||||
@@ -36,7 +37,7 @@ impl Backlight {
|
|||||||
};
|
};
|
||||||
|
|
||||||
dev.update();
|
dev.update();
|
||||||
BarWidget::new(Box::new(dev), font, size)
|
BarWidget::new(Box::new(dev), fm, font, size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,6 +54,6 @@ impl BarWidgetImpl for Backlight {
|
|||||||
self.cur as f32 / self.max as f32
|
self.cur as f32 / self.max as f32
|
||||||
}
|
}
|
||||||
fn color(&self) -> Color {
|
fn color(&self) -> Color {
|
||||||
Color::new(1.0, 1.0, 1.0, 1.0)
|
Color::WHITE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use crate::{
|
|||||||
draw::{draw_bar, draw_box},
|
draw::{draw_bar, draw_box},
|
||||||
fonts::FontMap,
|
fonts::FontMap,
|
||||||
widgets::{Geometry, Widget},
|
widgets::{Geometry, Widget},
|
||||||
|
event::{Event, PointerButton},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait BarWidgetImpl {
|
pub trait BarWidgetImpl {
|
||||||
@@ -15,6 +16,7 @@ pub trait BarWidgetImpl {
|
|||||||
fn name(&self) -> &'static str;
|
fn name(&self) -> &'static str;
|
||||||
fn value(&self) -> f32;
|
fn value(&self) -> f32;
|
||||||
fn color(&self) -> Color;
|
fn color(&self) -> Color;
|
||||||
|
fn click(&mut self, _pos: f32, _btn: PointerButton) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BarWidget {
|
pub struct BarWidget {
|
||||||
@@ -25,7 +27,8 @@ pub struct BarWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl BarWidget {
|
impl BarWidget {
|
||||||
pub fn new(inner_widget: Box<dyn BarWidgetImpl>, font: &'static str, size: f32) -> BarWidget {
|
pub fn new(inner_widget: Box<dyn BarWidgetImpl>, fm: &mut FontMap, font: &'static str, size: f32) -> BarWidget {
|
||||||
|
fm.queue_font(font, size, inner_widget.name());
|
||||||
BarWidget {
|
BarWidget {
|
||||||
geometry: Default::default(),
|
geometry: Default::default(),
|
||||||
inner_widget,
|
inner_widget,
|
||||||
@@ -46,10 +49,10 @@ impl Widget for BarWidget {
|
|||||||
|
|
||||||
fn draw(&mut self, fonts: &mut FontMap, view: &mut BufferView) -> Geometry {
|
fn draw(&mut self, fonts: &mut FontMap, view: &mut BufferView) -> Geometry {
|
||||||
let font = fonts.get_font(self.font, self.size);
|
let font = fonts.get_font(self.font, self.size);
|
||||||
let fg = Color::new(1., 1., 1., 1.);
|
let fg = Color::WHITE;
|
||||||
let bg = Color::new(0., 0., 0., 1.);
|
let bg = Color::BLACK;
|
||||||
|
|
||||||
font.auto_draw_text(view, &bg, &fg, self.inner_widget.name())
|
font.draw_text(view, bg, fg, self.inner_widget.name())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let size = self.size.ceil() as u32;
|
let size = self.size.ceil() as u32;
|
||||||
let bar_offset = 4 * size;
|
let bar_offset = 4 * size;
|
||||||
@@ -57,8 +60,8 @@ impl Widget for BarWidget {
|
|||||||
|
|
||||||
let c = self.inner_widget.color();
|
let c = self.inner_widget.color();
|
||||||
draw_bar(
|
draw_bar(
|
||||||
&mut view.offset((bar_offset, 0)).unwrap(),
|
&mut view.offset((bar_offset, 0)),
|
||||||
&c,
|
c,
|
||||||
self.geometry.width - bar_offset,
|
self.geometry.width - bar_offset,
|
||||||
size,
|
size,
|
||||||
val,
|
val,
|
||||||
@@ -66,8 +69,8 @@ impl Widget for BarWidget {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
draw_box(
|
draw_box(
|
||||||
&mut view.offset((bar_offset, 0)).unwrap(),
|
&mut view.offset((bar_offset, 0)),
|
||||||
&c,
|
c,
|
||||||
(self.geometry.width - bar_offset, size),
|
(self.geometry.width - bar_offset, size),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -88,4 +91,18 @@ impl Widget for BarWidget {
|
|||||||
};
|
};
|
||||||
self.geometry
|
self.geometry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn event(&mut self, event: &Event) {
|
||||||
|
match event {
|
||||||
|
Event::PointerEvent(ev) => {
|
||||||
|
let offset = 4 * self.size.ceil() as u32;
|
||||||
|
if ev.pos.0 >= offset {
|
||||||
|
let val = (ev.pos.0 - offset) as f32 / (self.geometry.width - offset) as f32;
|
||||||
|
self.inner_widget.click(val, ev.button);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+68
-103
@@ -1,110 +1,81 @@
|
|||||||
use std::{
|
use std::{
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
thread,
|
thread,
|
||||||
time::Duration,
|
error::Error,
|
||||||
};
|
|
||||||
|
|
||||||
use dbus::blocking::{
|
|
||||||
stdintf::org_freedesktop_dbus::{Properties, PropertiesPropertiesChanged},
|
|
||||||
LocalConnection,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
color::Color,
|
color::Color,
|
||||||
state::{Event, Events},
|
event::{Event, Events},
|
||||||
|
fonts::FontMap,
|
||||||
widgets::bar_widget::{BarWidget, BarWidgetImpl},
|
widgets::bar_widget::{BarWidget, BarWidgetImpl},
|
||||||
};
|
};
|
||||||
|
|
||||||
enum UpowerBatteryState {
|
use upower_dbus::BatteryState;
|
||||||
Charging,
|
|
||||||
Discharging,
|
|
||||||
Empty,
|
|
||||||
Full,
|
|
||||||
NotCharging,
|
|
||||||
Unknown,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct InnerBattery {
|
struct InnerBattery {
|
||||||
value: f32,
|
value: f32,
|
||||||
state: UpowerBatteryState,
|
state: BatteryState,
|
||||||
dirty: bool,
|
dirty: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn monitor(inner: Arc<Mutex<InnerBattery>>, events: Arc<Mutex<Events>>) -> Result<(), Box<dyn Error>> {
|
||||||
|
use zbus::Connection;
|
||||||
|
use upower_dbus::UPowerProxy;
|
||||||
|
use tokio_stream::StreamExt;
|
||||||
|
|
||||||
|
let conn = Connection::system().await?;
|
||||||
|
let proxy = UPowerProxy::new(&conn).await?;
|
||||||
|
|
||||||
|
let device = proxy.get_display_device().await?;
|
||||||
|
|
||||||
|
let local_inner = inner.clone();
|
||||||
|
let local_events = events.clone();
|
||||||
|
let mut percent_stream = device.receive_percentage_changed().await;
|
||||||
|
let a = tokio::spawn(async move {
|
||||||
|
while let Some(percent) = percent_stream.next().await {
|
||||||
|
let percent = percent.get().await.unwrap() as f32 / 100.;
|
||||||
|
let mut inner = local_inner.lock().unwrap();
|
||||||
|
inner.value = percent;
|
||||||
|
inner.dirty = true;
|
||||||
|
drop(inner);
|
||||||
|
|
||||||
|
let mut events = local_events.lock().unwrap();
|
||||||
|
events.add_event(Event::PowerUpdate);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let local_inner = inner.clone();
|
||||||
|
let local_events = events.clone();
|
||||||
|
let mut state_stream = device.receive_state_changed().await;
|
||||||
|
let b = tokio::spawn(async move {
|
||||||
|
while let Some(state) = state_stream.next().await {
|
||||||
|
let state = state.get().await.unwrap();
|
||||||
|
let mut inner = local_inner.lock().unwrap();
|
||||||
|
inner.state = state;
|
||||||
|
inner.dirty = true;
|
||||||
|
drop(inner);
|
||||||
|
|
||||||
|
let mut events = local_events.lock().unwrap();
|
||||||
|
events.add_event(Event::PowerUpdate);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
a.await?;
|
||||||
|
b.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn start_monitor(inner: Arc<Mutex<InnerBattery>>, events: Arc<Mutex<Events>>) {
|
fn start_monitor(inner: Arc<Mutex<InnerBattery>>, events: Arc<Mutex<Events>>) {
|
||||||
|
use tokio::runtime;
|
||||||
thread::Builder::new()
|
thread::Builder::new()
|
||||||
.name("battmon".to_string())
|
.name("battmon".to_string())
|
||||||
.spawn(move || {
|
.spawn(move || {
|
||||||
let conn = LocalConnection::new_system().unwrap();
|
let rt = runtime::Builder::new_current_thread()
|
||||||
let device_path = "/org/freedesktop/UPower/devices/DisplayDevice";
|
.enable_io()
|
||||||
let proxy = conn.with_proxy(
|
.build()
|
||||||
"org.freedesktop.UPower",
|
|
||||||
device_path,
|
|
||||||
Duration::from_millis(500),
|
|
||||||
);
|
|
||||||
|
|
||||||
let capacity: f64 = proxy
|
|
||||||
.get("org.freedesktop.UPower.Device", "Percentage")
|
|
||||||
.expect("unable to get property");
|
|
||||||
let state: u32 = proxy
|
|
||||||
.get("org.freedesktop.UPower.Device", "State")
|
|
||||||
.expect("unable to get state");
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut inner = inner.lock().unwrap();
|
|
||||||
inner.value = capacity as f32 / 100.;
|
|
||||||
inner.state = match state {
|
|
||||||
1 => UpowerBatteryState::Charging,
|
|
||||||
2 => UpowerBatteryState::Discharging,
|
|
||||||
3 => UpowerBatteryState::Empty,
|
|
||||||
4 => UpowerBatteryState::Full,
|
|
||||||
5 => UpowerBatteryState::NotCharging,
|
|
||||||
6 => UpowerBatteryState::Discharging,
|
|
||||||
_ => UpowerBatteryState::Unknown,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
proxy
|
|
||||||
.match_signal(
|
|
||||||
move |c: PropertiesPropertiesChanged,
|
|
||||||
_: &LocalConnection,
|
|
||||||
_: &dbus::Message| {
|
|
||||||
if c.interface_name != "org.freedesktop.UPower.Device" {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
let mut inner = inner.lock().unwrap();
|
|
||||||
for (key, value) in c.changed_properties {
|
|
||||||
match key.as_str() {
|
|
||||||
"State" => {
|
|
||||||
inner.state = match value.0.as_u64().unwrap() {
|
|
||||||
1 => UpowerBatteryState::Charging,
|
|
||||||
2 => UpowerBatteryState::Discharging,
|
|
||||||
3 => UpowerBatteryState::Empty,
|
|
||||||
4 => UpowerBatteryState::Full,
|
|
||||||
5 => UpowerBatteryState::NotCharging,
|
|
||||||
6 => UpowerBatteryState::Discharging,
|
|
||||||
_ => UpowerBatteryState::Unknown,
|
|
||||||
};
|
|
||||||
inner.dirty = true;
|
|
||||||
let mut events = events.lock().unwrap();
|
|
||||||
events.add_event(Event::PowerUpdate);
|
|
||||||
}
|
|
||||||
"Percentage" => {
|
|
||||||
inner.value = value.0.as_f64().unwrap() as f32 / 100.;
|
|
||||||
inner.dirty = true;
|
|
||||||
let mut events = events.lock().unwrap();
|
|
||||||
events.add_event(Event::PowerUpdate);
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
true
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
rt.block_on(async move { monitor(inner, events).await }).unwrap();
|
||||||
loop {
|
|
||||||
conn.process(Duration::from_millis(60000)).unwrap();
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
@@ -114,16 +85,16 @@ pub struct Battery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Battery {
|
impl Battery {
|
||||||
pub fn new(events: Arc<Mutex<Events>>, font: &'static str, size: f32) -> BarWidget {
|
pub fn new(events: Arc<Mutex<Events>>, fm: &mut FontMap, font: &'static str, size: f32) -> BarWidget {
|
||||||
let battery = Battery {
|
let battery = Battery {
|
||||||
inner: Arc::new(Mutex::new(InnerBattery {
|
inner: Arc::new(Mutex::new(InnerBattery {
|
||||||
value: 0.,
|
value: 0.,
|
||||||
state: UpowerBatteryState::Unknown,
|
state: BatteryState::Unknown,
|
||||||
dirty: false,
|
dirty: false,
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
start_monitor(battery.inner.clone(), events);
|
start_monitor(battery.inner.clone(), events);
|
||||||
BarWidget::new(Box::new(battery), font, size)
|
BarWidget::new(Box::new(battery), fm, font, size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,20 +113,14 @@ impl BarWidgetImpl for Battery {
|
|||||||
fn color(&self) -> Color {
|
fn color(&self) -> Color {
|
||||||
let inner = self.inner.lock().unwrap();
|
let inner = self.inner.lock().unwrap();
|
||||||
match inner.state {
|
match inner.state {
|
||||||
UpowerBatteryState::Discharging | UpowerBatteryState::Unknown => {
|
BatteryState::Charging | BatteryState::FullyCharged => Color::LIGHTGREEN,
|
||||||
if inner.value > 0.25 {
|
BatteryState::PendingCharge => Color::LIGHTRED,
|
||||||
Color::new(1.0, 1.0, 1.0, 1.0)
|
_ => if inner.value > 0.25 {
|
||||||
} else if inner.value > 0.1 {
|
Color::WHITE
|
||||||
Color::new(1.0, 0.5, 0.0, 1.0)
|
} else if inner.value > 0.1 {
|
||||||
} else {
|
Color::DARKORANGE
|
||||||
Color::new(1.0, 0.0, 0.0, 1.0)
|
} else {
|
||||||
}
|
Color::RED
|
||||||
}
|
|
||||||
UpowerBatteryState::Charging | UpowerBatteryState::Full => {
|
|
||||||
Color::new(0.5, 1.0, 0.5, 1.0)
|
|
||||||
}
|
|
||||||
UpowerBatteryState::NotCharging | UpowerBatteryState::Empty => {
|
|
||||||
Color::new(1.0, 0.5, 0.5, 1.0)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+116
-98
@@ -4,7 +4,7 @@ use crate::{
|
|||||||
buffer::BufferView,
|
buffer::BufferView,
|
||||||
color::Color,
|
color::Color,
|
||||||
fonts::FontMap,
|
fonts::FontMap,
|
||||||
state::Event,
|
event::Event,
|
||||||
widgets::{Geometry, Widget},
|
widgets::{Geometry, Widget},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -14,18 +14,32 @@ pub struct Calendar {
|
|||||||
font: &'static str,
|
font: &'static str,
|
||||||
sections_x: i32,
|
sections_x: i32,
|
||||||
sections_y: i32,
|
sections_y: i32,
|
||||||
|
shown_sections_x: u32,
|
||||||
|
shown_sections_y: u32,
|
||||||
size: f32,
|
size: f32,
|
||||||
dirty: bool,
|
dirty: bool,
|
||||||
geometry: Geometry,
|
geometry: Geometry,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DAY_FACTOR: f32 = 1.;
|
||||||
|
const YEAR_FACTOR: f32 = 1.5;
|
||||||
|
const MONTH_FACTOR: f32 = 2.;
|
||||||
|
const DATE_FACTOR: f32 = 2.;
|
||||||
|
const LINE_HEIGHT: f32 = 1.8;
|
||||||
|
|
||||||
impl Calendar {
|
impl Calendar {
|
||||||
pub fn new(font: &'static str, size: f32, sections_x: i32, sections_y: i32) -> Calendar {
|
pub fn new(fm: &mut FontMap, font: &'static str, size: f32, sections_x: i32, sections_y: i32) -> Calendar {
|
||||||
|
fm.queue_font(font, size, "ADEFHIMNORSTUW");
|
||||||
|
fm.queue_font(font, size * 1.5, "0123456789");
|
||||||
|
fm.queue_font(font, size * 2.0, "0123456789 ADFJMOSabcehgilmnoprstuvy");
|
||||||
|
|
||||||
Calendar {
|
Calendar {
|
||||||
font,
|
font,
|
||||||
size,
|
size,
|
||||||
sections_x,
|
sections_x,
|
||||||
sections_y,
|
sections_y,
|
||||||
|
shown_sections_x: 0,
|
||||||
|
shown_sections_y: 0,
|
||||||
dirty: true,
|
dirty: true,
|
||||||
geometry: Default::default(),
|
geometry: Default::default(),
|
||||||
}
|
}
|
||||||
@@ -38,10 +52,62 @@ impl Calendar {
|
|||||||
orig: NaiveDate,
|
orig: NaiveDate,
|
||||||
mut time: NaiveDate,
|
mut time: NaiveDate,
|
||||||
) {
|
) {
|
||||||
let black = Color::new(0., 0., 0., 1.);
|
let black = Color::BLACK;
|
||||||
let white = Color::new(1., 1., 1., 1.);
|
let white = Color::WHITE;
|
||||||
let dim = Color::new(0.8, 0.8, 0.8, 1.);
|
let dim = Color::GREY80;
|
||||||
let dimmer = Color::new(0.75, 0.75, 0.75, 1.);
|
let dimmer = Color::GREY75;
|
||||||
|
|
||||||
|
let mut y_off = 1;
|
||||||
|
// TODO: Fix offsets:
|
||||||
|
// - Headline font is not correctly accounted for
|
||||||
|
|
||||||
|
//
|
||||||
|
// Draw the week day
|
||||||
|
//
|
||||||
|
for idx in 1..8 {
|
||||||
|
let day_font = fonts.get_font(self.font, self.size * DAY_FACTOR);
|
||||||
|
let wk_chr = match idx {
|
||||||
|
1 => "MON",
|
||||||
|
2 => "TUE",
|
||||||
|
3 => "WED",
|
||||||
|
4 => "THU",
|
||||||
|
5 => "FRI",
|
||||||
|
6 => "SAT",
|
||||||
|
7 => "SUN",
|
||||||
|
_ => panic!("impossible value"),
|
||||||
|
};
|
||||||
|
|
||||||
|
day_font
|
||||||
|
.draw_text(
|
||||||
|
&mut view
|
||||||
|
.offset((
|
||||||
|
idx * (self.size * 2.5).ceil() as u32 + (self.size / 5.).ceil() as u32,
|
||||||
|
y_off * (self.size * LINE_HEIGHT).ceil() as u32
|
||||||
|
+ (self.size * 1.).ceil() as u32,
|
||||||
|
)),
|
||||||
|
black,
|
||||||
|
white,
|
||||||
|
&wk_chr,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Draw the month
|
||||||
|
//
|
||||||
|
if time.year() != orig.year() {
|
||||||
|
let year_font = fonts.get_font(self.font, self.size * YEAR_FACTOR);
|
||||||
|
year_font
|
||||||
|
.draw_text(
|
||||||
|
&mut view.offset(((self.size * 17.).ceil() as u32, 0)),
|
||||||
|
black,
|
||||||
|
dim,
|
||||||
|
&format!("{:}", time.year()),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let cal_font = fonts.get_font(self.font, self.size * DATE_FACTOR);
|
||||||
let month_str = match time.month() {
|
let month_str = match time.month() {
|
||||||
1 => "January",
|
1 => "January",
|
||||||
2 => "February",
|
2 => "February",
|
||||||
@@ -57,62 +123,8 @@ impl Calendar {
|
|||||||
12 => "December",
|
12 => "December",
|
||||||
_ => panic!("impossible value"),
|
_ => panic!("impossible value"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
let mut y_off = 1;
|
|
||||||
// TODO: Fix offsets:
|
|
||||||
// - Headline font is not correctly accounted for
|
|
||||||
|
|
||||||
//
|
|
||||||
// Draw the week day
|
|
||||||
//
|
|
||||||
for idx in 1..8 {
|
|
||||||
let day_font = fonts.get_font(self.font, self.size);
|
|
||||||
let wk_chr = match idx {
|
|
||||||
1 => "MON",
|
|
||||||
2 => "TUE",
|
|
||||||
3 => "WED",
|
|
||||||
4 => "THU",
|
|
||||||
5 => "FRI",
|
|
||||||
6 => "SAT",
|
|
||||||
7 => "SUN",
|
|
||||||
_ => panic!("impossible value"),
|
|
||||||
};
|
|
||||||
|
|
||||||
day_font
|
|
||||||
.auto_draw_text(
|
|
||||||
&mut view
|
|
||||||
.offset((
|
|
||||||
idx * (self.size * 2.5).ceil() as u32 + (self.size / 5.).ceil() as u32,
|
|
||||||
y_off * (self.size * 1.8).ceil() as u32
|
|
||||||
+ (self.size * 1.).ceil() as u32,
|
|
||||||
))
|
|
||||||
.unwrap(),
|
|
||||||
&black,
|
|
||||||
&white,
|
|
||||||
&wk_chr,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Draw the month
|
|
||||||
//
|
|
||||||
if time.year() != orig.year() {
|
|
||||||
let year_font = fonts.get_font(self.font, self.size * 1.5);
|
|
||||||
year_font
|
|
||||||
.auto_draw_text(
|
|
||||||
&mut view.offset(((self.size * 17.).ceil() as u32, 0)).unwrap(),
|
|
||||||
&black,
|
|
||||||
&dim,
|
|
||||||
&format!("{:}", time.year()),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
let cal_font = fonts.get_font(self.font, self.size * 2.);
|
|
||||||
cal_font
|
cal_font
|
||||||
.auto_draw_text(&mut view, &black, &white, month_str)
|
.draw_text(&mut view, black, white, month_str)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut done = false;
|
let mut done = false;
|
||||||
@@ -133,16 +145,15 @@ impl Calendar {
|
|||||||
//
|
//
|
||||||
let wk = time.iso_week();
|
let wk = time.iso_week();
|
||||||
cal_font
|
cal_font
|
||||||
.auto_draw_text(
|
.draw_text(
|
||||||
&mut view
|
&mut view
|
||||||
.offset((
|
.offset((
|
||||||
0,
|
0,
|
||||||
y_off * (self.size * 1.8).ceil() as u32
|
y_off * (self.size * LINE_HEIGHT).ceil() as u32
|
||||||
+ (self.size * 2.).ceil() as u32,
|
+ (self.size * MONTH_FACTOR).ceil() as u32,
|
||||||
))
|
)),
|
||||||
.unwrap(),
|
black,
|
||||||
&black,
|
dimmer,
|
||||||
&dimmer,
|
|
||||||
&format!("{:02}", wk.week()),
|
&format!("{:02}", wk.week()),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -153,21 +164,21 @@ impl Calendar {
|
|||||||
//
|
//
|
||||||
while x_pos < 8 {
|
while x_pos < 8 {
|
||||||
let c = if time.day() == orig.day() && time.month() == orig.month() {
|
let c = if time.day() == orig.day() && time.month() == orig.month() {
|
||||||
Color::new(1.0, 1.0, 1.0, 1.0)
|
Color::WHITE
|
||||||
} else {
|
} else {
|
||||||
Color::new(0.5, 0.5, 0.5, 1.0)
|
Color::GREY50
|
||||||
};
|
};
|
||||||
|
|
||||||
cal_font
|
cal_font
|
||||||
.auto_draw_text(
|
.draw_text(
|
||||||
&mut view
|
&mut view
|
||||||
.offset((
|
.offset((
|
||||||
x_pos * (self.size * 2.5).ceil() as u32,
|
x_pos * (self.size * 2.5).ceil() as u32,
|
||||||
y_off * (self.size * 1.8).ceil() as u32 + (self.size * 2.) as u32,
|
y_off * (self.size * LINE_HEIGHT).ceil() as u32
|
||||||
))
|
+ (self.size * MONTH_FACTOR).ceil() as u32,
|
||||||
.unwrap(),
|
)),
|
||||||
&black,
|
black,
|
||||||
&c,
|
c,
|
||||||
&format!("{:02}", time.day()),
|
&format!("{:02}", time.day()),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -205,35 +216,33 @@ impl<'a> Widget for Calendar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn draw(&mut self, fonts: &mut FontMap, view: &mut BufferView) -> Geometry {
|
fn draw(&mut self, fonts: &mut FontMap, view: &mut BufferView) -> Geometry {
|
||||||
|
if self.shown_sections_y == 0 || self.shown_sections_x == 0 {
|
||||||
|
return Geometry {
|
||||||
|
x: self.geometry.x,
|
||||||
|
y: self.geometry.y,
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
let time = Local::now().naive_local().date();
|
let time = Local::now().naive_local().date();
|
||||||
|
|
||||||
let cal_height = (self.size * 16.25).ceil() as u32;
|
let cal_height = (self.size * 16.25).ceil() as u32;
|
||||||
let cal_width = (7. * self.size * 3. + self.size * 2.).ceil() as u32;
|
let cal_width = (7. * self.size * 2.5 + self.size * 2.).ceil() as u32;
|
||||||
let cal_pad = (3. * self.size).ceil() as u32;
|
let cal_pad = (3. * self.size).ceil() as u32;
|
||||||
let sections_y = if self.sections_y > 0 {
|
|
||||||
self.sections_y as u32
|
|
||||||
} else {
|
|
||||||
self.geometry.height / cal_height
|
|
||||||
};
|
|
||||||
let sections_x = if self.sections_x > 0 {
|
|
||||||
self.sections_x as u32
|
|
||||||
} else {
|
|
||||||
self.geometry.width / (cal_height + cal_pad)
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut t = time.with_day(1).unwrap();
|
let mut t = time.with_day(1).unwrap();
|
||||||
let cals = sections_y * sections_x - 1;
|
let cals = self.shown_sections_y * self.shown_sections_x;
|
||||||
if cals >=3 {
|
if cals >= 3 {
|
||||||
t = t.pred_opt().unwrap().with_day(1).unwrap();
|
t = t.pred_opt().unwrap().with_day(1).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
for ydx in 0..sections_y {
|
for ydx in 0..self.shown_sections_y {
|
||||||
for idx in 0..sections_x {
|
for idx in 0..self.shown_sections_x {
|
||||||
self.draw_month(
|
self.draw_month(
|
||||||
fonts,
|
fonts,
|
||||||
&mut view
|
&mut view
|
||||||
.offset(((cal_width + cal_pad) * idx, (cal_height) * ydx))
|
.offset(((cal_width + cal_pad) * idx, (cal_height) * ydx)),
|
||||||
.unwrap(),
|
|
||||||
time,
|
time,
|
||||||
t,
|
t,
|
||||||
);
|
);
|
||||||
@@ -249,17 +258,26 @@ impl<'a> Widget for Calendar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn geometry_update(&mut self, _fonts: &mut FontMap, geometry: &Geometry) -> Geometry {
|
fn geometry_update(&mut self, _fonts: &mut FontMap, geometry: &Geometry) -> Geometry {
|
||||||
let cal_width = (7. * self.size * 3. + self.size * 2.).ceil() as u32;
|
let cal_width = 7 * (self.size * 2.5).ceil() as u32 + (self.size * 2.).ceil() as u32;
|
||||||
let cal_height = (self.size * 16.25).ceil() as u32; // TODO: Calculate from font sizes
|
let cal_height = (self.size * MONTH_FACTOR).ceil() as u32
|
||||||
|
+ (self.size * LINE_HEIGHT * 8.).ceil() as u32;
|
||||||
let cal_pad = (self.size * 3.).ceil() as u32;
|
let cal_pad = (self.size * 3.).ceil() as u32;
|
||||||
let width = if self.sections_x > 0 {
|
|
||||||
|
let possible_sections_x = geometry.width / (cal_width + cal_pad);
|
||||||
|
let possible_sections_y = geometry.height / cal_height;
|
||||||
|
|
||||||
|
let width = if self.sections_x > 0 && self.sections_x < possible_sections_x as i32 {
|
||||||
|
self.shown_sections_x = self.sections_x as u32;
|
||||||
cal_width * self.sections_x as u32 + cal_pad * (self.sections_x as u32 - 1)
|
cal_width * self.sections_x as u32 + cal_pad * (self.sections_x as u32 - 1)
|
||||||
} else {
|
} else {
|
||||||
(geometry.width / (cal_width + cal_pad)) * (cal_width + cal_pad)
|
self.shown_sections_x = possible_sections_x;
|
||||||
|
(geometry.width / (cal_width + cal_pad)) * (cal_width + cal_pad)
|
||||||
};
|
};
|
||||||
let height = if self.sections_y > 0 {
|
let height = if self.sections_y > 0 && self.sections_y < possible_sections_y as i32 {
|
||||||
|
self.shown_sections_y = self.sections_y as u32;
|
||||||
cal_height * self.sections_y as u32
|
cal_height * self.sections_y as u32
|
||||||
} else {
|
} else {
|
||||||
|
self.shown_sections_y = possible_sections_y;
|
||||||
(geometry.height / cal_height) * cal_height
|
(geometry.height / cal_height) * cal_height
|
||||||
};
|
};
|
||||||
self.geometry = Geometry {
|
self.geometry = Geometry {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use crate::{
|
|||||||
buffer::BufferView,
|
buffer::BufferView,
|
||||||
color::Color,
|
color::Color,
|
||||||
fonts::FontMap,
|
fonts::FontMap,
|
||||||
state::Event,
|
event::Event,
|
||||||
widgets::{Geometry, Widget},
|
widgets::{Geometry, Widget},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -20,7 +20,8 @@ pub struct Clock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Clock {
|
impl<'a> Clock {
|
||||||
pub fn new(font: &'static str, size: f32) -> Clock {
|
pub fn new(fm: &mut FontMap, font: &'static str, size: f32) -> Clock {
|
||||||
|
fm.queue_font(font, size, "0123456789: ");
|
||||||
Clock {
|
Clock {
|
||||||
font,
|
font,
|
||||||
size,
|
size,
|
||||||
@@ -52,16 +53,16 @@ impl<'a> Widget for Clock {
|
|||||||
|
|
||||||
fn draw(&mut self, fonts: &mut FontMap, view: &mut BufferView) -> Geometry {
|
fn draw(&mut self, fonts: &mut FontMap, view: &mut BufferView) -> Geometry {
|
||||||
let time = Local::now().naive_local();
|
let time = Local::now().naive_local();
|
||||||
let fg = Color::new(1., 1., 1., 1.);
|
let fg = Color::WHITE;
|
||||||
let bg = Color::new(0., 0., 0., 1.);
|
let bg = Color::BLACK;
|
||||||
|
|
||||||
let digit = self.digit_width;
|
let digit = self.digit_width;
|
||||||
let colon = self.colon_width;
|
let colon = self.colon_width;
|
||||||
let font = fonts.get_font(self.font, self.size);
|
let font = fonts.get_font(self.font, self.size);
|
||||||
font.draw_text_fixed_width(
|
font.draw_text_fixed_width(
|
||||||
view,
|
view,
|
||||||
&bg,
|
bg,
|
||||||
&fg,
|
fg,
|
||||||
&[digit, digit, colon, digit, digit],
|
&[digit, digit, colon, digit, digit],
|
||||||
&format!("{:02}:{:02}", time.hour(), time.minute()),
|
&format!("{:02}:{:02}", time.hour(), time.minute()),
|
||||||
)
|
)
|
||||||
|
|||||||
+12
-11
@@ -4,7 +4,7 @@ use crate::{
|
|||||||
buffer::BufferView,
|
buffer::BufferView,
|
||||||
color::Color,
|
color::Color,
|
||||||
fonts::FontMap,
|
fonts::FontMap,
|
||||||
state::Event,
|
event::Event,
|
||||||
widgets::{Geometry, Widget},
|
widgets::{Geometry, Widget},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -18,7 +18,8 @@ pub struct Date {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Date {
|
impl Date {
|
||||||
pub fn new(font: &'static str, size: f32) -> Date {
|
pub fn new(fm: &mut FontMap, font: &'static str, size: f32) -> Date {
|
||||||
|
fm.queue_font(font, size, "0123456789/, adehinortuFMSTW");
|
||||||
Date {
|
Date {
|
||||||
font,
|
font,
|
||||||
size,
|
size,
|
||||||
@@ -48,14 +49,13 @@ impl<'a> Widget for Date {
|
|||||||
|
|
||||||
fn draw(&mut self, fonts: &mut FontMap, view: &mut BufferView) -> Geometry {
|
fn draw(&mut self, fonts: &mut FontMap, view: &mut BufferView) -> Geometry {
|
||||||
let time = Local::now().naive_local();
|
let time = Local::now().naive_local();
|
||||||
let fg = Color::new(1., 1., 1., 1.);
|
let fg = Color::WHITE;
|
||||||
let bg = Color::new(0., 0., 0., 1.);
|
let bg = Color::BLACK;
|
||||||
let mut date_line = view.offset((0, 8)).unwrap();
|
|
||||||
let font = fonts.get_font(self.font, self.size);
|
let font = fonts.get_font(self.font, self.size);
|
||||||
font.auto_draw_text(
|
font.draw_text(
|
||||||
&mut date_line,
|
view,
|
||||||
&bg,
|
bg,
|
||||||
&fg,
|
fg,
|
||||||
&format!(
|
&format!(
|
||||||
"{}, {:02}/{:02}/{:4}",
|
"{}, {:02}/{:02}/{:4}",
|
||||||
time.weekday(),
|
time.weekday(),
|
||||||
@@ -69,13 +69,14 @@ impl<'a> Widget for Date {
|
|||||||
self.geometry
|
self.geometry
|
||||||
}
|
}
|
||||||
|
|
||||||
fn geometry_update(&mut self, _fonts: &mut FontMap, geometry: &Geometry) -> Geometry {
|
fn geometry_update(&mut self, fonts: &mut FontMap, geometry: &Geometry) -> Geometry {
|
||||||
let width = (3. + 2. + 2. + 2. + 4.) * self.size / 2.;
|
let width = (3. + 2. + 2. + 2. + 4.) * self.size / 2.;
|
||||||
|
let font = fonts.get_font(self.font, self.size);
|
||||||
self.geometry = Geometry {
|
self.geometry = Geometry {
|
||||||
x: geometry.x,
|
x: geometry.x,
|
||||||
y: geometry.y,
|
y: geometry.y,
|
||||||
width: width.ceil() as u32,
|
width: width.ceil() as u32,
|
||||||
height: self.size.ceil() as u32,
|
height: font.height().ceil() as u32,
|
||||||
};
|
};
|
||||||
self.geometry
|
self.geometry
|
||||||
}
|
}
|
||||||
|
|||||||
+71
-38
@@ -12,7 +12,7 @@ use crate::{
|
|||||||
color::Color,
|
color::Color,
|
||||||
fonts::FontMap,
|
fonts::FontMap,
|
||||||
keyboard::{keysyms, KeyEvent},
|
keyboard::{keysyms, KeyEvent},
|
||||||
state::Event,
|
event::{Event, Events, PointerEvent, PointerButton},
|
||||||
utils::desktop::{load_desktop_files, Desktop},
|
utils::desktop::{load_desktop_files, Desktop},
|
||||||
widgets::{Geometry, Widget},
|
widgets::{Geometry, Widget},
|
||||||
};
|
};
|
||||||
@@ -205,14 +205,20 @@ struct Launcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Launcher {
|
impl Launcher {
|
||||||
fn new() -> Launcher {
|
fn new(events: Arc<Mutex<Events>>) -> Launcher {
|
||||||
let options = Arc::new(Mutex::new(Vec::new()));
|
let options = Arc::new(Mutex::new(Vec::new()));
|
||||||
{
|
{
|
||||||
let options = Arc::clone(&options);
|
let options = Arc::clone(&options);
|
||||||
thread::spawn(move || {
|
thread::Builder::new()
|
||||||
let mut options = options.lock().unwrap();
|
.name("desktopini".to_string())
|
||||||
*options = load_desktop_files();
|
.spawn(move || {
|
||||||
});
|
let mut options = options.lock().unwrap();
|
||||||
|
*options = load_desktop_files();
|
||||||
|
drop(options);
|
||||||
|
let mut events = events.lock().unwrap();
|
||||||
|
events.add_event(Event::LauncherUpdate);
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
Launcher {
|
Launcher {
|
||||||
@@ -280,31 +286,31 @@ impl InterfaceWidget for Launcher {
|
|||||||
fonts: &mut FontMap,
|
fonts: &mut FontMap,
|
||||||
view: &mut BufferView,
|
view: &mut BufferView,
|
||||||
) -> Geometry {
|
) -> Geometry {
|
||||||
let fg = Color::new(1., 1., 1., 1.);
|
let fg = Color::WHITE;
|
||||||
let bg = Color::new(0., 0., 0., 1.);
|
let bg = Color::BLACK;
|
||||||
|
|
||||||
let line_height = intf.size.ceil() as u32;
|
let line_height = intf.size.ceil() as u32;
|
||||||
|
|
||||||
// Draw line
|
// Draw line
|
||||||
let mut prompt_offset = intf.geometry.height - line_height;
|
let mut prompt_offset = intf.geometry.height - line_height;
|
||||||
let mut prompt_line = view.offset((0, prompt_offset)).unwrap();
|
let mut prompt_line = view.offset((0, prompt_offset));
|
||||||
|
|
||||||
let font = fonts.get_font(intf.font, intf.size);
|
let font = fonts.get_font(intf.font, intf.size);
|
||||||
let mut x_max = font
|
let mut x_max = font
|
||||||
.auto_draw_text_with_cursor(
|
.auto_draw_text_with_cursor(
|
||||||
&mut prompt_line,
|
&mut prompt_line,
|
||||||
&bg,
|
bg,
|
||||||
&fg,
|
fg,
|
||||||
&format!(" {}", &intf.prompt.input),
|
&format!(" {}", &intf.prompt.input),
|
||||||
intf.prompt.cursor + 3,
|
intf.prompt.cursor + 3,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
font.auto_draw_text(&mut prompt_line, &bg, &fg, ">")
|
font.auto_draw_text(&mut prompt_line, bg, fg, ">")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Draw entries
|
// Draw entries
|
||||||
let dimfg = Color::new(0.5, 0.5, 0.5, 1.0);
|
let dimfg = Color::GREY50;
|
||||||
prompt_offset -= 16;
|
prompt_offset -= 16;
|
||||||
|
|
||||||
for (idx, m) in self.matches.iter().enumerate() {
|
for (idx, m) in self.matches.iter().enumerate() {
|
||||||
@@ -312,7 +318,7 @@ impl InterfaceWidget for Launcher {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
prompt_offset -= line_height;
|
prompt_offset -= line_height;
|
||||||
let mut line = view.offset((0, prompt_offset)).unwrap();
|
let mut line = view.offset((0, prompt_offset));
|
||||||
|
|
||||||
if idx == intf.selection {
|
if idx == intf.selection {
|
||||||
let fuzzy_matcher = SkimMatcherV2::default();
|
let fuzzy_matcher = SkimMatcherV2::default();
|
||||||
@@ -323,20 +329,20 @@ impl InterfaceWidget for Launcher {
|
|||||||
let mut colors = Vec::with_capacity(m.name.len());
|
let mut colors = Vec::with_capacity(m.name.len());
|
||||||
for pos in 0..m.name.len() {
|
for pos in 0..m.name.len() {
|
||||||
if indices.contains(&pos) {
|
if indices.contains(&pos) {
|
||||||
colors.push(Color::new(1.0, 0.65, 0., 1.0));
|
colors.push(Color::LIGHTORANGE);
|
||||||
} else {
|
} else {
|
||||||
colors.push(Color::new(0.75, 0.75, 0.75, 1.0));
|
colors.push(Color::GREY75);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
x_max = max(
|
x_max = max(
|
||||||
x_max,
|
x_max,
|
||||||
font.auto_draw_text_individual_colors(&mut line, &bg, &colors, &m.name)
|
font.auto_draw_text_individual_colors(&mut line, bg, &colors, &m.name)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
x_max = max(
|
x_max = max(
|
||||||
x_max,
|
x_max,
|
||||||
font.auto_draw_text(&mut line, &bg, &dimfg, &m.name)
|
font.auto_draw_text(&mut line, bg, dimfg, &m.name)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -379,27 +385,27 @@ impl InterfaceWidget for Shell {
|
|||||||
fonts: &mut FontMap,
|
fonts: &mut FontMap,
|
||||||
view: &mut BufferView,
|
view: &mut BufferView,
|
||||||
) -> Geometry {
|
) -> Geometry {
|
||||||
let fg = Color::new(1., 1., 1., 1.);
|
let fg = Color::WHITE;
|
||||||
let bg = Color::new(0., 0., 0., 1.);
|
let bg = Color::BLACK;
|
||||||
|
|
||||||
let line_height = intf.size.ceil() as u32;
|
let line_height = intf.size.ceil() as u32;
|
||||||
|
|
||||||
// Draw line
|
// Draw line
|
||||||
let prompt_offset = intf.geometry.height - line_height;
|
let prompt_offset = intf.geometry.height - line_height;
|
||||||
let mut prompt_line = view.offset((0, prompt_offset)).unwrap();
|
let mut prompt_line = view.offset((0, prompt_offset));
|
||||||
|
|
||||||
// Draw prompt
|
// Draw prompt
|
||||||
let font = fonts.get_font(intf.font, intf.size);
|
let font = fonts.get_font(intf.font, intf.size);
|
||||||
let x_max = font
|
let x_max = font
|
||||||
.auto_draw_text_with_cursor(
|
.auto_draw_text_with_cursor(
|
||||||
&mut prompt_line,
|
&mut prompt_line,
|
||||||
&bg,
|
bg,
|
||||||
&fg,
|
fg,
|
||||||
&format!(" {}", &intf.prompt.input),
|
&format!(" {}", &intf.prompt.input),
|
||||||
intf.prompt.cursor + 3,
|
intf.prompt.cursor + 3,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
font.auto_draw_text(&mut prompt_line, &bg, &Color::new(1., 0.75, 0.5, 1.), "!")
|
font.auto_draw_text(&mut prompt_line, bg, Color::BUFF, "!")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
Geometry {
|
Geometry {
|
||||||
@@ -440,45 +446,45 @@ impl InterfaceWidget for Calc {
|
|||||||
fonts: &mut FontMap,
|
fonts: &mut FontMap,
|
||||||
view: &mut BufferView,
|
view: &mut BufferView,
|
||||||
) -> Geometry {
|
) -> Geometry {
|
||||||
let fg = Color::new(1., 1., 1., 1.);
|
let fg = Color::WHITE;
|
||||||
let bg = Color::new(0., 0., 0., 1.);
|
let bg = Color::BLACK;
|
||||||
|
|
||||||
let line_height = intf.size.ceil() as u32;
|
let line_height = intf.size.ceil() as u32;
|
||||||
|
|
||||||
// Draw line
|
// Draw line
|
||||||
let mut prompt_offset = intf.geometry.height - (line_height);
|
let mut prompt_offset = intf.geometry.height - (line_height);
|
||||||
let mut prompt_line = view.offset((0, prompt_offset)).unwrap();
|
let mut prompt_line = view.offset((0, prompt_offset));
|
||||||
|
|
||||||
// Draw prompt
|
// Draw prompt
|
||||||
let font = fonts.get_font(intf.font, intf.size);
|
let font = fonts.get_font(intf.font, intf.size);
|
||||||
let res_off = font
|
let res_off = font
|
||||||
.auto_draw_text_with_cursor(
|
.auto_draw_text_with_cursor(
|
||||||
&mut prompt_line,
|
&mut prompt_line,
|
||||||
&bg,
|
bg,
|
||||||
&fg,
|
fg,
|
||||||
&format!(" {} ", &intf.prompt.input),
|
&format!(" {} ", &intf.prompt.input),
|
||||||
intf.prompt.cursor + 3,
|
intf.prompt.cursor + 3,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
font.auto_draw_text(&mut prompt_line, &bg, &Color::new(1., 0.75, 0.5, 1.), "=")
|
font.auto_draw_text(&mut prompt_line, bg, Color::BUFF, "=")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
if let Some(res) = &self.result {
|
if let Some(res) = &self.result {
|
||||||
let resfg = Color::new(1.0, 0.65, 0., 1.0);
|
let resfg = Color::LIGHTORANGE;
|
||||||
let mut result_line = view.offset((res_off.0, prompt_offset)).unwrap();
|
let mut result_line = view.offset((res_off.0, prompt_offset));
|
||||||
font.auto_draw_text(&mut result_line, &bg, &resfg, &format!(" = {}", &res))
|
font.auto_draw_text(&mut result_line, bg, resfg, &format!(" = {}", &res))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
for m in self.old.iter().rev() {
|
for m in self.old.iter().rev() {
|
||||||
let dimfg = Color::new(0.5, 0.5, 0.5, 1.0);
|
let dimfg = Color::GREY50;
|
||||||
if prompt_offset < line_height {
|
if prompt_offset < line_height {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
prompt_offset -= line_height;
|
prompt_offset -= line_height;
|
||||||
let mut result_line = view.offset((0, prompt_offset)).unwrap();
|
let mut result_line = view.offset((0, prompt_offset));
|
||||||
font.auto_draw_text(&mut result_line, &bg, &dimfg, &m)
|
font.auto_draw_text(&mut result_line, bg, dimfg, &m)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -512,9 +518,14 @@ pub struct Interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Interface {
|
impl Interface {
|
||||||
pub fn new(font: &'static str, size: f32) -> Interface {
|
pub fn new(events: Arc<Mutex<Events>>, fm: &mut FontMap, font: &'static str, size: f32) -> Interface {
|
||||||
|
fm.queue_font(
|
||||||
|
font, size,
|
||||||
|
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 >=!,.-/()",
|
||||||
|
);
|
||||||
|
|
||||||
Interface {
|
Interface {
|
||||||
launcher: Launcher::new(),
|
launcher: Launcher::new(events),
|
||||||
shell: Shell {},
|
shell: Shell {},
|
||||||
calc: Calc {
|
calc: Calc {
|
||||||
old: Vec::new(),
|
old: Vec::new(),
|
||||||
@@ -531,6 +542,23 @@ impl Interface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn pointer_input(&mut self, event: &PointerEvent) {
|
||||||
|
if let PointerButton::Left = event.button {
|
||||||
|
let line_height = self.inner.size.ceil() as u32;
|
||||||
|
let height = self.inner.geometry.height - line_height - 16;
|
||||||
|
let lines = height / line_height;
|
||||||
|
|
||||||
|
let offset = height % line_height;
|
||||||
|
let pos = if event.pos.1 >= offset {
|
||||||
|
event.pos.1 - offset
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
self.inner.selection = (lines - pos / line_height - 1) as usize;
|
||||||
|
self.inner.dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn keyboard_input(&mut self, event: &KeyEvent) {
|
fn keyboard_input(&mut self, event: &KeyEvent) {
|
||||||
if event.state != WEnum::Value(wl_keyboard::KeyState::Pressed) {
|
if event.state != WEnum::Value(wl_keyboard::KeyState::Pressed) {
|
||||||
return;
|
return;
|
||||||
@@ -616,6 +644,11 @@ impl Widget for Interface {
|
|||||||
fn event(&mut self, event: &Event) {
|
fn event(&mut self, event: &Event) {
|
||||||
match event {
|
match event {
|
||||||
Event::KeyEvent(e) => self.keyboard_input(e),
|
Event::KeyEvent(e) => self.keyboard_input(e),
|
||||||
|
Event::PointerEvent(e) => self.pointer_input(e),
|
||||||
|
Event::LauncherUpdate => {
|
||||||
|
self.inner.dirty = true;
|
||||||
|
self.launcher.update(&self.inner);
|
||||||
|
},
|
||||||
Event::TokenUpdate(t) => self.launcher.next_token = Some(t.to_string()),
|
Event::TokenUpdate(t) => self.launcher.next_token = Some(t.to_string()),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,174 @@
|
|||||||
|
use std::cmp::max;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
fonts::FontMap,
|
||||||
|
state::State,
|
||||||
|
widgets::{Geometry},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub trait Layout {
|
||||||
|
fn geometry_update(
|
||||||
|
&self,
|
||||||
|
fonts: &mut FontMap,
|
||||||
|
geometry: &Geometry,
|
||||||
|
state: &mut State,
|
||||||
|
) -> Geometry;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HorizontalLayout {
|
||||||
|
pub widgets: Vec<Box<dyn Layout>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HorizontalLayout {
|
||||||
|
pub fn new(widgets: Vec<Box<dyn Layout>>) -> Box<dyn Layout> {
|
||||||
|
Box::new(HorizontalLayout { widgets })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Layout for HorizontalLayout {
|
||||||
|
fn geometry_update(
|
||||||
|
&self,
|
||||||
|
fonts: &mut FontMap,
|
||||||
|
geometry: &Geometry,
|
||||||
|
state: &mut State,
|
||||||
|
) -> Geometry {
|
||||||
|
let mut geo = geometry.clone();
|
||||||
|
let mut max_width = 0;
|
||||||
|
let mut max_height = 0;
|
||||||
|
for w in self.widgets.iter() {
|
||||||
|
let result = w.geometry_update(fonts, &geo, state);
|
||||||
|
geo.x = result.x + result.width;
|
||||||
|
geo.width -= result.width;
|
||||||
|
max_width += result.width;
|
||||||
|
max_height = max(result.height, max_height);
|
||||||
|
}
|
||||||
|
geo.width = max_width;
|
||||||
|
geo.height = max_height;
|
||||||
|
geo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct VerticalLayout {
|
||||||
|
pub widgets: Vec<Box<dyn Layout>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VerticalLayout {
|
||||||
|
pub fn new(widgets: Vec<Box<dyn Layout>>) -> Box<dyn Layout> {
|
||||||
|
Box::new(VerticalLayout { widgets })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Layout for VerticalLayout {
|
||||||
|
fn geometry_update(
|
||||||
|
&self,
|
||||||
|
fonts: &mut FontMap,
|
||||||
|
geometry: &Geometry,
|
||||||
|
state: &mut State,
|
||||||
|
) -> Geometry {
|
||||||
|
let mut geo = geometry.clone();
|
||||||
|
let mut max_width = 0;
|
||||||
|
let mut max_height = 0;
|
||||||
|
for w in self.widgets.iter() {
|
||||||
|
let result = w.geometry_update(fonts, &geo, state);
|
||||||
|
geo.y = result.y + result.height;
|
||||||
|
geo.height -= result.height;
|
||||||
|
max_width = max(result.width, max_width);
|
||||||
|
max_height += result.height;
|
||||||
|
}
|
||||||
|
geo.width = max_width;
|
||||||
|
geo.height = max_height;
|
||||||
|
geo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait WidgetUpdater {
|
||||||
|
fn geometry_update(&mut self, idx: usize, fonts: &mut FontMap, geometry: &Geometry)
|
||||||
|
-> Geometry;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct IndexedLayout {
|
||||||
|
pub widget_idx: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexedLayout {
|
||||||
|
pub fn new(widget_idx: usize) -> Box<dyn Layout> {
|
||||||
|
Box::new(IndexedLayout { widget_idx })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Layout for IndexedLayout {
|
||||||
|
fn geometry_update(
|
||||||
|
&self,
|
||||||
|
fonts: &mut FontMap,
|
||||||
|
geometry: &Geometry,
|
||||||
|
state: &mut State,
|
||||||
|
) -> Geometry {
|
||||||
|
state.geometry_update(self.widget_idx, fonts, geometry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Margin {
|
||||||
|
pub widget: Box<dyn Layout>,
|
||||||
|
pub margin: (u32, u32, u32, u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Margin {
|
||||||
|
pub fn new(widget: Box<dyn Layout>, margin: (u32, u32, u32, u32)) -> Box<dyn Layout> {
|
||||||
|
Box::new(Margin { widget, margin })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Layout for Margin {
|
||||||
|
fn geometry_update(
|
||||||
|
&self,
|
||||||
|
fonts: &mut FontMap,
|
||||||
|
geometry: &Geometry,
|
||||||
|
state: &mut State,
|
||||||
|
) -> Geometry {
|
||||||
|
let geo = Geometry {
|
||||||
|
x: geometry.x + self.margin.0,
|
||||||
|
y: geometry.y + self.margin.1,
|
||||||
|
width: geometry.width - self.margin.0 - self.margin.2,
|
||||||
|
height: geometry.height - self.margin.1 - self.margin.3,
|
||||||
|
};
|
||||||
|
let out = self.widget.geometry_update(fonts, &geo, state);
|
||||||
|
Geometry {
|
||||||
|
x: out.x - self.margin.0,
|
||||||
|
y: out.y - self.margin.1,
|
||||||
|
width: out.width + self.margin.0 + self.margin.2,
|
||||||
|
height: out.height + self.margin.1 + self.margin.3,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct InvertedHorizontalLayout {
|
||||||
|
pub widgets: Vec<Box<dyn Layout>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InvertedHorizontalLayout {
|
||||||
|
pub fn new(widgets: Vec<Box<dyn Layout>>) -> Box<dyn Layout> {
|
||||||
|
Box::new(InvertedHorizontalLayout { widgets })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Layout for InvertedHorizontalLayout {
|
||||||
|
fn geometry_update(
|
||||||
|
&self,
|
||||||
|
fonts: &mut FontMap,
|
||||||
|
geometry: &Geometry,
|
||||||
|
state: &mut State,
|
||||||
|
) -> Geometry {
|
||||||
|
let mut geo = geometry.clone();
|
||||||
|
let mut max_height = 0;
|
||||||
|
for w in self.widgets.iter() {
|
||||||
|
let mut temp_geo = geo.clone();
|
||||||
|
let temp_result = w.geometry_update(fonts, &temp_geo, state);
|
||||||
|
temp_geo.x = geo.x + (geo.width - temp_result.width);
|
||||||
|
let result = w.geometry_update(fonts, &temp_geo, state);
|
||||||
|
geo.width -= result.width;
|
||||||
|
max_height = max(result.height, max_height);
|
||||||
|
}
|
||||||
|
geo.height = max_height;
|
||||||
|
geo
|
||||||
|
}
|
||||||
|
}
|
||||||
+8
-6
@@ -7,14 +7,17 @@ use crate::{
|
|||||||
widgets::{Geometry, Widget},
|
widgets::{Geometry, Widget},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct Line {
|
pub struct Line {
|
||||||
geometry: Geometry,
|
geometry: Geometry,
|
||||||
|
thickness: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Line {
|
impl Line {
|
||||||
pub fn new() -> Line {
|
pub fn new(thickness: u32) -> Line {
|
||||||
Default::default()
|
Line{
|
||||||
|
geometry: Default::default(),
|
||||||
|
thickness,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,16 +26,15 @@ impl Widget for Line {
|
|||||||
self.geometry
|
self.geometry
|
||||||
}
|
}
|
||||||
fn draw(&mut self, _fonts: &mut FontMap, view: &mut BufferView) -> Geometry {
|
fn draw(&mut self, _fonts: &mut FontMap, view: &mut BufferView) -> Geometry {
|
||||||
view.memset(&Color::new(1., 1., 1., 1.));
|
view.memset(Color::WHITE);
|
||||||
self.geometry
|
self.geometry
|
||||||
}
|
}
|
||||||
|
|
||||||
fn geometry_update(&mut self, _fonts: &mut FontMap, geometry: &Geometry) -> Geometry {
|
fn geometry_update(&mut self, _fonts: &mut FontMap, geometry: &Geometry) -> Geometry {
|
||||||
self.geometry = Geometry {
|
self.geometry = Geometry {
|
||||||
x: geometry.x,
|
x: geometry.x,
|
||||||
y: geometry.y,
|
y: geometry.y,
|
||||||
width: geometry.width,
|
width: geometry.width,
|
||||||
height: 1,
|
height: self.thickness,
|
||||||
};
|
};
|
||||||
self.geometry
|
self.geometry
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-4
@@ -1,3 +1,4 @@
|
|||||||
|
mod audio;
|
||||||
mod backlight;
|
mod backlight;
|
||||||
mod bar_widget;
|
mod bar_widget;
|
||||||
mod battery;
|
mod battery;
|
||||||
@@ -7,7 +8,9 @@ mod date;
|
|||||||
mod launcher;
|
mod launcher;
|
||||||
mod line;
|
mod line;
|
||||||
mod widget;
|
mod widget;
|
||||||
|
mod layout;
|
||||||
|
|
||||||
|
pub use audio::Audio;
|
||||||
pub use backlight::Backlight;
|
pub use backlight::Backlight;
|
||||||
pub use battery::Battery;
|
pub use battery::Battery;
|
||||||
pub use calendar::Calendar;
|
pub use calendar::Calendar;
|
||||||
@@ -15,7 +18,5 @@ pub use clock::Clock;
|
|||||||
pub use date::Date;
|
pub use date::Date;
|
||||||
pub use launcher::Interface;
|
pub use launcher::Interface;
|
||||||
pub use line::Line;
|
pub use line::Line;
|
||||||
pub use widget::{
|
pub use layout::{VerticalLayout, HorizontalLayout, IndexedLayout, InvertedHorizontalLayout, Layout, Margin, WidgetUpdater};
|
||||||
Geometry, HorizontalLayout, IndexedLayout, InvertedHorizontalLayout, Layout, Margin,
|
pub use widget::{Geometry, Widget};
|
||||||
VerticalLayout, Widget, WidgetUpdater,
|
|
||||||
};
|
|
||||||
|
|||||||
+6
-167
@@ -6,7 +6,7 @@ use std::{
|
|||||||
use crate::{
|
use crate::{
|
||||||
buffer::BufferView,
|
buffer::BufferView,
|
||||||
fonts::FontMap,
|
fonts::FontMap,
|
||||||
state::{Event, State},
|
event::Event,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Copy)]
|
#[derive(Debug, Default, Clone, Copy)]
|
||||||
@@ -47,6 +47,11 @@ impl Geometry {
|
|||||||
height: max(self.height + self.y, other.height + other.height) - y,
|
height: max(self.height + self.y, other.height + other.height) - y,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn contains(&self, position: (u32, u32)) -> bool {
|
||||||
|
position.0 >= self.x && position.0 < self.x + self.width &&
|
||||||
|
position.1 >= self.y && position.1 < self.y + self.height
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Widget {
|
pub trait Widget {
|
||||||
@@ -59,169 +64,3 @@ pub trait Widget {
|
|||||||
fn event(&mut self, _event: &Event) {}
|
fn event(&mut self, _event: &Event) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Layout {
|
|
||||||
fn geometry_update(
|
|
||||||
&self,
|
|
||||||
fonts: &mut FontMap,
|
|
||||||
geometry: &Geometry,
|
|
||||||
state: &mut State,
|
|
||||||
) -> Geometry;
|
|
||||||
}
|
|
||||||
pub struct HorizontalLayout {
|
|
||||||
pub widgets: Vec<Box<dyn Layout>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HorizontalLayout {
|
|
||||||
pub fn new(widgets: Vec<Box<dyn Layout>>) -> Box<dyn Layout> {
|
|
||||||
Box::new(HorizontalLayout { widgets })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Layout for HorizontalLayout {
|
|
||||||
fn geometry_update(
|
|
||||||
&self,
|
|
||||||
fonts: &mut FontMap,
|
|
||||||
geometry: &Geometry,
|
|
||||||
state: &mut State,
|
|
||||||
) -> Geometry {
|
|
||||||
let mut geo = geometry.clone();
|
|
||||||
let mut max_width = 0;
|
|
||||||
let mut max_height = 0;
|
|
||||||
for w in self.widgets.iter() {
|
|
||||||
let result = w.geometry_update(fonts, &geo, state);
|
|
||||||
geo.x = result.x + result.width;
|
|
||||||
geo.width -= result.width;
|
|
||||||
max_width += result.width;
|
|
||||||
max_height = max(result.height, max_height);
|
|
||||||
}
|
|
||||||
geo.width = max_width;
|
|
||||||
geo.height = max_height;
|
|
||||||
geo
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct VerticalLayout {
|
|
||||||
pub widgets: Vec<Box<dyn Layout>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VerticalLayout {
|
|
||||||
pub fn new(widgets: Vec<Box<dyn Layout>>) -> Box<dyn Layout> {
|
|
||||||
Box::new(VerticalLayout { widgets })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Layout for VerticalLayout {
|
|
||||||
fn geometry_update(
|
|
||||||
&self,
|
|
||||||
fonts: &mut FontMap,
|
|
||||||
geometry: &Geometry,
|
|
||||||
state: &mut State,
|
|
||||||
) -> Geometry {
|
|
||||||
let mut geo = geometry.clone();
|
|
||||||
let mut max_width = 0;
|
|
||||||
let mut max_height = 0;
|
|
||||||
for w in self.widgets.iter() {
|
|
||||||
let result = w.geometry_update(fonts, &geo, state);
|
|
||||||
geo.y = result.y + result.height;
|
|
||||||
geo.height -= result.height;
|
|
||||||
max_width = max(result.width, max_width);
|
|
||||||
max_height += result.height;
|
|
||||||
}
|
|
||||||
geo.width = max_width;
|
|
||||||
geo.height = max_height;
|
|
||||||
geo
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait WidgetUpdater {
|
|
||||||
fn geometry_update(&mut self, idx: usize, fonts: &mut FontMap, geometry: &Geometry)
|
|
||||||
-> Geometry;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct IndexedLayout {
|
|
||||||
pub widget_idx: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IndexedLayout {
|
|
||||||
pub fn new(widget_idx: usize) -> Box<dyn Layout> {
|
|
||||||
Box::new(IndexedLayout { widget_idx })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Layout for IndexedLayout {
|
|
||||||
fn geometry_update(
|
|
||||||
&self,
|
|
||||||
fonts: &mut FontMap,
|
|
||||||
geometry: &Geometry,
|
|
||||||
state: &mut State,
|
|
||||||
) -> Geometry {
|
|
||||||
state.geometry_update(self.widget_idx, fonts, geometry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Margin {
|
|
||||||
pub widget: Box<dyn Layout>,
|
|
||||||
pub margin: (u32, u32, u32, u32),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Margin {
|
|
||||||
pub fn new(widget: Box<dyn Layout>, margin: (u32, u32, u32, u32)) -> Box<dyn Layout> {
|
|
||||||
Box::new(Margin { widget, margin })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Layout for Margin {
|
|
||||||
fn geometry_update(
|
|
||||||
&self,
|
|
||||||
fonts: &mut FontMap,
|
|
||||||
geometry: &Geometry,
|
|
||||||
state: &mut State,
|
|
||||||
) -> Geometry {
|
|
||||||
let geo = Geometry {
|
|
||||||
x: geometry.x + self.margin.0,
|
|
||||||
y: geometry.y + self.margin.1,
|
|
||||||
width: geometry.width - self.margin.0 - self.margin.2,
|
|
||||||
height: geometry.height - self.margin.1 - self.margin.3,
|
|
||||||
};
|
|
||||||
|
|
||||||
let out = self.widget.geometry_update(fonts, &geo, state);
|
|
||||||
Geometry {
|
|
||||||
x: out.x - self.margin.0,
|
|
||||||
y: out.y - self.margin.1,
|
|
||||||
width: out.width + self.margin.0 + self.margin.2,
|
|
||||||
height: out.height + self.margin.1 + self.margin.3,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct InvertedHorizontalLayout {
|
|
||||||
pub widgets: Vec<Box<dyn Layout>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InvertedHorizontalLayout {
|
|
||||||
pub fn new(widgets: Vec<Box<dyn Layout>>) -> Box<dyn Layout> {
|
|
||||||
Box::new(InvertedHorizontalLayout { widgets })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Layout for InvertedHorizontalLayout {
|
|
||||||
fn geometry_update(
|
|
||||||
&self,
|
|
||||||
fonts: &mut FontMap,
|
|
||||||
geometry: &Geometry,
|
|
||||||
state: &mut State,
|
|
||||||
) -> Geometry {
|
|
||||||
let mut geo = geometry.clone();
|
|
||||||
let mut max_height = 0;
|
|
||||||
for w in self.widgets.iter() {
|
|
||||||
let mut temp_geo = geo.clone();
|
|
||||||
let temp_result = w.geometry_update(fonts, &temp_geo, state);
|
|
||||||
temp_geo.x = geo.x + (geo.width - temp_result.width);
|
|
||||||
let result = w.geometry_update(fonts, &temp_geo, state);
|
|
||||||
geo.width -= result.width;
|
|
||||||
max_height = max(result.height, max_height);
|
|
||||||
}
|
|
||||||
geo.height = max_height;
|
|
||||||
geo
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user