git.lucas.co / cce-status-interface
status bar
git clone https://git.lucas.co/cce-status-interface.git

commit01461691bd5076b1f38e2e36ec2c9497f1bcaffb
parent0b2d4f46f0
authorLucas Galante <[email protected]>
date2026-05-28 15:41
Update system configuration and interface modules

 Cargo.lock               | 228 ++++++++++++++++++++++++++++++-
 Cargo.toml               |   3 +
 src/bin/check_metrics.rs |  15 +++
 src/bin/dbus_test.rs     | 285 +++++++++++++++++++--------------------
 src/main.rs              | 340 ++++++++++++++++++++++++++++++++++++++++-------
 5 files changed, 671 insertions(+), 200 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index ad8cf0c..4b729e3 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -17,6 +17,12 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "arrayref"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb"
+
 [[package]]
 name = "arrayvec"
 version = "0.7.6"
@@ -186,6 +192,12 @@ version = "1.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
 
+[[package]]
+name = "base64"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+
 [[package]]
 name = "bit-set"
 version = "0.8.0"
@@ -350,6 +362,7 @@ dependencies = [
  "png",
  "pollster",
  "raw-window-handle",
+ "resvg",
  "serde",
  "serde_json",
  "smithay-client-toolkit",
@@ -371,6 +384,7 @@ dependencies = [
  "glyphon",
  "pollster",
  "raw-window-handle",
+ "resvg",
  "smithay-client-toolkit",
  "tokio",
  "wayland-client",
@@ -388,6 +402,12 @@ dependencies = [
  "unicode-width",
 ]
 
+[[package]]
+name = "color_quant"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
+
 [[package]]
 name = "concurrent-queue"
 version = "2.5.0"
@@ -436,7 +456,7 @@ dependencies = [
  "rangemap",
  "rayon",
  "rustc-hash 1.1.0",
- "rustybuzz",
+ "rustybuzz 0.14.1",
  "self_cell",
  "swash",
  "sys-locale",
@@ -506,6 +526,12 @@ version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f"
 
+[[package]]
+name = "data-url"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be1e0bca6c3637f992fc1cc7cbc52a78c1ef6db076dbf1059c4323d6a2048376"
+
 [[package]]
 name = "digest"
 version = "0.10.7"
@@ -660,6 +686,12 @@ dependencies = [
  "miniz_oxide",
 ]
 
+[[package]]
+name = "float-cmp"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4"
+
 [[package]]
 name = "foldhash"
 version = "0.1.5"
@@ -681,7 +713,7 @@ version = "0.5.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bbc773e24e02d4ddd8395fd30dc147524273a83e54e0f312d986ea30de5f5646"
 dependencies = [
- "roxmltree",
+ "roxmltree 0.20.0",
 ]
 
 [[package]]
@@ -810,6 +842,16 @@ dependencies = [
  "wasip2",
 ]
 
+[[package]]
+name = "gif"
+version = "0.13.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ae047235e33e2829703574b54fdec96bfbad892062d97fed2f76022287de61b"
+dependencies = [
+ "color_quant",
+ "weezl",
+]
+
 [[package]]
 name = "gl_generator"
 version = "0.14.0"
@@ -969,6 +1011,12 @@ dependencies = [
  "cc",
 ]
 
+[[package]]
+name = "imagesize"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "029d73f573d8e8d63e6d5020011d3255b28c3ba85d6cf870a07184ed23de9284"
+
 [[package]]
 name = "indexmap"
 version = "2.14.0"
@@ -1013,6 +1061,12 @@ dependencies = [
  "syn",
 ]
 
+[[package]]
+name = "jpeg-decoder"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00810f1d8b74be64b13dbf3db89ac67740615d6c891f0e7b6179326533011a07"
+
 [[package]]
 name = "js-sys"
 version = "0.3.99"
@@ -1042,6 +1096,17 @@ version = "3.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
 
+[[package]]
+name = "kurbo"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c62026ae44756f8a599ba21140f350303d4f08dcdcc71b5ad9c9bb8128c13c62"
+dependencies = [
+ "arrayvec",
+ "euclid",
+ "smallvec",
+]
+
 [[package]]
 name = "libc"
 version = "0.2.186"
@@ -1303,6 +1368,12 @@ version = "1.0.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
 
+[[package]]
+name = "pico-args"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315"
+
 [[package]]
 name = "pin-project-lite"
 version = "0.2.17"
@@ -1515,6 +1586,38 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832"
 
+[[package]]
+name = "resvg"
+version = "0.41.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2327ced609dadeed3e9702fec3e6b2ddd208758a9268d13e06566c6101ba533"
+dependencies = [
+ "gif",
+ "jpeg-decoder",
+ "log",
+ "pico-args",
+ "png",
+ "rgb",
+ "svgtypes",
+ "tiny-skia",
+ "usvg",
+]
+
+[[package]]
+name = "rgb"
+version = "0.8.53"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47b34b781b31e5d73e9fbc8689c70551fd1ade9a19e3e28cfec8580a79290cc4"
+dependencies = [
+ "bytemuck",
+]
+
+[[package]]
+name = "roxmltree"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3cd14fd5e3b777a7422cca79358c57a8f6e3a703d9ac187448d0daf220c2407f"
+
 [[package]]
 name = "roxmltree"
 version = "0.20.0"
@@ -1565,6 +1668,22 @@ version = "1.0.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
 
+[[package]]
+name = "rustybuzz"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88117946aa1bfb53c2ae0643ceac6506337f44887f8c9fbfb43587b1cc52ba49"
+dependencies = [
+ "bitflags 2.11.1",
+ "bytemuck",
+ "smallvec",
+ "ttf-parser 0.20.0",
+ "unicode-bidi-mirroring",
+ "unicode-ccc",
+ "unicode-properties",
+ "unicode-script",
+]
+
 [[package]]
 name = "rustybuzz"
 version = "0.14.1"
@@ -1687,6 +1806,21 @@ version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214"
 
+[[package]]
+name = "simplecss"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a9c6883ca9c3c7c90e888de77b7a5c849c779d25d74a1269b0218b14e8b136c"
+dependencies = [
+ "log",
+]
+
+[[package]]
+name = "siphasher"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649"
+
 [[package]]
 name = "skrifa"
 version = "0.22.3"
@@ -1771,6 +1905,15 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
 
+[[package]]
+name = "strict-num"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
+dependencies = [
+ "float-cmp",
+]
+
 [[package]]
 name = "strum"
 version = "0.26.3"
@@ -1799,6 +1942,16 @@ version = "0.4.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0193cc4331cfd2f3d2011ef287590868599a2f33c3e69bc22c1a3d3acf9e02fb"
 
+[[package]]
+name = "svgtypes"
+version = "0.15.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68c7541fff44b35860c1a7a47a7cadf3e4a304c457b58f9870d9706ece028afc"
+dependencies = [
+ "kurbo",
+ "siphasher",
+]
+
 [[package]]
 name = "swash"
 version = "0.1.19"
@@ -1892,6 +2045,32 @@ dependencies = [
  "syn",
 ]
 
+[[package]]
+name = "tiny-skia"
+version = "0.11.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab"
+dependencies = [
+ "arrayref",
+ "arrayvec",
+ "bytemuck",
+ "cfg-if",
+ "log",
+ "png",
+ "tiny-skia-path",
+]
+
+[[package]]
+name = "tiny-skia-path"
+version = "0.11.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93"
+dependencies = [
+ "arrayref",
+ "bytemuck",
+ "strict-num",
+]
+
 [[package]]
 name = "tinyvec"
 version = "1.11.0"
@@ -2084,6 +2263,12 @@ version = "1.13.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c"
 
+[[package]]
+name = "unicode-vo"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94"
+
 [[package]]
 name = "unicode-width"
 version = "0.1.14"
@@ -2096,6 +2281,33 @@ version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
 
+[[package]]
+name = "usvg"
+version = "0.41.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c704361d822337cfc00387672c7b59eaa72a1f0744f62b2a68aa228a0c6927d"
+dependencies = [
+ "base64",
+ "data-url",
+ "flate2",
+ "fontdb",
+ "imagesize",
+ "kurbo",
+ "log",
+ "pico-args",
+ "roxmltree 0.19.0",
+ "rustybuzz 0.13.0",
+ "simplecss",
+ "siphasher",
+ "strict-num",
+ "svgtypes",
+ "tiny-skia-path",
+ "unicode-bidi",
+ "unicode-script",
+ "unicode-vo",
+ "xmlwriter",
+]
+
 [[package]]
 name = "version_check"
 version = "0.9.5"
@@ -2277,6 +2489,12 @@ dependencies = [
  "wasm-bindgen",
 ]
 
+[[package]]
+name = "weezl"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88"
+
 [[package]]
 name = "wgpu"
 version = "24.0.5"
@@ -2666,6 +2884,12 @@ version = "0.8.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f"
 
+[[package]]
+name = "xmlwriter"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9"
+
 [[package]]
 name = "yazi"
 version = "0.1.6"
diff --git a/Cargo.toml b/Cargo.toml
index dad0cb6..a0547ef 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -21,9 +21,12 @@ serde_json = "1"
 chrono = "0.4"
 tokio-stream = "0.1"
 zbus = "4"
+resvg = "0.41.0"
 png = "0.17"
 
 
 
 
 
+
+
diff --git a/src/bin/check_metrics.rs b/src/bin/check_metrics.rs
new file mode 100644
index 0000000..b6ea506
--- /dev/null
+++ b/src/bin/check_metrics.rs
@@ -0,0 +1,15 @@
+use glyphon::{FontSystem, Buffer, Metrics, Attrs, Shaping};
+
+fn main() {
+    let mut font_system = FontSystem::new();
+    let font_size = 11.0;
+    let metrics = Metrics::new(font_size, font_size * 1.4);
+    let mut buffer = Buffer::new(&mut font_system, metrics);
+    let attrs = Attrs::new().family(glyphon::Family::Name("Berkeley Mono"));
+    buffer.set_text(&mut font_system, "Vol 0%", attrs, Shaping::Advanced);
+    buffer.shape_until_scroll(&mut font_system, true);
+
+    for run in buffer.layout_runs() {
+        println!("line_y: {}, line_w: {}", run.line_y, run.line_w);
+    }
+}
diff --git a/src/bin/dbus_test.rs b/src/bin/dbus_test.rs
index ab20bd3..dd29326 100644
--- a/src/bin/dbus_test.rs
+++ b/src/bin/dbus_test.rs
@@ -1,53 +1,8 @@
 use zbus::{proxy, Connection};
-
-#[derive(Debug, Clone)]
-pub struct NotifierAddress {
-    pub destination: String,
-    pub path: String,
-}
-
-impl NotifierAddress {
-    pub fn from_notifier_service(service: &str, sender: &str) -> Result<Self, String> {
-        if service.starts_with('/') {
-            Ok(NotifierAddress {
-                destination: sender.to_string(),
-                path: service.to_string(),
-            })
-        } else if let Some((destination, path)) = service.split_once('/') {
-            Ok(NotifierAddress {
-                destination: destination.to_string(),
-                path: format!("/{}", path),
-            })
-        } else if service.contains(':') {
-            let split = service.split(':').collect::<Vec<&str>>();
-            Ok(NotifierAddress {
-                destination: format!(":{}", split[1]),
-                path: "/StatusNotifierItem".to_string(),
-            })
-        } else {
-            Ok(NotifierAddress {
-                destination: service.to_string(),
-                path: "/StatusNotifierItem".to_string(),
-            })
-        }
-    }
-}
-
-#[derive(Debug, Clone)]
-pub struct TrayPixmap {
-    pub width: i32,
-    pub height: i32,
-    pub pixels: Vec<u8>,
-}
-
-#[derive(Debug, Clone)]
-pub struct TrayItem {
-    pub id: String,
-    pub icon_name: Option<String>,
-    pub icon_theme_path: Option<String>,
-    pub pixmaps: Option<Vec<TrayPixmap>>,
-    pub title: Option<String>,
-}
+use std::collections::HashMap;
+use zbus::zvariant::{OwnedValue, Value};
+use std::process::{Command, Stdio};
+use std::io::Write;
 
 #[proxy(
     interface = "org.kde.StatusNotifierItem",
@@ -55,127 +10,159 @@ pub struct TrayItem {
 )]
 trait StatusNotifierItem {
     #[zbus(property)]
-    fn id(&self) -> zbus::Result<String>;
-
-    #[zbus(property)]
-    fn category(&self) -> zbus::Result<String>;
-
-    #[zbus(property)]
-    fn status(&self) -> zbus::Result<String>;
+    fn item_is_menu(&self) -> zbus::Result<bool>;
 
     #[zbus(property)]
-    fn title(&self) -> zbus::Result<String>;
-
-    #[zbus(property)]
-    fn icon_name(&self) -> zbus::Result<String>;
-
-    #[zbus(property)]
-    fn icon_theme_path(&self) -> zbus::Result<String>;
-
-    #[zbus(property)]
-    fn icon_pixmap(&self) -> zbus::Result<Vec<(i32, i32, Vec<u8>)>>;
+    fn menu(&self) -> zbus::Result<zbus::zvariant::OwnedObjectPath>;
 }
 
 #[proxy(
-    interface = "org.kde.StatusNotifierWatcher",
-    default_path = "/StatusNotifierWatcher"
+    interface = "com.canonical.dbusmenu",
+    default_path = "/StatusNotifierItem/menu"
 )]
