Compare commits

..
19 changed files with 1020 additions and 1074 deletions

544
plugin/Cargo.lock generated
View file

@ -23,64 +23,6 @@ version = "1.0.102"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
[[package]]
name = "async-broadcast"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532"
dependencies = [
"event-listener",
"event-listener-strategy",
"futures-core",
"pin-project-lite",
]
[[package]]
name = "async-recursion"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "async-trait"
version = "0.1.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "autocfg"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "bitflags"
version = "2.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3"
[[package]]
name = "bumpalo"
version = "3.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
[[package]]
name = "bytes"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
[[package]]
name = "cc"
version = "1.2.61"
@ -155,15 +97,6 @@ dependencies = [
"unicode-width 0.2.2",
]
[[package]]
name = "concurrent-queue"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "convert_case"
version = "0.6.0"
@ -173,12 +106,6 @@ dependencies = [
"unicode-segmentation",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
[[package]]
name = "ctor"
version = "0.13.1"
@ -355,76 +282,12 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "endi"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099"
[[package]]
name = "enumflags2"
version = "0.7.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef"
dependencies = [
"enumflags2_derive",
"serde",
]
[[package]]
name = "enumflags2_derive"
version = "0.7.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "errno"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys",
]
[[package]]
name = "event-listener"
version = "5.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab"
dependencies = [
"concurrent-queue",
"parking",
"pin-project-lite",
]
[[package]]
name = "event-listener-strategy"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93"
dependencies = [
"event-listener",
"pin-project-lite",
]
[[package]]
name = "fastrand"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6"
[[package]]
name = "find-msvc-tools"
version = "0.1.9"
@ -437,49 +300,6 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
[[package]]
name = "futures-core"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
[[package]]
name = "futures-io"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718"
[[package]]
name = "futures-lite"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad"
dependencies = [
"fastrand",
"futures-core",
"futures-io",
"parking",
"pin-project-lite",
]
[[package]]
name = "futures-task"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
[[package]]
name = "futures-util"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
dependencies = [
"futures-core",
"futures-task",
"pin-project-lite",
"slab",
]
[[package]]
name = "getrandom"
version = "0.2.17"
@ -509,12 +329,6 @@ version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51"
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "indexmap"
version = "2.14.0"
@ -550,18 +364,6 @@ dependencies = [
"libc",
]
[[package]]
name = "js-sys"
version = "0.3.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1840c94c045fbcf8ba2812c95db44499f7c64910a912551aaaa541decebcacf"
dependencies = [
"cfg-if",
"futures-util",
"once_cell",
"wasm-bindgen",
]
[[package]]
name = "lazy_static"
version = "1.5.0"
@ -604,12 +406,6 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a44cd706ff0d503ee32b2071166510ca27e281228de10cd3aa8d35ff94560f81"
[[package]]
name = "linux-raw-sys"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
[[package]]
name = "log"
version = "0.4.29"
@ -631,26 +427,6 @@ version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
[[package]]
name = "memoffset"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
dependencies = [
"autocfg",
]
[[package]]
name = "mio"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1"
dependencies = [
"libc",
"wasi",
"windows-sys",
]
[[package]]
name = "nova-plugin"
version = "0.1.0"
@ -664,10 +440,8 @@ dependencies = [
"libc",
"serde",
"serde_json",
"tokio",
"tracing",
"tracing-subscriber",
"zbus",
]
[[package]]
@ -691,37 +465,12 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "ordered-stream"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50"
dependencies = [
"futures-core",
"pin-project-lite",
]
[[package]]
name = "parking"
version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba"
[[package]]
name = "pin-project-lite"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
[[package]]
name = "proc-macro-crate"
version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f"
dependencies = [
"toml_edit",
]
[[package]]
name = "proc-macro2"
version = "1.0.106"
@ -787,19 +536,6 @@ version = "0.8.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
[[package]]
name = "rustix"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys",
"windows-sys",
]
[[package]]
name = "rustversion"
version = "1.0.22"
@ -861,17 +597,6 @@ dependencies = [
"zmij",
]
[[package]]
name = "serde_repr"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "sharded-slab"
version = "0.1.7"
@ -887,38 +612,12 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "signal-hook-registry"
version = "1.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
dependencies = [
"errno",
"libc",
]
[[package]]
name = "slab"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
[[package]]
name = "smallvec"
version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]]
name = "socket2"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
dependencies = [
"libc",
"windows-sys",
]
[[package]]
name = "static_assertions"
version = "1.1.0"
@ -942,19 +641,6 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "tempfile"
version = "3.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
dependencies = [
"fastrand",
"getrandom 0.3.4",
"once_cell",
"rustix",
"windows-sys",
]
[[package]]
name = "termcolor"
version = "1.4.1"
@ -1013,64 +699,6 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "tokio"
version = "1.52.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "110a78583f19d5cdb2c5ccf321d1290344e71313c6c37d43520d386027d18386"
dependencies = [
"bytes",
"libc",
"mio",
"pin-project-lite",
"signal-hook-registry",
"socket2",
"tokio-macros",
"tracing",
"windows-sys",
]
[[package]]
name = "tokio-macros"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "toml_datetime"
version = "1.1.1+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7"
dependencies = [
"serde_core",
]
[[package]]
name = "toml_edit"
version = "0.25.11+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b"
dependencies = [
"indexmap",
"toml_datetime",
"toml_parser",
"winnow",
]
[[package]]
name = "toml_parser"
version = "1.1.2+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526"
dependencies = [
"winnow",
]
[[package]]
name = "tracing"
version = "0.1.44"
@ -1132,17 +760,6 @@ dependencies = [
"tracing-log",
]
[[package]]
name = "uds_windows"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e"
dependencies = [
"memoffset",
"tempfile",
"windows-sys",
]
[[package]]
name = "unicode-ident"
version = "1.0.24"
@ -1167,17 +784,6 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
[[package]]
name = "uuid"
version = "1.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76"
dependencies = [
"js-sys",
"serde_core",
"wasm-bindgen",
]
[[package]]
name = "valuable"
version = "0.1.1"
@ -1199,51 +805,6 @@ dependencies = [
"wit-bindgen",
]
[[package]]
name = "wasm-bindgen"
version = "0.2.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df52b6d9b87e0c74c9edfa1eb2d9bf85e5d63515474513aa50fa181b3c4f5db1"
dependencies = [
"cfg-if",
"once_cell",
"rustversion",
"wasm-bindgen-macro",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78b1041f495fb322e64aca85f5756b2172e35cd459376e67f2a6c9dffcedb103"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9dcd0ff20416988a18ac686d4d4d0f6aae9ebf08a389ff5d29012b05af2a1b41"
dependencies = [
"bumpalo",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49757b3c82ebf16c57d69365a142940b384176c24df52a087fb748e2085359ea"
dependencies = [
"unicode-ident",
]
[[package]]
name = "winapi-util"
version = "0.1.11"
@ -1268,119 +829,14 @@ dependencies = [
"windows-link",
]
[[package]]
name = "winnow"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0"
dependencies = [
"memchr",
]
[[package]]
name = "wit-bindgen"
version = "0.57.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
[[package]]
name = "zbus"
version = "5.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3bcbf15c8708d7fc1be0c993622e0a5cbd5e8b52bfa40afa4c3e0cd8d724ac1"
dependencies = [
"async-broadcast",
"async-recursion",
"async-trait",
"enumflags2",
"event-listener",
"futures-core",
"futures-lite",
"hex",
"libc",
"ordered-stream",
"rustix",
"serde",
"serde_repr",
"tokio",
"tracing",
"uds_windows",
"uuid",
"windows-sys",
"winnow",
"zbus_macros",
"zbus_names",
"zvariant",
]
[[package]]
name = "zbus_macros"
version = "5.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51fa5406ad9175a8c825a931f8cf347116b531b3634fcb0b627c290f1f2516ff"
dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn",
"zbus_names",
"zvariant",
"zvariant_utils",
]
[[package]]
name = "zbus_names"
version = "4.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7074f3e50b894eac91750142016d30d0a89be8e67dbfd9704fb875825760e52d"
dependencies = [
"serde",
"winnow",
"zvariant",
]
[[package]]
name = "zmij"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
[[package]]
name = "zvariant"
version = "5.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c1567a6ec68df868cbbfde844cfc6d81649fe5109a62b116b19fabd53e618ee"
dependencies = [
"endi",
"enumflags2",
"serde",
"winnow",
"zvariant_derive",
"zvariant_utils",
]
[[package]]
name = "zvariant_derive"
version = "5.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7d5b780599bbde114e39d9a0799577fad1ced5105d38515745f7b3099d8ceda"
dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn",
"zvariant_utils",
]
[[package]]
name = "zvariant_utils"
version = "3.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d464f5733ffa07a3164d656f18533caace9d0638596721355d73256a410d691"
dependencies = [
"proc-macro2",
"quote",
"serde",
"syn",
"winnow",
]

