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

commit64232b1798a03c1621b5c4ae383ee0173b232047
parentf7272f93a5
authorLucas Galante <[email protected]>
date2026-05-24 17:04
Update components and system settings

 src/bin/test_read_volume.rs | 50 +++++++++++++++++++++++++++
 src/main.rs                 | 84 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 134 insertions(+)

diff --git a/src/bin/test_read_volume.rs b/src/bin/test_read_volume.rs
new file mode 100644
index 0000000..2d3ecb6
--- /dev/null
+++ b/src/bin/test_read_volume.rs
@@ -0,0 +1,50 @@
+#[tokio::main]
+async fn main() {
+    println!("Starting read_volume diagnostics...");
+    
+    let vol_res = tokio::process::Command::new("pactl")
+        .args(["get-sink-volume", "@DEFAULT_SINK@"])
+        .output()
+        .await;
+        
+    match &vol_res {
+        Ok(output) => {
+            println!("pactl get-sink-volume succeeded.");
+            println!("stdout: {:?}", String::from_utf8_lossy(&output.stdout));
+            println!("stderr: {:?}", String::from_utf8_lossy(&output.stderr));
+        }
+        Err(e) => {
+            println!("pactl get-sink-volume failed: {:?}", e);
+        }
+    }
+
+    let mute_res = tokio::process::Command::new("pactl")
+        .args(["get-sink-mute", "@DEFAULT_SINK@"])
+        .output()
+        .await;
+
+    match &mute_res {
+        Ok(output) => {
+            println!("pactl get-sink-mute succeeded.");
+            println!("stdout: {:?}", String::from_utf8_lossy(&output.stdout));
+            println!("stderr: {:?}", String::from_utf8_lossy(&output.stderr));
+        }
+        Err(e) => {
+            println!("pactl get-sink-mute failed: {:?}", e);
+        }
+    }
+
+    // Try parsing
+    if let Ok(vol_output) = vol_res {
+        let vol_str = String::from_utf8_lossy(&vol_output.stdout);
+        let mut pct = None;
+        if let Some(pos) = vol_str.find('%') {
+            let start = vol_str[..pos].rfind(|c: char| !c.is_ascii_digit()).map(|i| i + 1).unwrap_or(0);
+            println!("pos: {}, start: {}, substring: {:?}", pos, start, &vol_str[start..pos]);
+            if let Ok(num) = vol_str[start..pos].parse::<u32>() {
+                pct = Some(num);
+            }
+        }
+        println!("Parsed pct: {:?}", pct);
+    }
+}
diff --git a/src/main.rs b/src/main.rs
index eda6875..a4155cb 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -49,6 +49,7 @@ struct SystemStats {
     memory: String,
     cpu: String,
     battery: String,
+    volume: String,
 }
 
 #[derive(Debug, Clone)]
@@ -471,6 +472,32 @@ impl StatusApp {
                 });
             }
 
+            // Volume
+            if !stats.volume.is_empty() {
+                right_x -= 16.0 * s;
+                let buf = make_text_buffer(&mut self.font_system, &stats.volume, 11.0 * s);
+                let w = buf.layout_runs().next().map(|r| r.line_w).unwrap_or(0.0);
+                right_x -= w;
+                
+                let is_muted = stats.volume.starts_with('🔇');
+                let color_val = if is_muted {
+                    color::TEXT_DIM
+                } else {
+                    color::TEXT_ACCENT
+                };
+
+                self.text_items.push(TextItem {
+                    buffer: buf,
+                    x: right_x,
+                    y: (bar_h - 11.0 * s * 1.4) / 2.0,
+                    color: glyphon::Color::rgb(
+                        (color_val[0] * 255.0) as u8,
+                        (color_val[1] * 255.0) as u8,
+                        (color_val[2] * 255.0) as u8,
+                    ),
+                });
+            }
+
             // Memory
             right_x -= 16.0 * s;
             let buf = make_text_buffer(&mut self.font_system, &stats.memory, 11.0 * s);
@@ -930,9 +957,63 @@ async fn spawn_status_listener(sub: &'static str, proxy: EventLoopProxy<CustomEv
     }
 }
 
+async fn read_volume() -> Option<String> {
+    let vol_output = match tokio::process::Command::new("pactl")
+        .args(["get-sink-volume", "@DEFAULT_SINK@"])
+        .output()
+        .await
+    {
+        Ok(o) => o,
+        Err(e) => {
+            eprintln!("[read_volume] failed to spawn pactl: {:?}", e);
+            return None;
+        }
+    };
+    if !vol_output.status.success() {
+        eprintln!("[read_volume] pactl get-sink-volume exited with error: {:?}", String::from_utf8_lossy(&vol_output.stderr));
+        return None;
+    }
+    let vol_str = String::from_utf8_lossy(&vol_output.stdout);
+    
+    let mute_output = match tokio::process::Command::new("pactl")
+        .args(["get-sink-mute", "@DEFAULT_SINK@"])
+        .output()
+        .await
+    {
+        Ok(o) => o,
+        Err(e) => {
+            eprintln!("[read_volume] failed to spawn pactl mute: {:?}", e);
+            return None;
+        }
+    };
+    if !mute_output.status.success() {
+        eprintln!("[read_volume] pactl get-sink-mute exited with error: {:?}", String::from_utf8_lossy(&mute_output.stderr));
+        return None;
+    }
+    let mute_str = String::from_utf8_lossy(&mute_output.stdout);
+    let muted = mute_str.contains("yes");
+
+    let mut pct = None;
+    if let Some(pos) = vol_str.find('%') {
+        let start = vol_str[..pos].rfind(|c: char| !c.is_ascii_digit()).map(|i| i + 1).unwrap_or(0);
+        if let Ok(num) = vol_str[start..pos].parse::<u32>() {
+            pct = Some(num);
+        }
+    }
+
+    match (muted, pct) {
+        (true, Some(p)) => Some(format!("🔇 {}%", p)),
+        (true, None) => Some("🔇 Muted".to_string()),
+        (false, Some(p)) => Some(format!("🔊 {}%", p)),
+        (false, None) => Some("🔊 Vol".to_string()),
+    }
+}
+
 async fn spawn_system_stats(proxy: EventLoopProxy<CustomEvent>) {
+    eprintln!("[spawn_system_stats] Starting system stats loop!");
     let mut last_cpu = read_cpu_ticks().unwrap_or((0, 0));
     loop {
+        eprintln!("[spawn_system_stats] loop iteration start");
         let clock = chrono::Local::now().format("%A, %B %d, %Y %I:%M %p").to_string();
         let memory = read_memory_usage().unwrap_or_else(|| "Mem N/A".to_string());
         
@@ -951,13 +1032,16 @@ async fn spawn_system_stats(proxy: EventLoopProxy<CustomEvent>) {
         };
 
         let battery = read_battery().unwrap_or_default();
+        let volume = read_volume().await.unwrap_or_default();
 
         let stats = SystemStats {
             clock,
             memory,
             cpu: cpu_str,
             battery,
+            volume,
         };
+        eprintln!("[spawn_system_stats] stats: {:?}", stats);
         let _ = proxy.send_event(CustomEvent::SystemStatsUpdated(stats));
         tokio::time::sleep(std::time::Duration::from_secs(1)).await;
     }