-trait StatusNotifierWatcher {
-    #[zbus(property)]
-    fn registered_status_notifier_items(&self) -> zbus::Result<Vec<String>>;
+trait DBusMenu {
+    fn get_layout(
+        &self,
+        parent_id: i32,
+        recursion_depth: i32,
+        property_names: Vec<String>,
+    ) -> zbus::Result<(u32, (i32, HashMap<String, OwnedValue>, Vec<OwnedValue>))>;
+
+    fn event(
+        &self,
+        id: i32,
+        event_id: &str,
+        data: &zbus::zvariant::Value<'_>,
+        timestamp: u32,
+    ) -> zbus::Result<()>;
+
+    fn about_to_show(&self, id: i32) -> zbus::Result<bool>;
 }
 
-async fn fetch_tray_item(conn: &Connection, addr: &NotifierAddress) -> Result<TrayItem, zbus::Error> {
-    let proxy = StatusNotifierItemProxy::builder(conn)
-        .destination(addr.destination.clone())?
-        .path(addr.path.clone())?
-        .build()
-        .await?;
-
-    println!("Querying properties for destination='{}', path='{}'...", addr.destination, addr.path);
-    
-    let id_res = proxy.id().await;
-    println!("  id result: {:?}", id_res);
-    
-    let category_res = proxy.category().await;
-    println!("  category result: {:?}", category_res);
-
-    let status_res = proxy.status().await;
-    println!("  status result: {:?}", status_res);
-
-    let icon_name_res = proxy.icon_name().await;
-    println!("  icon_name result: {:?}", icon_name_res);
-
-    let icon_theme_path_res = proxy.icon_theme_path().await;
-    println!("  icon_theme_path result: {:?}", icon_theme_path_res);
-
-    let title_res = proxy.title().await;
-    println!("  title result: {:?}", title_res);
-
-    let pixmap_res = proxy.icon_pixmap().await;
-    println!("  pixmap result: ({} pixmaps or error: {:?})", 
-        pixmap_res.as_ref().map(|v| v.len()).unwrap_or(0),
-        pixmap_res.as_ref().err()
-    );
-
-    let id = format!("{}/{}", addr.destination, addr.path.trim_start_matches('/'));
-    let icon_name = icon_name_res.ok();
-    let icon_theme_path = icon_theme_path_res.ok();
-    let title = title_res.ok();
+fn flatten_menu(
+    id: i32,
+    mut properties: HashMap<String, OwnedValue>,
+    children: Vec<OwnedValue>,
+    prefix: &str,
+    out: &mut Vec<(i32, String)>
+) {
+    let label: String = properties.remove("label")
+        .and_then(|v| {
+            let s: Result<String, _> = v.try_into();
+            s.ok()
+        })
+        .unwrap_or_default();
+    let type_: String = properties.remove("type")
+        .and_then(|v| {
+            let s: Result<String, _> = v.try_into();
+            s.ok()
+        })
+        .unwrap_or_default();
+    let enabled: bool = properties.remove("enabled")
+        .and_then(|v| {
+            let b: Result<bool, _> = v.try_into();
+            b.ok()
+        })
+        .unwrap_or(true);
+
+    if type_ == "separator" || !enabled {
+        // Skip separator or disabled items
+    } else {
+        let current_path = if prefix.is_empty() {
+            label.clone()
+        } else if !label.is_empty() {
+            format!("{} > {}", prefix, label)
+        } else {
+            prefix.to_string()
+        };
 
-    let pixmaps = pixmap_res.ok().map(|v| {
-        v.into_iter()
-            .map(|(w, h, pixels)| TrayPixmap {
-                width: w,
-                height: h,
-                pixels,
-            })
-            .collect()
-    });
+        if !current_path.is_empty() && children.is_empty() {
+            out.push((id, current_path.clone()));
+        }
 
-    Ok(TrayItem {
-        id,
-        icon_name,
-        icon_theme_path,
-        pixmaps,
-        title,
-    })
+        for child_val in children {
+            let child_val_inner = zbus::zvariant::Value::from(child_val);
+            if let Ok(child) = <(i32, HashMap<String, OwnedValue>, Vec<OwnedValue>)>::try_from(child_val_inner) {
+                flatten_menu(child.0, child.1, child.2, &current_path, out);
+            }
+        }
+    }
 }
 
 #[tokio::main]
 async fn main() -> Result<(), Box<dyn std::error::Error>> {
     let conn = Connection::session().await?;
     
-    let watcher_proxy = StatusNotifierWatcherProxy::builder(&conn)
-        .destination("org.kde.StatusNotifierWatcher")?
-        .path("/StatusNotifierWatcher")?
+    let destination = "org.kde.StatusNotifierItem-997-1";
+    let path = "/StatusNotifierItem";
+    
+    println!("Connecting to StatusNotifierItem at destination='{}', path='{}'...", destination, path);
+    let sni_proxy = StatusNotifierItemProxy::builder(&conn)
+        .destination(destination)?
+        .path(path)?
         .build()
         .await?;
         
-    let items = watcher_proxy.registered_status_notifier_items().await?;
-    println!("Registered status notifier items from watcher: {:?}", items);
-
-    for item in items {
-        println!("======================================");
-        // An item string can be like ":1.5631/org/ayatana/NotificationItem/dropbox_client_1112673"
-        // Let's parse it using split_once('/')
-        let addr = if let Some((destination, path)) = item.split_once('/') {
-            NotifierAddress {
-                destination: destination.to_string(),
-                path: format!("/{}", path),
-            }
-        } else {
-            NotifierAddress {
-                destination: item.clone(),
-                path: "/StatusNotifierItem".to_string(),
-            }
-        };
+    let is_menu = sni_proxy.item_is_menu().await.unwrap_or(false);
+    let menu_path = sni_proxy.menu().await?;
+    
+    println!("is_menu: {}, menu_path: {}", is_menu, menu_path.as_str());
+    
+    let menu_proxy = DBusMenuProxy::builder(&conn)
+        .destination(destination)?
+        .path(menu_path.as_str())?
+        .build()
+        .await?;
         
-        match fetch_tray_item(&conn, &addr).await {
-            Ok(item) => println!("SUCCESS: {:?}", item.id),
-            Err(e) => println!("ERROR for {}: {:?}", item, e),
+    // Call about_to_show
+    let _ = menu_proxy.about_to_show(0).await;
+    
+    let (revision, layout) = menu_proxy.get_layout(0, 3, vec![]).await?;
+    println!("Menu revision: {}", revision);
+    
+    let mut items = Vec::new();
+    flatten_menu(layout.0, layout.1, layout.2, "", &mut items);
+    
+    println!("Flattened items count: {}", items.len());
+    
+    // Format input for fuzzel
+    let mut fuzzel_input = String::new();
+    for (_, label) in &items {
+        fuzzel_input.push_str(label);
+        fuzzel_input.push('\n');
+    }
+    
+    // Spawn fuzzel
+    println!("Spawning fuzzel...");
+    let mut child = Command::new("fuzzel")
+        .args(["-dmenu", "-p", "Tray Menu:"])
+        .stdin(Stdio::piped())
+        .stdout(Stdio::piped())
+        .spawn()?;
+        
+    if let Some(mut stdin) = child.stdin.take() {
+        stdin.write_all(fuzzel_input.as_bytes())?;
+    }
+    
+    let output = child.wait_with_output()?;
+    if output.status.success() {
+        let selected = String::from_utf8_lossy(&output.stdout).trim().to_string();
+        println!("Selected: '{}'", selected);
+        if let Some((id, _)) = items.iter().find(|(_, label)| label == &selected) {
+            println!("Triggering event on item ID: {}", id);
+            let timestamp = std::time::SystemTime::now()
+                .duration_since(std::time::UNIX_EPOCH)
+                .unwrap_or_default()
+                .as_secs() as u32;
+            let val = Value::from("");
+            menu_proxy.event(*id, "clicked", &val, timestamp).await?;
+            println!("Event sent successfully!");
+        } else {
+            println!("Selection match not found in items list!");
         }
+    } else {
+        println!("Fuzzel was cancelled or failed");
     }
-
+    
     Ok(())
 }
diff --git a/src/main.rs b/src/main.rs
index 3a81811..f044f89 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -417,13 +417,14 @@ impl StatusApp {
 
     fn rebuild_layout(&mut self) {
         let font_family = read_status_font_from_config();
+        let font_size = read_status_font_size_from_config();
         let sw = self.width as f32;
         let sh = self.height as f32;
         let s = self.scale_factor as f32;
         let sw_logical = sw / s;
         let sh_logical = sh / s;
         let bar_h = 28.0;
-        eprintln!("[rebuild_layout] sw={}, sh={}, s={}, sw_logical={}, sh_logical={}, font_family={}", sw, sh, s, sw_logical, sh_logical, font_family);
+        eprintln!("[rebuild_layout] sw={}, sh={}, s={}, sw_logical={}, sh_logical={}, font_family={}, font_size={}", sw, sh, s, sw_logical, sh_logical, font_family, font_size);
 
         self.current_bg_color = read_bg_color_from_config().unwrap_or(color::STATUS_BG);
         eprintln!("[rebuild_layout] Using background color: {:?}", self.current_bg_color);
@@ -450,8 +451,8 @@ impl StatusApp {
         let tags = parse_tags(&self.tags);
         for (col, text) in tags {
             let label_str = format!(" {} ", text);
-            let label = Label::new_with_family(&mut self.font_system, &label_str, 11.0, col, &font_family);
-            let line_w = label.draw(&mut self.text_items, left_x, (bar_h - 11.0 * 1.4) / 2.0);
+            let label = Label::new_with_family(&mut self.font_system, &label_str, font_size, col, &font_family);
+            let line_w = label.draw(&mut self.text_items, left_x, (bar_h - font_size * 1.4) / 2.0);
             self.tag_bounds.push(TagBounds {
                 name: text.clone(),
                 x: left_x,
@@ -468,8 +469,8 @@ impl StatusApp {
         // 3. Layout Mode
         if !self.layout.is_empty() {
             let label_str = format!("[{}]", self.layout);
-            let label = Label::new_with_family(&mut self.font_system, &label_str, 11.0, color::TEXT_ACCENT, &font_family);
-            let line_w = label.draw(&mut self.text_items, left_x, (bar_h - 11.0 * 1.4) / 2.0);
+            let label = Label::new_with_family(&mut self.font_system, &label_str, font_size, color::TEXT_ACCENT, &font_family);
+            let line_w = label.draw(&mut self.text_items, left_x, (bar_h - font_size * 1.4) / 2.0);
             left_x += line_w + 16.0;
         }
 
@@ -479,26 +480,34 @@ impl StatusApp {
             if display_title.chars().count() > 40 {
                 display_title = display_title.chars().take(37).collect::<String>() + "...";
             }
-            let label = Label::new_with_family(&mut self.font_system, &display_title, 11.0, color::TEXT_FG, &font_family);
-            label.draw(&mut self.text_items, left_x, (bar_h - 11.0 * 1.4) / 2.0);
+            let label = Label::new_with_family(&mut self.font_system, &display_title, font_size, color::TEXT_FG, &font_family);
+            label.draw(&mut self.text_items, left_x, (bar_h - font_size * 1.4) / 2.0);
         }
 
         // 5. Right Side Stats (CPU, Mem, Bat, Clock)
         let mut right_x = sw_logical - 12.0;
         if let Some(ref stats) = self.stats {
+            let clock_w = 270.0;
+            let battery_w = 80.0;
+            let volume_w = 80.0;
+            let memory_w = 140.0;
+            let cpu_w = 90.0;
+
             // Clock
-            let label = Label::new_with_family(&mut self.font_system, &stats.clock, 11.0, color::TEXT_FG, &font_family);
-            right_x -= label.w;
-            eprintln!("[rebuild_layout] Clock: x={}, w={}", right_x, label.w);
-            label.draw(&mut self.text_items, right_x, (bar_h - 11.0 * 1.4) / 2.0);
+            let label = Label::new_with_family(&mut self.font_system, &stats.clock, font_size, color::TEXT_FG, &font_family);
+            right_x -= clock_w;
+            let draw_x = right_x + (clock_w - label.w); // right-aligned
+            eprintln!("[rebuild_layout] Clock: x={}, w={}", draw_x, label.w);
+            label.draw(&mut self.text_items, draw_x, (bar_h - font_size * 1.4) / 2.0);
 
             // Battery
             if !stats.battery.is_empty() {
                 right_x -= 16.0;
-                let label = Label::new_with_family(&mut self.font_system, &stats.battery, 11.0, color::TEXT_ACCENT, &font_family);
-                right_x -= label.w;
-                eprintln!("[rebuild_layout] Battery: x={}, w={}", right_x, label.w);
-                label.draw(&mut self.text_items, right_x, (bar_h - 11.0 * 1.4) / 2.0);
+                let label = Label::new_with_family(&mut self.font_system, &stats.battery, font_size, color::TEXT_ACCENT, &font_family);
+                right_x -= battery_w;
+                let draw_x = right_x; // left-aligned
+                eprintln!("[rebuild_layout] Battery: x={}, w={}", draw_x, label.w);
+                label.draw(&mut self.text_items, draw_x, (bar_h - font_size * 1.4) / 2.0);
             }
 
             // Volume
@@ -510,11 +519,11 @@ impl StatusApp {
                 } else {
                     color::TEXT_ACCENT
                 };
-                let label = Label::new_with_family(&mut self.font_system, &stats.volume, 11.0, color_val, &font_family)
+                let label = Label::new_with_family(&mut self.font_system, &stats.volume, font_size, color_val, &font_family)
                     .with_strikethrough(is_muted);
-                right_x -= label.w;
-                let start_x = right_x;
-                let start_y = (bar_h - 11.0 * 1.4) / 2.0;
+                right_x -= volume_w;
+                let start_x = right_x; // left-aligned
+                let start_y = (bar_h - font_size * 1.4) / 2.0;
                 eprintln!("[rebuild_layout] Volume: x={}, w={}, is_muted={}", start_x, label.w, is_muted);
                 if let Some((sx, sy, sw_rect, sh_rect, scol)) = label.strikethrough_rect(start_x, start_y, 1.0) {
                     eprintln!("[rebuild_layout] Strikethrough rect: sx={}, sy={}, sw={}, sh={}, scol={:?}", sx, sy, sw_rect, sh_rect, scol);
@@ -523,7 +532,7 @@ impl StatusApp {
                         y: sy,
                         w: sw_rect,
                         h: sh_rect,
-                        color: scol,
+                        color: color::to_linear(scol),
                     });
                 }
                 label.draw(&mut self.text_items, start_x, start_y);
@@ -531,17 +540,19 @@ impl StatusApp {
 
             // Memory
             right_x -= 16.0;
-            let label = Label::new_with_family(&mut self.font_system, &stats.memory, 11.0, color::TEXT_DIM, &font_family);
-            right_x -= label.w;
-            eprintln!("[rebuild_layout] Memory: x={}, w={}", right_x, label.w);
-            label.draw(&mut self.text_items, right_x, (bar_h - 11.0 * 1.4) / 2.0);
+            let label = Label::new_with_family(&mut self.font_system, &stats.memory, font_size, color::TEXT_DIM, &font_family);
+            right_x -= memory_w;
+            let draw_x = right_x; // left-aligned
+            eprintln!("[rebuild_layout] Memory: x={}, w={}", draw_x, label.w);
+            label.draw(&mut self.text_items, draw_x, (bar_h - font_size * 1.4) / 2.0);
 
             // CPU
             right_x -= 16.0;
-            let label = Label::new_with_family(&mut self.font_system, &stats.cpu, 11.0, color::TEXT_DIM, &font_family);
-            right_x -= label.w;
-            eprintln!("[rebuild_layout] CPU: x={}, w={}", right_x, label.w);
-            label.draw(&mut self.text_items, right_x, (bar_h - 11.0 * 1.4) / 2.0);
+            let label = Label::new_with_family(&mut self.font_system, &stats.cpu, font_size, color::TEXT_DIM, &font_family);
+            right_x -= cpu_w;
+            let draw_x = right_x; // left-aligned
+            eprintln!("[rebuild_layout] CPU: x={}, w={}", draw_x, label.w);
+            label.draw(&mut self.text_items, draw_x, (bar_h - font_size * 1.4) / 2.0);
         }
 
         // 5b. System Tray Icons (render to the left of the CPU/stats block)
@@ -558,6 +569,7 @@ impl StatusApp {
                 let y = (bar_h - icon_size) / 2.0;
 
                 // Record bounds for hit-testing
+                eprintln!("[rebuild_layout] Tray icon bounds: id={}, x={}, y={}, w={}, h={}", item.id, x, y, icon_size, icon_size);
                 self.tray_item_bounds.push(TrayIconBounds {
                     id: item.id.clone(),
                     x,
@@ -571,7 +583,8 @@ impl StatusApp {
                 let mut drawn_pixmap = false;
                 if let Some(ref pixmaps) = item.pixmaps {
                     if !pixmaps.is_empty() {
-                        if let Some(pixmap) = pixmaps.iter().min_by_key(|p| (p.width - 16).abs()) {
+                        let target_pixel_width = (icon_size * self.scale_factor as f32) as i32;
+                        if let Some(pixmap) = pixmaps.iter().min_by_key(|p| (p.width - target_pixel_width).abs()) {
                             if pixmap.width > 0 && pixmap.height > 0 {
                                 // Calculate average brightness of visible pixels to see if we need to recolor
                                 let mut total_brightness = 0.0;
@@ -599,8 +612,12 @@ impl StatusApp {
                                 };
                                 let recolor_light = avg_brightness < 0.35;
  
-                                let draw_w = 16;
-                                let draw_h = 16;
+                                let mut draw_w = pixmap.width;
+                                let mut draw_h = pixmap.height;
+                                if draw_w > 48 {
+                                    draw_w = 48;
+                                    draw_h = 48;
+                                }
                                 let pixel_w = icon_size / draw_w as f32;
                                 let pixel_h = icon_size / draw_h as f32;
                                 for row in 0..draw_h {
@@ -666,10 +683,10 @@ impl StatusApp {
                         "⚙"
                     };
 
-                    let buf = make_text_buffer(&mut self.font_system, symbol, 11.0, &font_family);
+                    let buf = make_text_buffer(&mut self.font_system, symbol, font_size, &font_family);
                     let tw = buf.layout_runs().next().map(|r| r.line_w).unwrap_or(0.0);
                     let tx = x + (icon_size - tw) / 2.0;
-                    let ty = y + (icon_size - 11.0 * 1.4) / 2.0;
+                    let ty = y + (icon_size - font_size * 1.4) / 2.0;
                     self.text_items.push(TextItem {
                         buffer: buf,
                         x: tx,
@@ -690,13 +707,13 @@ impl StatusApp {
         if let Some(ref hovered_id) = self.hovered_tray_item {
             if let Some(bound) = self.tray_item_bounds.iter().find(|b| &b.id == hovered_id) {
                 let tooltip_text = bound.title.as_deref().unwrap_or(bound.id.as_str());
-                let font_size = 10.0;
-                let buf = make_text_buffer(&mut self.font_system, tooltip_text, font_size, &font_family);
+                let tooltip_font_size = font_size - 1.0;
+                let buf = make_text_buffer(&mut self.font_system, tooltip_text, tooltip_font_size, &font_family);
                 let text_w = buf.layout_runs().next().map(|r| r.line_w).unwrap_or(0.0);
                 let padding = 6.0;
 
                 let tooltip_w = text_w + padding * 2.0;
-                let tooltip_w_h = font_size * 1.4 + padding * 2.0;
+                let tooltip_w_h = tooltip_font_size * 1.4 + padding * 2.0;
                 let tx = bound.x + (bound.w - tooltip_w) / 2.0;
                 let ty = bar_h + 4.0;
 
@@ -1036,6 +1053,7 @@ impl PointerHandler for AppState {
         use smithay_client_toolkit::seat::pointer::PointerEventKind;
         for event in events {
             let (x, y) = event.position;
+            eprintln!("[pointer] Event: pos=({:.1}, {:.1}), kind={:?}", x, y, event.kind);
             if let Some(ref mut st) = self.state {
                 st.cursor_pos = (x, y);
             }
@@ -1099,11 +1117,32 @@ impl PointerHandler for AppState {
                                                 .build()
                                                 .await
                                             {
-                                                if btn == 272 {
-                                                    println!("[tray-click] Calling Activate on {} at ({}, {})", id, cx_i, cy_i);
-                                                    let _ = proxy.activate(cx_i, cy_i).await;
+                                                let is_menu = proxy.item_is_menu().await.unwrap_or(false);
+                                                let menu_path = proxy.menu().await.ok();
+
+                                                let should_show_menu = (btn == 273 && menu_path.is_some())
+                                                    || (btn == 272 && is_menu && menu_path.is_some());
+
+                                                if should_show_menu {
+                                                    if let Some(menu_p) = menu_path {
+                                                        eprintln!("[tray-click] Displaying menu for {} at path {}", id, menu_p.as_str());
+                                                        if let Err(e) = show_clear_cloud_menu(&conn, destination, menu_p.as_str()).await {
+                                                            eprintln!("[tray-click] show_clear_cloud_menu failed: {:?}", e);
+                                                        }
+                                                    }
+                                                } else if btn == 272 {
+                                                    eprintln!("[tray-click] Calling Activate on {} at ({}, {})", id, cx_i, cy_i);
+                                                    if let Err(e) = proxy.activate(cx_i, cy_i).await {
+                                                        eprintln!("[tray-click] Activate failed: {:?}", e);
+                                                        if let Some(menu_p) = menu_path {
+                                                            eprintln!("[tray-click] Fallback: Displaying menu for {}", id);
+                                                            if let Err(e) = show_clear_cloud_menu(&conn, destination, menu_p.as_str()).await {
+                                                                eprintln!("[tray-click] Fallback show_clear_cloud_menu failed: {:?}", e);
+                                                            }
+                                                        }
+                                                    }
                                                 } else if btn == 273 {
-                                                    println!("[tray-click] Calling ContextMenu on {} at ({}, {})", id, cx_i, cy_i);
+                                                    eprintln!("[tray-click] Calling ContextMenu on {} at ({}, {})", id, cx_i, cy_i);
                                                     let _ = proxy.context_menu(cx_i, cy_i).await;
                                                 }
                                             }
@@ -1115,13 +1154,13 @@ impl PointerHandler for AppState {
                         }
 
                         if *button == 272 {
-                            println!("[tags-click] Mouse left click at logical: ({}, {})", cx, cy);
+                            eprintln!("[tags-click] Mouse left click at logical: ({}, {})", cx, cy);
                             for bound in &st.tag_bounds {
-                                println!("[tags-click] Checking Tag '{}' bounds: x=[{}..{}], y=[{}..{}]", 
+                                eprintln!("[tags-click] Checking Tag '{}' bounds: x=[{}..{}], y=[{}..{}]", 
                                     bound.name, bound.x, bound.x + bound.w, bound.y, bound.y + bound.h);
                                 if cx >= bound.x as f64 && cx <= (bound.x + bound.w) as f64
                                     && cy >= bound.y as f64 && cy <= (bound.y + bound.h) as f64 {
-                                    println!("[tags-click] Tag matched: {}", bound.name);
+                                    eprintln!("[tags-click] Tag matched: {}", bound.name);
                                     let name = bound.name.clone();
                                     std::thread::spawn(move || {
                                         let _ = std::process::Command::new("clearctl")
@@ -1283,7 +1322,11 @@ async fn spawn_status_listener(sub: &'static str, sender: calloop::channel::Send
     use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
     use tokio::net::UnixStream;
     loop {
-        if let Ok(mut stream) = UnixStream::connect("/tmp/clearwm-status.sock").await {
+        let socket_path = match std::env::var("WAYLAND_DISPLAY") {
+            Ok(display) => format!("/tmp/clearwm-status-{}.sock", display),
+            Err(_) => "/tmp/clearwm-status.sock".to_string(),
+        };
+        if let Ok(mut stream) = UnixStream::connect(&socket_path).await {
             if stream.write_all(format!("{}\n", sub).as_bytes()).await.is_ok() {
                 let mut reader = BufReader::new(stream);
                 let mut line = String::new();
@@ -1466,8 +1509,144 @@ trait StatusNotifierItem {
 
     fn activate(&self, x: i32, y: i32) -> zbus::Result<()>;
     fn context_menu(&self, x: i32, y: i32) -> zbus::Result<()>;
+
+    #[zbus(property)]
+    fn item_is_menu(&self) -> zbus::Result<bool>;
+
+    #[zbus(property)]
+    fn menu(&self) -> zbus::Result<zbus::zvariant::OwnedObjectPath>;
+}
+
+#[zbus::proxy(
+    interface = "com.canonical.dbusmenu",
+    default_path = "/StatusNotifierItem/menu"
+)]
+trait DBusMenu {
+    fn get_layout(
+        &self,
+        parent_id: i32,
+        recursion_depth: i32,
+        property_names: Vec<String>,
+    ) -> zbus::Result<(u32, (i32, std::collections::HashMap<String, zbus::zvariant::OwnedValue>, Vec<zbus::zvariant::OwnedValue>))>;
+
+    fn event(
+        &self,
+        id: i32,
+        event_id: &str,
+        data: &zbus::zvariant::Value<'_>,
+        timestamp: u32,
+    ) -> zbus::Result<()>;
+
+    fn about_to_show(&self, id: i32) -> zbus::Result<bool>;
+}
+
+fn flatten_menu(
+    id: i32,
+    mut properties: std::collections::HashMap<String, zbus::zvariant::OwnedValue>,
+    children: Vec<zbus::zvariant::OwnedValue>,
+    prefix: &str,
+    out: &mut Vec<(i32, String)>
+) {
+    let label: String = properties.remove("label")
+        .and_then(|v| {
+            let s: Result<String, _> = v.try_into();
+            s.ok()
+        })
+        .unwrap_or_default();
+    let type_: String = properties.remove("type")
+        .and_then(|v| {
+            let s: Result<String, _> = v.try_into();
+            s.ok()
+        })
+        .unwrap_or_default();
+    let enabled: bool = properties.remove("enabled")
+        .and_then(|v| {
+            let b: Result<bool, _> = v.try_into();
+            b.ok()
+        })
+        .unwrap_or(true);
+
+    if type_ == "separator" || !enabled {
+        // Skip
+    } else {
+        let current_path = if prefix.is_empty() {
+            label.clone()
+        } else if !label.is_empty() {
+            format!("{} > {}", prefix, label)
+        } else {
+            prefix.to_string()
+        };
+
+        if !current_path.is_empty() && children.is_empty() {
+            out.push((id, current_path.clone()));
+        }
+
+        for child_val in children {
+            let child_val_inner = zbus::zvariant::Value::from(child_val);
+            if let Ok(child) = <(i32, std::collections::HashMap<String, zbus::zvariant::OwnedValue>, Vec<zbus::zvariant::OwnedValue>)>::try_from(child_val_inner) {
+                flatten_menu(child.0, child.1, child.2, &current_path, out);
+            }
+        }
+    }
 }
 
+async fn show_clear_cloud_menu(conn: &zbus::Connection, destination: &str, menu_path: &str) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
+    let menu_proxy = DBusMenuProxy::builder(conn)
+        .destination(destination)?
+        .path(menu_path)?
+        .build()
+        .await?;
+
+    let _ = menu_proxy.about_to_show(0).await;
+    let (_, layout) = menu_proxy.get_layout(0, 3, vec![]).await?;
+    eprintln!("[tray-click] show_clear_cloud_menu layout: root_id={}, properties={:?}, children_len={}", layout.0, layout.1, layout.2.len());
+
+    let mut items = Vec::new();
+    flatten_menu(layout.0, layout.1, layout.2, "", &mut items);
+    eprintln!("[tray-click] show_clear_cloud_menu flattened items: {:?}", items);
+
+    if items.is_empty() {
+        eprintln!("[tray-click] show_clear_cloud_menu: items is empty, returning early");
+        return Ok(());
+    }
+
+    let mut clear_cloud_input = String::new();
+    for (_, label) in &items {
+        clear_cloud_input.push_str(label);
+        clear_cloud_input.push('\n');
+    }
+
+    let mut child = std::process::Command::new("clear-cloud")
+        .args(["--dmenu", "-p", "Tray Menu:"])
+        .stdin(std::process::Stdio::piped())
+        .stdout(std::process::Stdio::piped())
+        .stderr(std::process::Stdio::piped())
+        .spawn()?;
+
+    if let Some(mut stdin) = child.stdin.take() {
+        use std::io::Write;
+        stdin.write_all(clear_cloud_input.as_bytes())?;
+    }
+
+    let output = child.wait_with_output()?;
+    if output.status.success() {
+        let selected = String::from_utf8_lossy(&output.stdout).trim().to_string();
+        if let Some((id, _)) = items.iter().find(|(_, label)| label == &selected) {
+            let timestamp = std::time::SystemTime::now()
+                .duration_since(std::time::UNIX_EPOCH)
+                .unwrap_or_default()
+                .as_secs() as u32;
+            let val = zbus::zvariant::Value::from("");
+            let _ = menu_proxy.event(*id, "clicked", &val, timestamp).await;
+        }
+    } else {
+        let stderr_str = String::from_utf8_lossy(&output.stderr).trim().to_string();
+        eprintln!("[tray-click] clear-cloud failed with status: {:?}, stderr: {:?}", output.status, stderr_str);
+    }
+    Ok(())
+}
+
+
 fn find_icon_file(dir: &std::path::Path, icon_name: &str) -> Option<std::path::PathBuf> {
     if let Ok(entries) = std::fs::read_dir(dir) {
         for entry in entries.filter_map(Result::ok) {
@@ -1481,7 +1660,7 @@ fn find_icon_file(dir: &std::path::Path, icon_name: &str) -> Option<std::path::P
                     }
                 } else if file_type.is_file() {
                     if let Some(file_name) = path.file_name().and_then(|f| f.to_str()) {
-                        if file_name == format!("{}.png", icon_name) {
+                        if file_name == format!("{}.png", icon_name) || file_name == format!("{}.svg", icon_name) {
                             return Some(path);
                         }
                     }
@@ -1554,6 +1733,40 @@ fn load_png_as_pixmap(path: &std::path::Path) -> Option<TrayPixmap> {
     })
 }
 
+fn load_svg_as_pixmap(path: &std::path::Path) -> Option<TrayPixmap> {
+    let svg_data = std::fs::read(path).ok()?;
+    let opt = resvg::usvg::Options::default();
+    let fontdb = resvg::usvg::fontdb::Database::new();
+    let tree = resvg::usvg::Tree::from_data(&svg_data, &opt, &fontdb).ok()?;
+    
+    let target_w = 48;
+    let target_h = 48;
+    let mut pixmap = resvg::tiny_skia::Pixmap::new(target_w, target_h)?;
+    
+    let orig_w = tree.size().width();
+    let orig_h = tree.size().height();
+    let sx = target_w as f32 / orig_w;
+    let sy = target_h as f32 / orig_h;
+    let transform = resvg::tiny_skia::Transform::from_scale(sx, sy);
+    
+    resvg::render(&tree, transform, &mut pixmap.as_mut());
+    
+    let raw_pixels = pixmap.data();
+    let mut argb_pixels = Vec::with_capacity((target_w * target_h * 4) as usize);
+    for chunk in raw_pixels.chunks_exact(4) {
+        argb_pixels.push(chunk[3]); // A
+        argb_pixels.push(chunk[0]); // R
+        argb_pixels.push(chunk[1]); // G
+        argb_pixels.push(chunk[2]); // B
+    }
+    
+    Some(TrayPixmap {
+        width: target_w as i32,
+        height: target_h as i32,
+        pixels: argb_pixels,
+    })
+}
+
 fn resolve_icon_path(theme_path: Option<&str>, icon_name: &str) -> Option<std::path::PathBuf> {
     if icon_name.is_empty() {
         return None;
@@ -1586,28 +1799,36 @@ fn resolve_icon_path(theme_path: Option<&str>, icon_name: &str) -> Option<std::p
         "hicolor/24x24/status",
         "hicolor/32x32/status",
         "hicolor/48x48/status",
+        "hicolor/scalable/status",
         "hicolor/16x16/apps",
         "hicolor/22x22/apps",
         "hicolor/24x24/apps",
         "hicolor/32x32/apps",
         "hicolor/48x48/apps",
+        "hicolor/scalable/apps",
         "gnome/16x16/status",
         "gnome/22x22/status",
         "gnome/24x24/status",
         "gnome/32x32/status",
         "gnome/48x48/status",
+        "gnome/scalable/status",
         "gnome/16x16/apps",
         "gnome/22x22/apps",
         "gnome/24x24/apps",
         "gnome/32x32/apps",
         "gnome/48x48/apps",
+        "gnome/scalable/apps",
     ];
 
     for base in &search_dirs {
         for sub in &sub_paths {
-            let path = std::path::Path::new(base).join(sub).join(format!("{}.png", icon_name));
-            if path.exists() && path.is_file() {
-                return Some(path);
+            let path_png = std::path::Path::new(base).join(sub).join(format!("{}.png", icon_name));
+            if path_png.exists() && path_png.is_file() {
+                return Some(path_png);
+            }
+            let path_svg = std::path::Path::new(base).join(sub).join(format!("{}.svg", icon_name));
+            if path_svg.exists() && path_svg.is_file() {
+                return Some(path_svg);
             }
         }
         let base_path = std::path::Path::new(base);
@@ -1652,7 +1873,13 @@ async fn fetch_tray_item(conn: &zbus::Connection, addr: &NotifierAddress) -> Res
             println!("[status-tray] Trying to resolve theme icon for '{}' (theme path: {:?})", name, icon_theme_path);
             if let Some(icon_path) = resolve_icon_path(icon_theme_path.as_deref(), name) {
                 println!("[status-tray] Found icon file at {:?}", icon_path);
-                if let Some(pixmap) = load_png_as_pixmap(&icon_path) {
+                let ext = icon_path.extension().and_then(|e| e.to_str()).unwrap_or("");
+                let pixmap = if ext.eq_ignore_ascii_case("svg") {
+                    load_svg_as_pixmap(&icon_path)
+                } else {
+                    load_png_as_pixmap(&icon_path)
+                };
+                if let Some(pixmap) = pixmap {
                     println!("[status-tray] Successfully decoded icon file to pixmap (size: {}x{})", pixmap.width, pixmap.height);
                     pixmaps = Some(vec![pixmap]);
                 } else {
@@ -2004,6 +2231,21 @@ fn read_status_font_from_config() -> String {
     "sans-serif".to_string()
 }
 
+fn read_status_font_size_from_config() -> f32 {
+    let content = std::fs::read_to_string("/home/lsgalante/.config/clearwm/config.toml").unwrap_or_default();
+    for line in content.lines() {
+        let trimmed = line.trim();
+        if let Some(rest) = trimmed.strip_prefix("status_font_size") {
+            let rest = rest.trim_start_matches(|c: char| c == ' ' || c == '=' || c == '"');
+            if let Ok(val) = rest.trim_end_matches('"').trim().parse::<f32>() {
+                return val;
+            }
+        }
+    }
+    11.0
+}
+
+
 fn parse_font_for_alias(content: &str, alias: &str) -> Option<String> {
     let lines: Vec<&str> = content.lines().collect();
     for i in 0..lines.len() {