View file

@ -23,14 +23,6 @@ serde_json = "1.0.149"
dirs = "6.0.0"
tracing = "0.1.44"
tracing-subscriber = { version = "0.3.23", features = ["env-filter"] }
zbus = { version = "5.15.0", default-features = false, features = ["tokio"] }
tokio = { version = "1.52.2", features = [
"macros",
"net",
"rt",
"sync",
"time",
] }
[build-dependencies]
cxx-qt-build = "0.8.1"

View file

@ -31,7 +31,6 @@ fn main() {
"src/system_stats.rs",
"src/cpu_service.rs",
"src/modules_service.rs",
"src/systemd_service.rs",
"src/theme_service.rs",
];
if !bridge_files.iter().all(|p| manifest.join(p).exists()) {

View file

@ -2,7 +2,6 @@ pub mod cpu_service;
pub mod modules_service;
pub mod stats;
pub mod system_stats;
pub mod systemd_service;
pub mod theme_service;
#[ctor::ctor(unsafe)]

View file

@ -101,9 +101,11 @@ pub mod qobject {
#[qproperty(bool, dock_applet_mpris, cxx_name = "dockAppletMpris")]
#[qproperty(bool, dock_applet_notifications, cxx_name = "dockAppletNotifications")]
#[qproperty(bool, dock_applet_power, cxx_name = "dockAppletPower")]
// Unified systemd bar module (covers local + nspawn containers, and later remotes).
// Systemd / machinectl bar modules.
#[qproperty(bool, systemd_enable, cxx_name = "systemdEnable")]
#[qproperty(i32, systemd_interval, cxx_name = "systemdInterval")]
#[qproperty(bool, machinectl_enable, cxx_name = "machinectlEnable")]
#[qproperty(i32, machinectl_interval, cxx_name = "machinectlInterval")]
type ModulesService = super::ModulesServiceRust;
}
@ -520,6 +522,8 @@ mod data {
#[serde(default)]
pub systemd: WithInterval,
#[serde(default)]
pub machinectl: WithInterval,
#[serde(default)]
pub stats_daemon: StatsDaemon,
}
}
@ -595,6 +599,8 @@ pub struct ModulesServiceRust {
dock_applet_power: bool,
systemd_enable: bool,
systemd_interval: i32,
machinectl_enable: bool,
machinectl_interval: i32,
}
impl Default for ModulesServiceRust {
@ -678,6 +684,8 @@ impl ModulesServiceRust {
dock_applet_power: d.dock.applets.power,
systemd_enable: d.systemd.enable,
systemd_interval: d.systemd.interval,
machinectl_enable: d.machinectl.enable,
machinectl_interval: d.machinectl.interval,
}
}
}
@ -738,6 +746,7 @@ fn parse_modules(raw: &str, path: &std::path::Path) -> ModulesData {
"lock",
"dock",
"systemd",
"machinectl",
"statsDaemon",
];
for key in map.keys() {

View file

@ -1,273 +0,0 @@
// In-process systemd state for nova-shell.
//
// Lists of units and machines are exposed to QML as JSON-encoded QString props
// (`failedUnitsJson`, `containersJson`) rather than QList<QVariantMap>. cxx-qt
// 0.8.1 does not implement QVariantValue for QVariantMap/QVariantList, and
// cxx-qt main on git regressed qt-build-utils to require QuickControls2.prl
// files that nixpkgs strips. Switch to QList<QVariantMap> when a release ships
// with both fixes.
use core::pin::Pin;
use cxx_qt_lib::QString;
use serde::Serialize;
use std::sync::OnceLock;
use tokio::runtime::Runtime;
use zbus::{Connection, proxy};
#[cxx_qt::bridge]
pub mod qobject {
unsafe extern "C++" {
include!("cxx-qt-lib/qstring.h");
type QString = cxx_qt_lib::QString;
}
extern "RustQt" {
#[qobject]
#[qml_element]
#[qml_singleton]
#[qproperty(QString, hostname)]
#[qproperty(QString, system_state, cxx_name = "systemState")]
#[qproperty(QString, user_state, cxx_name = "userState")]
#[qproperty(i32, failed_count, cxx_name = "failedCount")]
// JSON array: [{ name, description, subState, scope: "system"|"user", machine: "" | name }]
#[qproperty(QString, failed_units_json, cxx_name = "failedUnitsJson")]
// JSON array: [{ name, class, service, systemState, failedUnits: [...] }]
#[qproperty(QString, containers_json, cxx_name = "containersJson")]
type SystemdService = super::SystemdServiceRust;
#[qinvokable]
fn poll(self: Pin<&mut Self>);
#[qinvokable]
#[cxx_name = "restartUnit"]
fn restart_unit(self: Pin<&mut Self>, name: QString, scope: QString, machine: QString);
}
impl cxx_qt::Initialize for SystemdService {}
}
// systemd1.Manager.ListUnitsFiltered returns a(ssssssouso): name, description,
// load_state, active_state, sub_state, follower, unit_path, job_id, job_type, job_path.
type UnitTuple = (
String,
String,
String,
String,
String,
String,
zbus::zvariant::OwnedObjectPath,
u32,
String,
zbus::zvariant::OwnedObjectPath,
);
#[proxy(
interface = "org.freedesktop.systemd1.Manager",
default_service = "org.freedesktop.systemd1",
default_path = "/org/freedesktop/systemd1"
)]
trait SystemdManager {
#[zbus(property)]
fn system_state(&self) -> zbus::Result<String>;
fn list_units_filtered(&self, states: Vec<&str>) -> zbus::Result<Vec<UnitTuple>>;
fn restart_unit(&self, name: &str, mode: &str)
-> zbus::Result<zbus::zvariant::OwnedObjectPath>;
}
#[proxy(
interface = "org.freedesktop.machine1.Manager",
default_service = "org.freedesktop.machine1",
default_path = "/org/freedesktop/machine1"
)]
trait Machined {
fn list_machines(
&self,
) -> zbus::Result<Vec<(String, String, String, zbus::zvariant::OwnedObjectPath)>>;
}
#[derive(Serialize)]
struct UnitJson<'a> {
name: &'a str,
description: &'a str,
#[serde(rename = "subState")]
sub_state: &'a str,
scope: &'a str,
machine: &'a str,
}
#[derive(Serialize)]
struct ContainerJson<'a> {
name: &'a str,
class: &'a str,
service: &'a str,
#[serde(rename = "systemState")]
system_state: &'a str,
#[serde(rename = "failedUnits")]
failed_units: Vec<UnitJson<'a>>,
}
pub struct SystemdServiceRust {
hostname: QString,
system_state: QString,
user_state: QString,
failed_count: i32,
failed_units_json: QString,
containers_json: QString,
}
impl Default for SystemdServiceRust {
fn default() -> Self {
Self {
hostname: QString::from(read_hostname()),
system_state: QString::from("unknown"),
user_state: QString::from("unknown"),
failed_count: 0,
failed_units_json: QString::from("[]"),
containers_json: QString::from("[]"),
}
}
}
fn read_hostname() -> String {
std::fs::read_to_string("/etc/hostname")
.map(|s| s.trim().to_string())
.unwrap_or_else(|_| "localhost".to_string())
}
fn rt() -> &'static Runtime {
static RT: OnceLock<Runtime> = OnceLock::new();
RT.get_or_init(|| {
tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("tokio runtime")
})
}
async fn fetch_failed(bus: &Connection) -> (String, Vec<UnitTuple>) {
let mut state = String::from("unknown");
let mut units = Vec::new();
if let Ok(mgr) = SystemdManagerProxy::new(bus).await {
if let Ok(s) = mgr.system_state().await {
state = s;
}
if let Ok(u) = mgr.list_units_filtered(vec!["failed"]).await {
units = u;
}
}
(state, units)
}
async fn poll_async() -> (
String,
String,
Vec<UnitTuple>,
Vec<UnitTuple>,
Vec<(String, String, String)>,
) {
let mut sys_state = String::from("unknown");
let mut sys_units = Vec::new();
let mut user_state = String::from("unknown");
let mut user_units = Vec::new();
let mut machines = Vec::new();
if let Ok(c) = Connection::system().await {
let (s, u) = fetch_failed(&c).await;
sys_state = s;
sys_units = u;
if let Ok(m) = MachinedProxy::new(&c).await {
if let Ok(list) = m.list_machines().await {
machines = list
.into_iter()
.filter(|(name, _, _, _)| name != ".host")
.map(|(n, c, s, _)| (n, c, s))
.collect();
}
}
}
if let Ok(c) = Connection::session().await {
let (s, u) = fetch_failed(&c).await;
user_state = s;
user_units = u;
}
(sys_state, user_state, sys_units, user_units, machines)
}
fn unit_jsons<'a>(units: &'a [UnitTuple], scope: &'a str, machine: &'a str) -> Vec<UnitJson<'a>> {
units
.iter()
.map(|u| UnitJson {
name: &u.0,
description: &u.1,
sub_state: &u.4,
scope,
machine,
})
.collect()
}
impl cxx_qt::Initialize for qobject::SystemdService {
fn initialize(self: Pin<&mut Self>) {
self.poll();
}
}
impl qobject::SystemdService {
fn poll(mut self: Pin<&mut Self>) {
let (sys_state, user_state, sys_units, user_units, machines) = rt().block_on(poll_async());
let mut all_failed: Vec<UnitJson> = Vec::with_capacity(sys_units.len() + user_units.len());
all_failed.extend(unit_jsons(&sys_units, "system", ""));
all_failed.extend(unit_jsons(&user_units, "user", ""));
let count = all_failed.len() as i32;
let failed_json = serde_json::to_string(&all_failed).unwrap_or_else(|_| "[]".into());
let containers: Vec<ContainerJson> = machines
.iter()
.map(|(n, c, s)| ContainerJson {
name: n,
class: c,
service: s,
system_state: "unknown",
failed_units: Vec::new(),
})
.collect();
let containers_json = serde_json::to_string(&containers).unwrap_or_else(|_| "[]".into());
self.as_mut().set_system_state(QString::from(sys_state));
self.as_mut().set_user_state(QString::from(user_state));
self.as_mut()
.set_failed_units_json(QString::from(failed_json));
self.as_mut().set_failed_count(count);
self.as_mut()
.set_containers_json(QString::from(containers_json));
}
fn restart_unit(self: Pin<&mut Self>, name: QString, scope: QString, machine: QString) {
let name = name.to_string();
let scope = scope.to_string();
let machine = machine.to_string();
let _ = self;
rt().block_on(async move {
// Local-only restart for now. Container/remote restart comes later.
if !machine.is_empty() {
tracing::warn!(target: "nova_plugin", machine = %machine, "container restart not yet implemented");
return;
}
let conn = match scope.as_str() {
"user" => Connection::session().await,
_ => Connection::system().await,
};
let Ok(conn) = conn else { return };
let Ok(mgr) = SystemdManagerProxy::new(&conn).await else {
return;
};
if let Err(e) = mgr.restart_unit(&name, "replace").await {
tracing::warn!(target: "nova_plugin", unit = %name, error = %e, "restart_unit failed");
}
});
}
}

View file

@ -0,0 +1,354 @@
pragma ComponentBehavior: Bound
import QtQuick
import "../services" as S
import NovaStats as NS
Column {
id: root
required property color accentColor
property bool active: true
property bool _localExpanded: true
// Localhost section header
Item {
width: root.width
height: 32
Rectangle {
anchors.fill: parent
anchors.leftMargin: 4
anchors.rightMargin: 4
color: _localHdrHover.hovered ? NS.ThemeService.base02 : "transparent"
radius: NS.ThemeService.radius
z: -1
}
HoverHandler {
id: _localHdrHover
}
Text {
anchors.left: parent.left
anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter
text: " localhost"
color: NS.ThemeService.base05
font.pixelSize: NS.ThemeService.fontSize
font.family: NS.ThemeService.fontFamily
}
Rectangle {
id: _localStateChip
anchors.right: _localChevron.left
anchors.rightMargin: 8
anchors.verticalCenter: parent.verticalCenter
visible: S.SystemdService.systemState !== "unknown"
color: {
const st = S.SystemdService.systemState;
if (st === "running")
return NS.ThemeService.base0B;
if (st === "degraded")
return NS.ThemeService.base0A;
return NS.ThemeService.base08;
}
opacity: 0.85
radius: 3
width: _localStateLbl.width + 8
height: 14
Text {
id: _localStateLbl
anchors.centerIn: parent
text: S.SystemdService.systemState
color: NS.ThemeService.base00
font.pixelSize: NS.ThemeService.fontSize - 3
font.family: NS.ThemeService.fontFamily
}
}
Text {
id: _localChevron
anchors.right: parent.right
anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter
text: root._localExpanded ? "" : ""
color: NS.ThemeService.base04
font.pixelSize: NS.ThemeService.fontSize - 2
font.family: NS.ThemeService.iconFontFamily
}
TapHandler {
onTapped: root._localExpanded = !root._localExpanded
}
}
// Localhost expanded content
Column {
visible: root._localExpanded
width: root.width
// System sub-section
Item {
width: root.width
height: 22
Text {
anchors.left: parent.left
anchors.leftMargin: 24
anchors.verticalCenter: parent.verticalCenter
text: "SYSTEM"
color: NS.ThemeService.base03
font.pixelSize: NS.ThemeService.fontSize - 3
font.family: NS.ThemeService.fontFamily
font.letterSpacing: 1
}
}
Repeater {
model: S.SystemdService.systemUnits
delegate: SystemdUnitRow {
required property var modelData
unitName: modelData.name
description: modelData.description
subState: modelData.subState
isUser: false
machineName: ""
accentColor: root.accentColor
}
}
Item {
visible: S.SystemdService.systemUnits.length === 0
width: root.width
height: 22
Text {
anchors.centerIn: parent
text: "no failures"
color: NS.ThemeService.base0B
font.pixelSize: NS.ThemeService.fontSize - 2
font.family: NS.ThemeService.fontFamily
}
}
// User sub-section
Item {
width: root.width
height: 22
Text {
anchors.left: parent.left
anchors.leftMargin: 24
anchors.verticalCenter: parent.verticalCenter
text: "USER"
color: NS.ThemeService.base03
font.pixelSize: NS.ThemeService.fontSize - 3
font.family: NS.ThemeService.fontFamily
font.letterSpacing: 1
}
}
Repeater {
model: S.SystemdService.userUnits
delegate: SystemdUnitRow {
required property var modelData
unitName: modelData.name
description: modelData.description
subState: modelData.subState
isUser: true
machineName: ""
accentColor: root.accentColor
}
}
Item {
visible: S.SystemdService.userUnits.length === 0
width: root.width
height: 22
Text {
anchors.centerIn: parent
text: "no failures"
color: NS.ThemeService.base0B
font.pixelSize: NS.ThemeService.fontSize - 2
font.family: NS.ThemeService.fontFamily
}
}
}
// Containers
Repeater {
model: S.MachinectlService.machines
delegate: Column {
id: _machineSection
required property var modelData
required property int index
property bool _expanded: false
property bool _loading: false
width: root.width
Connections {
target: S.MachinectlService
function onMachineReady(machineName) {
if (machineName === _machineSection.modelData.name)
_machineSection._loading = false;
}
}
Separator {}
// Machine header
Item {
width: _machineSection.width
height: 32
Rectangle {
anchors.fill: parent
anchors.leftMargin: 4
anchors.rightMargin: 4
color: _mHdrHover.hovered ? NS.ThemeService.base02 : "transparent"
radius: NS.ThemeService.radius
z: -1
}
HoverHandler {
id: _mHdrHover
}
Text {
anchors.left: parent.left
anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter
text: " " + _machineSection.modelData.name
color: NS.ThemeService.base05
font.pixelSize: NS.ThemeService.fontSize
font.family: NS.ThemeService.fontFamily
elide: Text.ElideRight
width: parent.width - 100
}
Rectangle {
id: _mStateChip
anchors.right: _mChevron.left
anchors.rightMargin: 8
anchors.verticalCenter: parent.verticalCenter
visible: _machineSection._expanded && !_machineSection._loading
color: {
const st = S.MachinectlService.machineState(_machineSection.modelData.name);
if (st === "running")
return NS.ThemeService.base0B;
if (st === "degraded")
return NS.ThemeService.base0A;
return st === "unknown" ? "transparent" : NS.ThemeService.base08;
}
opacity: 0.85
radius: 3
width: _mStateLbl.width + 8
height: 14
Text {
id: _mStateLbl
anchors.centerIn: parent
text: S.MachinectlService.machineState(_machineSection.modelData.name)
color: NS.ThemeService.base00
font.pixelSize: NS.ThemeService.fontSize - 3
font.family: NS.ThemeService.fontFamily
}
}
Text {
id: _mChevron
anchors.right: parent.right
anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter
text: _machineSection._expanded ? "" : ""
color: NS.ThemeService.base04
font.pixelSize: NS.ThemeService.fontSize - 2
font.family: NS.ThemeService.iconFontFamily
}
TapHandler {
onTapped: {
_machineSection._expanded = !_machineSection._expanded;
if (_machineSection._expanded) {
_machineSection._loading = true;
S.MachinectlService.fetchMachine(_machineSection.modelData.name);
}
}
}
}
// Machine expanded content
Column {
visible: _machineSection._expanded
width: _machineSection.width
Item {
visible: _machineSection._loading
width: _machineSection.width
height: 28
Text {
anchors.centerIn: parent
text: "loading..."
color: NS.ThemeService.base04
font.pixelSize: NS.ThemeService.fontSize - 2
font.family: NS.ThemeService.fontFamily
}
}
// System units inside the container
Item {
visible: !_machineSection._loading
width: _machineSection.width
height: 22
Text {
anchors.left: parent.left
anchors.leftMargin: 24
anchors.verticalCenter: parent.verticalCenter
text: "SYSTEM"
color: NS.ThemeService.base03
font.pixelSize: NS.ThemeService.fontSize - 3
font.family: NS.ThemeService.fontFamily
font.letterSpacing: 1
}
}
Repeater {
model: !_machineSection._loading ? S.MachinectlService.machineUnits(_machineSection.modelData.name) : []
delegate: SystemdUnitRow {
required property var modelData
unitName: modelData.name
description: modelData.description
subState: modelData.subState
isUser: false
machineName: _machineSection.modelData.name
accentColor: root.accentColor
}
}
Item {
visible: !_machineSection._loading && S.MachinectlService.machineUnits(_machineSection.modelData.name).length === 0
width: _machineSection.width
height: 22
Text {
anchors.centerIn: parent
text: "no failures"
color: NS.ThemeService.base0B
font.pixelSize: NS.ThemeService.fontSize - 2
font.family: NS.ThemeService.fontFamily
}
}
}
}
}
Item {
width: 1
height: 4
}
}

View file

@ -9,43 +9,156 @@ Column {
required property color accentColor
property bool active: true
// Emitted when content resizes; parent can connect to extend panel-close grace.
signal contentResized
onHeightChanged: root.contentResized()
// Local machine header + units
SystemdMachineSection {
// Section header: state label + unit count
Item {
width: root.width
accentColor: root.accentColor
machineName: ""
title: S.SystemdService.hostname
marker: " this machine"
systemState: S.SystemdService.systemState
units: S.SystemdService.failedUnits
startExpanded: true
height: 28
Text {
anchors.left: parent.left
anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter
text: "SYSTEM"
color: NS.ThemeService.base03
font.pixelSize: NS.ThemeService.fontSize - 3
font.family: NS.ThemeService.fontFamily
font.letterSpacing: 1
}
Rectangle {
anchors.right: parent.right
anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter
visible: S.SystemdService.systemState !== "unknown"
color: {
const st = S.SystemdService.systemState;
if (st === "running")
return NS.ThemeService.base0B;
if (st === "degraded")
return NS.ThemeService.base0A;
return NS.ThemeService.base08;
}
opacity: 0.85
radius: 3
width: _sysStateLbl.width + 8
height: 14
Text {
id: _sysStateLbl
anchors.centerIn: parent
text: S.SystemdService.systemState
color: NS.ThemeService.base00
font.pixelSize: NS.ThemeService.fontSize - 3
font.family: NS.ThemeService.fontFamily
}
}
}
// Containers
Repeater {
model: S.SystemdService.containers
model: S.SystemdService.systemUnits
delegate: Column {
id: _row
delegate: SystemdUnitRow {
required property var modelData
width: root.width
unitName: modelData.name
description: modelData.description
subState: modelData.subState
isUser: false
machineName: ""
accentColor: root.accentColor
onHeightChanged: root.contentResized()
}
}
Separator {}
Item {
visible: S.SystemdService.systemUnits.length === 0
width: root.width
height: 24
SystemdMachineSection {
width: _row.width
accentColor: root.accentColor
machineName: _row.modelData.name
title: _row.modelData.name
marker: ""
systemState: _row.modelData.systemState ?? "unknown"
units: _row.modelData.failedUnits ?? []
startExpanded: (_row.modelData.failedUnits ?? []).length > 0
Text {
anchors.centerIn: parent
text: "no failed system units"
color: NS.ThemeService.base0B
font.pixelSize: NS.ThemeService.fontSize - 2
font.family: NS.ThemeService.fontFamily
}
}
Separator {}
// User section
Item {
width: root.width
height: 28
Text {
anchors.left: parent.left
anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter
text: "USER"
color: NS.ThemeService.base03
font.pixelSize: NS.ThemeService.fontSize - 3
font.family: NS.ThemeService.fontFamily
font.letterSpacing: 1
}
Rectangle {
anchors.right: parent.right
anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter
visible: S.SystemdService.userState !== "unknown"
color: {
const st = S.SystemdService.userState;
if (st === "running")
return NS.ThemeService.base0B;
if (st === "degraded")
return NS.ThemeService.base0A;
return NS.ThemeService.base08;
}
opacity: 0.85
radius: 3
width: _userStateLbl.width + 8
height: 14
Text {
id: _userStateLbl
anchors.centerIn: parent
text: S.SystemdService.userState
color: NS.ThemeService.base00
font.pixelSize: NS.ThemeService.fontSize - 3
font.family: NS.ThemeService.fontFamily
}
}
}
Repeater {
model: S.SystemdService.userUnits
delegate: SystemdUnitRow {
required property var modelData
unitName: modelData.name
description: modelData.description
subState: modelData.subState
isUser: true
machineName: ""
accentColor: root.accentColor
onHeightChanged: root.contentResized()
}
}
Item {
visible: S.SystemdService.userUnits.length === 0
width: root.width
height: 24
Text {
anchors.centerIn: parent
text: "no failed user units"
color: NS.ThemeService.base0B
font.pixelSize: NS.ThemeService.fontSize - 2
font.family: NS.ThemeService.fontFamily
}
}

View file

@ -1,111 +0,0 @@
pragma ComponentBehavior: Bound
import QtQuick
import "../services" as S
import NovaStats as NS
// One section of the systemd applet: a header with title + state chip,
// expandable list of failed units underneath.
Column {
id: root
required property color accentColor
required property string machineName
required property string title
required property string marker
required property string systemState
required property var units
property bool startExpanded: false
width: parent?.width ?? 0
property bool _expanded: startExpanded
Item {
width: root.width
height: 32
Rectangle {
anchors.fill: parent
anchors.leftMargin: 4
anchors.rightMargin: 4
color: _hdrHover.hovered ? NS.ThemeService.base02 : "transparent"
radius: NS.ThemeService.radius
z: -1
}
HoverHandler {
id: _hdrHover
}
Text {
anchors.left: parent.left
anchors.leftMargin: 12
anchors.right: _stateChip.left
anchors.rightMargin: 6
anchors.verticalCenter: parent.verticalCenter
text: root.title + (root.marker !== "" ? " " + root.marker : "")
color: NS.ThemeService.base05
font.pixelSize: NS.ThemeService.fontSize
font.family: NS.ThemeService.fontFamily
elide: Text.ElideRight
}
Rectangle {
id: _stateChip
anchors.right: _chevron.left
anchors.rightMargin: 8
anchors.verticalCenter: parent.verticalCenter
visible: root.systemState !== "unknown"
color: {
const st = root.systemState;
if (st === "running")
return NS.ThemeService.base0B;
if (st === "degraded")
return NS.ThemeService.base0A;
return NS.ThemeService.base08;
}
opacity: 0.85
radius: 3
width: _stateLbl.width + 8
height: 14
Text {
id: _stateLbl
anchors.centerIn: parent
text: root.systemState
color: NS.ThemeService.base00
font.pixelSize: NS.ThemeService.fontSize - 3
font.family: NS.ThemeService.fontFamily
}
}
Text {
id: _chevron
anchors.right: parent.right
anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter
text: root._expanded ? "" : ""
color: NS.ThemeService.base04
font.pixelSize: NS.ThemeService.fontSize - 2
font.family: NS.ThemeService.iconFontFamily
}
TapHandler {
onTapped: root._expanded = !root._expanded
}
}
Repeater {
model: root._expanded ? root.units : []
delegate: SystemdUnitRow {
required property var modelData
unitName: modelData.name
description: modelData.description ?? ""
subState: modelData.subState ?? ""
scope: modelData.scope ?? "system"
machineName: root.machineName
accentColor: root.accentColor
}
}
}

View file

@ -8,95 +8,233 @@ Item {
required property string unitName
required property string description
required property string subState
required property string scope
required property string machineName
required property bool isUser
property string machineName: ""
required property color accentColor
property string _jText: ""
property bool _expanded: false
property bool _loading: false
width: parent?.width ?? 0
height: 28
height: _row.height + (_expanded ? _journalArea.height : 0)
HoverHandler {
id: _rowHover
}
Rectangle {
anchors.fill: parent
anchors.leftMargin: 4
anchors.rightMargin: 4
color: _rowHover.hovered ? NS.ThemeService.base02 : "transparent"
radius: NS.ThemeService.radius
z: -1
}
Text {
anchors.left: parent.left
anchors.leftMargin: 12
anchors.right: _subStateTag.left
anchors.rightMargin: 6
anchors.verticalCenter: parent.verticalCenter
text: root.unitName
color: NS.ThemeService.base05
font.pixelSize: NS.ThemeService.fontSize - 1
font.family: NS.ThemeService.fontFamily
elide: Text.ElideRight
}
Rectangle {
id: _subStateTag
anchors.right: _restartBtn.left
anchors.rightMargin: 6
anchors.verticalCenter: parent.verticalCenter
color: NS.ThemeService.base08
opacity: 0.85
radius: 3
width: _subStateLbl.width + 8
height: 14
Text {
id: _subStateLbl
anchors.centerIn: parent
text: root.subState
color: NS.ThemeService.base00
font.pixelSize: NS.ThemeService.fontSize - 3
font.family: NS.ThemeService.fontFamily
Behavior on height {
NumberAnimation {
duration: 150
}
}
// Restart button only visible while hovering the row. = fa-refresh
Connections {
target: S.SystemdService
enabled: root.machineName === ""
function onJournalReady(unitName, isUser, text) {
if (unitName === root.unitName && isUser === root.isUser) {
root._jText = text;
root._loading = false;
}
}
}
Connections {
target: S.MachinectlService
enabled: root.machineName !== ""
function onMachineJournalReady(mname, unitName, text) {
if (mname === root.machineName && unitName === root.unitName) {
root._jText = text;
root._loading = false;
}
}
}
function _fetchJournal() {
root._loading = true;
root._jText = "";
if (root.machineName === "")
S.SystemdService.fetchJournal(root.unitName, root.isUser);
else
S.MachinectlService.fetchMachineJournal(root.machineName, root.unitName);
}
function _doRestart() {
if (root.machineName === "")
S.SystemdService.restartUnit(root.unitName, root.isUser);
else
S.MachinectlService.restartMachineUnit(root.machineName, root.unitName);
}
// Row
Item {
id: _restartBtn
anchors.right: parent.right
anchors.rightMargin: 8
anchors.verticalCenter: parent.verticalCenter
width: 24
height: 24
opacity: _rowHover.hovered ? 1 : 0
Behavior on opacity {
NumberAnimation {
duration: 80
id: _row
width: parent.width
height: 32
Rectangle {
anchors.fill: parent
anchors.leftMargin: 4
anchors.rightMargin: 4
color: _rowHover.hovered ? NS.ThemeService.base02 : "transparent"
radius: NS.ThemeService.radius
z: -1
}
HoverHandler {
id: _rowHover
}
Text {
anchors.left: parent.left
anchors.leftMargin: 12
anchors.right: _subStateTag.left
anchors.rightMargin: 6
anchors.verticalCenter: parent.verticalCenter
text: root.unitName
color: NS.ThemeService.base05
font.pixelSize: NS.ThemeService.fontSize - 1
font.family: NS.ThemeService.fontFamily
elide: Text.ElideRight
}
Rectangle {
id: _subStateTag
anchors.right: _restartBtn.left
anchors.rightMargin: 6
anchors.verticalCenter: parent.verticalCenter
color: NS.ThemeService.base08
opacity: 0.85
radius: 3
width: _subStateLbl.width + 8
height: 14
Text {
id: _subStateLbl
anchors.centerIn: parent
text: root.subState
color: NS.ThemeService.base00
font.pixelSize: NS.ThemeService.fontSize - 3
font.family: NS.ThemeService.fontFamily
}
}
Text {
anchors.centerIn: parent
text: ""
color: _rHover.hovered ? root.accentColor : NS.ThemeService.base04
font.pixelSize: NS.ThemeService.fontSize
font.family: NS.ThemeService.iconFontFamily
Behavior on color {
ColorAnimation {
duration: 80
// Restart button - = fa-refresh
Item {
id: _restartBtn
anchors.right: _expandBtn.left
anchors.rightMargin: 2
anchors.verticalCenter: parent.verticalCenter
width: 24
height: 24
Text {
anchors.centerIn: parent
text: ""
color: _rHover.hovered ? root.accentColor : NS.ThemeService.base04
font.pixelSize: NS.ThemeService.fontSize
font.family: NS.ThemeService.iconFontFamily
Behavior on color {
ColorAnimation {
duration: 80
}
}
}
HoverHandler {
id: _rHover
cursorShape: Qt.PointingHandCursor
}
TapHandler {
onTapped: {
root._doRestart();
if (root._expanded) {
root._jText = "";
Qt.callLater(root._fetchJournal);
}
}
}
}
HoverHandler {
id: _rHover
cursorShape: Qt.PointingHandCursor
// Expand chevron - = fa-chevron-down, = fa-chevron-up
Item {
id: _expandBtn
anchors.right: parent.right
anchors.rightMargin: 4
anchors.verticalCenter: parent.verticalCenter
width: 24
height: 24
Text {
anchors.centerIn: parent
text: root._expanded ? "" : ""
color: _expHover.hovered ? root.accentColor : NS.ThemeService.base04
font.pixelSize: NS.ThemeService.fontSize - 1
font.family: NS.ThemeService.iconFontFamily
Behavior on color {
ColorAnimation {
duration: 80
}
}
}
HoverHandler {
id: _expHover
cursorShape: Qt.PointingHandCursor
}
TapHandler {
onTapped: {
root._expanded = !root._expanded;
if (root._expanded && root._jText === "")
root._fetchJournal();
}
}
}
TapHandler {
enabled: _rowHover.hovered
onTapped: S.SystemdService.restartUnit(root.unitName, root.scope, root.machineName)
}
// Journal area
Item {
id: _journalArea
anchors.top: _row.bottom
width: parent.width
height: 120
visible: root._expanded
clip: true
Rectangle {
anchors.fill: parent
anchors.leftMargin: 8
anchors.rightMargin: 8
anchors.bottomMargin: 4
color: NS.ThemeService.base01
radius: NS.ThemeService.radius
Text {
anchors.centerIn: parent
visible: root._loading
text: "loading..."
color: NS.ThemeService.base04
font.pixelSize: NS.ThemeService.fontSize - 2
font.family: NS.ThemeService.fontFamily
}
Flickable {
id: _flick
anchors.fill: parent
anchors.margins: 6
visible: !root._loading
contentHeight: _jContent.height
clip: true
Text {
id: _jContent
width: _flick.width
text: root._jText
color: NS.ThemeService.base04
font.pixelSize: NS.ThemeService.fontSize - 3
font.family: NS.ThemeService.fontFamily
wrapMode: Text.WrapAnywhere
}
onContentHeightChanged: contentY = Math.max(0, contentHeight - height)
}
}
}
}

View file

@ -10,6 +10,7 @@ GpuApplet 1.0 GpuApplet.qml
HexWaveBackground 1.0 HexWaveBackground.qml
HoverableListItem 1.0 HoverableListItem.qml
InfoRow 1.0 InfoRow.qml
MachinectlApplet 1.0 MachinectlApplet.qml
MemoryApplet 1.0 MemoryApplet.qml
MprisApplet 1.0 MprisApplet.qml
NetworkApplet 1.0 NetworkApplet.qml
@ -18,7 +19,6 @@ PowerApplet 1.0 PowerApplet.qml
Separator 1.0 Separator.qml
SparklineCanvas 1.0 SparklineCanvas.qml
SystemdApplet 1.0 SystemdApplet.qml
SystemdMachineSection 1.0 SystemdMachineSection.qml
SystemdUnitRow 1.0 SystemdUnitRow.qml
TemperatureApplet 1.0 TemperatureApplet.qml
VolumeApplet 1.0 VolumeApplet.qml

View file

@ -187,6 +187,7 @@ PanelWindow {
M.WeatherModule {}
M.DiskModule {}
M.SystemdModule {}
M.MachinectlModule {}
}
// Power + Dock

View file

@ -0,0 +1,47 @@
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import "." as M
import "../services" as S
import "../applets" as C
import NovaStats as NS
M.BarModule {
id: root
active: NS.ModulesService.machinectlEnable
tooltip: {
const n = S.MachinectlService.machines.length;
return n === 0 ? "no containers" : n + " container" + (n === 1 ? "" : "s");
}
panelNamespace: "nova-machinectl"
panelContentWidth: 320
panelComponent: Component {
C.MachinectlApplet {
width: parent.width
accentColor: root.accentColor
active: root._showPanel
}
}
Connections {
target: S.MachinectlService
function onMachineReady() {
root.keepPanelOpen(300);
}
}
readonly property color _stateColor: S.MachinectlService.anyUnhealthy ? NS.ThemeService.base0A : root.accentColor
M.BarIcon {
icon: ""
color: root._stateColor
anchors.verticalCenter: parent.verticalCenter
}
M.BarLabel {
label: S.MachinectlService.machines.length.toString()
minText: "9"
color: root._stateColor
anchors.verticalCenter: parent.verticalCenter
}
}

View file

@ -1,6 +1,7 @@
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import "." as M
import "../services" as S
import "../applets" as C
@ -10,11 +11,12 @@ M.BarModule {
id: root
active: NS.ModulesService.systemdEnable
tooltip: {
const fc = S.SystemdService.failedCount;
return fc === 0 ? "systemd: ok" : "systemd: " + fc + " failed";
const sys = S.SystemdService.systemState;
const fc = S.SystemdService.totalFailedCount;
return "systemd: " + sys + (fc > 0 ? " (" + fc + " failed)" : "");
}
panelNamespace: "nova-systemd"
panelContentWidth: 320
panelContentWidth: 300
panelComponent: Component {
C.SystemdApplet {
width: parent.width
@ -26,12 +28,22 @@ M.BarModule {
Connections {
target: S.SystemdService
function onFailedUnitsChanged() {
function onSystemUnitsChanged() {
root.keepPanelOpen(300);
}
function onUserUnitsChanged() {
root.keepPanelOpen(300);
}
}
readonly property color _stateColor: S.SystemdService.failedCount > 0 ? NS.ThemeService.base0A : root.accentColor
readonly property color _stateColor: {
const st = S.SystemdService.systemState;
if (st === "running")
return root.accentColor;
if (st === "degraded")
return NS.ThemeService.base0A;
return NS.ThemeService.base08;
}
M.BarIcon {
icon: ""
@ -39,8 +51,8 @@ M.BarModule {
anchors.verticalCenter: parent.verticalCenter
}
M.BarLabel {
label: S.SystemdService.failedCount > 0 ? S.SystemdService.failedCount + " failed" : "ok"
minText: "0 failed"
label: S.SystemdService.totalFailedCount > 0 ? S.SystemdService.totalFailedCount + " failed" : S.SystemdService.systemState
minText: "degraded"
color: root._stateColor
anchors.verticalCenter: parent.verticalCenter
}

View file

@ -16,6 +16,7 @@ DockModule 1.0 DockModule.qml
GpuModule 1.0 GpuModule.qml
HoverPanel 1.0 HoverPanel.qml
IdleInhibitorModule 1.0 IdleInhibitorModule.qml
MachinectlModule 1.0 MachinectlModule.qml
MemoryModule 1.0 MemoryModule.qml
MprisModule 1.0 MprisModule.qml
NetworkModule 1.0 NetworkModule.qml

View file

@ -0,0 +1,152 @@
pragma Singleton
import QtQuick
import Quickshell.Io
import "." as S
import NovaStats as NS
QtObject {
id: root
property var machines: []
// cache: machineName -> {state, units, loading}
property var _cache: ({})
readonly property bool anyUnhealthy: {
for (const k of Object.keys(_cache)) {
if ((_cache[k]?.units?.length ?? 0) > 0)
return true;
}
return false;
}
function machineState(name) {
return _cache[name]?.state ?? "unknown";
}
function machineUnits(name) {
return _cache[name]?.units ?? [];
}
function machineLoading(name) {
return _cache[name]?.loading ?? false;
}
signal machineReady(string machineName, string state, var units)
signal machineJournalReady(string machineName, string unitName, string text)
// Per-call state: kept on root (not on the inline Process objects) so qmllint can see them.
property string _machineName: ""
property string _journalMachine: ""
property string _journalUnit: ""
property string _restartMachine: ""
function fetchMachine(name) {
const c = Object.assign({}, _cache);
c[name] = Object.assign({}, c[name] ?? {}, {
loading: true
});
_cache = c;
root._machineName = name;
_machineProc.command = ["sh", "-c", "busctl get-property --json=short --machine=" + name + " org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager SystemState 2>/dev/null || echo '{}'; " + "busctl call --json=short --machine=" + name + " org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager ListUnitsFiltered as 1 failed 2>/dev/null || echo '{}'"];
if (_machineProc.running)
_machineProc.running = false;
_machineProc.running = true;
}
function fetchMachineJournal(machineName, unitName) {
root._journalMachine = machineName;
root._journalUnit = unitName;
_machineJournalProc.command = ["journalctl", "-M", machineName, "-u", unitName, "-n", "80", "--no-pager", "--output=short-precise"];
if (_machineJournalProc.running)
_machineJournalProc.running = false;
_machineJournalProc.running = true;
}
function restartMachineUnit(machineName, unitName) {
root._restartMachine = machineName;
_machineRestartProc.command = ["pkexec", "systemctl", "-M", machineName, "restart", unitName];
if (_machineRestartProc.running)
_machineRestartProc.running = false;
_machineRestartProc.running = true;
}
property Timer _poll: Timer {
interval: NS.ModulesService.machinectlInterval ?? 15000
running: NS.ModulesService.machinectlEnable
repeat: true
triggeredOnStart: true
onTriggered: if (!root._listProc.running)
root._listProc.running = true
}
property Process _listProc: Process {
command: ["busctl", "call", "--json=short", "org.freedesktop.machine1", "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", "ListMachines"]
stdout: StdioCollector {
onStreamFinished: {
try {
const parsed = JSON.parse(text.trim());
const newMachines = (parsed.data?.[0] || []).map(m => ({
name: m[0],
class: m[1],
service: m[2]
}));
root.machines = newMachines;
// drop stale cache entries
const names = new Set(newMachines.map(m => m.name));
const c = {};
for (const k of Object.keys(root._cache)) {
if (names.has(k))
c[k] = root._cache[k];
}
root._cache = c;
} catch (e) {
root.machines = [];
}
}
}
}
// 2 lines of output: state, failed-units
property Process _machineProc: Process {
stdout: StdioCollector {
onStreamFinished: {
const lines = text.trim().split("\n");
let state = "unknown";
let units = [];
try {
state = JSON.parse(lines[0] ?? "").data || "unknown";
} catch (e) {}
try {
const parsed = JSON.parse(lines[1] ?? "");
units = (parsed.data?.[0] || []).map(u => ({
name: u[0],
description: u[1],
loadState: u[2],
activeState: u[3],
subState: u[4]
}));
} catch (e) {}
const c = Object.assign({}, root._cache);
c[root._machineName] = {
state: state,
units: units,
loading: false
};
root._cache = c;
root.machineReady(root._machineName, state, units);
}
}
}
property Process _machineJournalProc: Process {
stdout: StdioCollector {
onStreamFinished: root.machineJournalReady(root._journalMachine, root._journalUnit, text)
}
}
property Process _machineRestartProc: Process {
onRunningChanged: if (!running && root._restartMachine !== "")
root.fetchMachine(root._restartMachine)
}
}

View file

@ -1,53 +1,100 @@
pragma Singleton
import QtQuick
import Quickshell.Io
import "." as S
import NovaStats as NS
// Thin wrapper around NS.SystemdService: drives the poll Timer and parses the
// JSON-encoded list properties into JS arrays for QML consumers. Restart helper
// proxies through to the Rust singleton.
QtObject {
id: root
readonly property string hostname: NS.SystemdService.hostname
readonly property string systemState: NS.SystemdService.systemState
readonly property string userState: NS.SystemdService.userState
readonly property int failedCount: NS.SystemdService.failedCount
property string systemState: "unknown"
property string userState: "unknown"
property var systemUnits: []
property var userUnits: []
readonly property int totalFailedCount: systemUnits.length + userUnits.length
// Parsed [{ name, description, subState, scope, machine }, ...]
readonly property var failedUnits: {
try {
return JSON.parse(NS.SystemdService.failedUnitsJson);
} catch (e) {
return [];
}
}
// Parsed [{ name, class, service, systemState, failedUnits: [...] }, ...]
readonly property var containers: {
try {
return JSON.parse(NS.SystemdService.containersJson);
} catch (e) {
return [];
}
}
function restartUnit(name, scope, machine) {
NS.SystemdService.restartUnit(name, scope ?? "system", machine ?? "");
}
signal journalReady(string unitName, bool isUser, string text)
function refresh() {
NS.SystemdService.poll();
if (!_pollProc.running)
_pollProc.running = true;
}
property Timer _pollTimer: Timer {
interval: {
const ms = NS.ModulesService.systemdInterval;
return ms > 0 ? ms : 15000;
// Per-fetch journal state: kept here (not on the Process) so qmllint can see them.
property string _journalUnitName: ""
property bool _journalIsUser: false
function fetchJournal(unitName, isUser) {
_journalProc.command = isUser ? ["journalctl", "--user", "-u", unitName, "-n", "80", "--no-pager", "--output=short-precise"] : ["journalctl", "-u", unitName, "-n", "80", "--no-pager", "--output=short-precise"];
root._journalUnitName = unitName;
root._journalIsUser = isUser;
if (_journalProc.running)
_journalProc.running = false;
_journalProc.running = true;
}
function restartUnit(unitName, isUser) {
_restartProc.command = isUser ? ["systemctl", "--user", "restart", unitName] : ["pkexec", "systemctl", "restart", unitName];
if (_restartProc.running)
_restartProc.running = false;
_restartProc.running = true;
}
function _parseState(json) {
try {
return JSON.parse(json).data || "unknown";
} catch (e) {
return "unknown";
}
}
function _parseUnits(json) {
try {
const parsed = JSON.parse(json);
return (parsed.data?.[0] || []).map(u => ({
name: u[0],
description: u[1],
loadState: u[2],
activeState: u[3],
subState: u[4]
}));
} catch (e) {
return [];
}
}
property Timer _poll: Timer {
interval: NS.ModulesService.systemdInterval ?? 15000
running: NS.ModulesService.systemdEnable
repeat: true
triggeredOnStart: false
onTriggered: NS.SystemdService.poll()
triggeredOnStart: true
onTriggered: if (!root._pollProc.running)
root._pollProc.running = true
}
// 4 lines of output: systemState, systemUnits, userState, userUnits
property Process _pollProc: Process {
command: ["sh", "-c", "busctl get-property --json=short org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager SystemState 2>/dev/null || echo '{}'; " + "busctl call --json=short org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager ListUnitsFiltered as 1 failed 2>/dev/null || echo '{}'; " + "busctl --user get-property --json=short org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager SystemState 2>/dev/null || echo '{}'; " + "busctl --user call --json=short org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager ListUnitsFiltered as 1 failed 2>/dev/null || echo '{}'"]
stdout: StdioCollector {
onStreamFinished: {
const lines = text.trim().split("\n");
root.systemState = root._parseState(lines[0] ?? "");
root.systemUnits = root._parseUnits(lines[1] ?? "");
root.userState = root._parseState(lines[2] ?? "");
root.userUnits = root._parseUnits(lines[3] ?? "");
}
}
}
property Process _journalProc: Process {
stdout: StdioCollector {
onStreamFinished: root.journalReady(root._journalUnitName, root._journalIsUser, text)
}
}
property Process _restartProc: Process {
onRunningChanged: if (!running)
root.refresh()
}
}

View file

@ -8,6 +8,7 @@ singleton CpuService 1.0 CpuService.qml
singleton DockState 1.0 DockState.qml
singleton IdleInhibitService 1.0 IdleInhibitService.qml
singleton LockService 1.0 LockService.qml
singleton MachinectlService 1.0 MachinectlService.qml
singleton MprisService 1.0 MprisService.qml
singleton NetworkService 1.0 NetworkService.qml
singleton NiriIpc 1.0 NiriIpc.qml

View file

@ -36,6 +36,14 @@ shell/applets/HexWaveBackground.qml: Type "QColor" of property "base0E" not foun
shell/applets/HoverableListItem.qml: Type "QColor" of property "base02" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/InfoRow.qml: Type "QColor" of property "base04" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/InfoRow.qml: Type "QColor" of property "base05" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/MachinectlApplet.qml: Type "QColor" of property "base00" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/MachinectlApplet.qml: Type "QColor" of property "base02" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/MachinectlApplet.qml: Type "QColor" of property "base03" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/MachinectlApplet.qml: Type "QColor" of property "base04" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/MachinectlApplet.qml: Type "QColor" of property "base05" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/MachinectlApplet.qml: Type "QColor" of property "base08" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/MachinectlApplet.qml: Type "QColor" of property "base0A" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/MachinectlApplet.qml: Type "QColor" of property "base0B" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/MemoryApplet.qml: Type "QColor" of property "base02" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/MemoryApplet.qml: Type "QColor" of property "base03" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/MemoryApplet.qml: Type "QColor" of property "base0D" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
@ -70,14 +78,13 @@ shell/applets/PowerApplet.qml: Type "QColor" of property "base0D" not found. Thi
shell/applets/PowerApplet.qml: Type "QColor" of property "base0E" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/PowerApplet.qml: Unqualified access [unqualified]
shell/applets/Separator.qml: Type "QColor" of property "base03" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/SystemdMachineSection.qml: Type "QColor" of property "base00" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/SystemdMachineSection.qml: Type "QColor" of property "base02" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/SystemdMachineSection.qml: Type "QColor" of property "base04" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/SystemdMachineSection.qml: Type "QColor" of property "base05" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/SystemdMachineSection.qml: Type "QColor" of property "base08" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/SystemdMachineSection.qml: Type "QColor" of property "base0A" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/SystemdMachineSection.qml: Type "QColor" of property "base0B" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/SystemdApplet.qml: Type "QColor" of property "base00" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/SystemdApplet.qml: Type "QColor" of property "base03" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/SystemdApplet.qml: Type "QColor" of property "base08" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/SystemdApplet.qml: Type "QColor" of property "base0A" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/SystemdApplet.qml: Type "QColor" of property "base0B" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/SystemdUnitRow.qml: Type "QColor" of property "base00" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/SystemdUnitRow.qml: Type "QColor" of property "base01" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/SystemdUnitRow.qml: Type "QColor" of property "base02" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/SystemdUnitRow.qml: Type "QColor" of property "base04" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/applets/SystemdUnitRow.qml: Type "QColor" of property "base05" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
@ -175,6 +182,7 @@ shell/modules/HoverPanel.qml: Type PanelWindow is not creatable. [uncreatable-ty
shell/modules/HoverPanel.qml: Type margins is used but it is not resolved [unresolved-type]
shell/modules/HoverPanel.qml: unknown grouped property scope margins. [unqualified]
shell/modules/IdleInhibitorModule.qml: Type "QColor" of property "base09" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/MachinectlModule.qml: Type "QColor" of property "base0A" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/MemoryModule.qml: Unqualified access [unqualified]
shell/modules/MprisModule.qml: Unqualified access [unqualified]
shell/modules/NetworkModule.qml: Type "QColor" of property "base08" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
@ -210,6 +218,7 @@ shell/modules/ScreenCorners.qml: Type PanelWindow is not creatable. [uncreatable
shell/modules/ScreenCorners.qml: Type margins is used but it is not resolved [unresolved-type]
shell/modules/ScreenCorners.qml: Unqualified access [unqualified]
shell/modules/ScreenCorners.qml: unknown grouped property scope margins. [unqualified]
shell/modules/SystemdModule.qml: Type "QColor" of property "base08" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/SystemdModule.qml: Type "QColor" of property "base0A" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/TemperatureModule.qml: Type "QColor" of property "base08" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]
shell/modules/TemperatureModule.qml: Type "QColor" of property "base0A" not found. This is likely due to a missing dependency entry or a type not being exposed declaratively. [unresolved-type]