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

commite4ec67d3bc5114601d469d0027054a99b80c38b2
parentc699a6110d
authorLucas Galante <[email protected]>
date2026-05-26 15:19
Update system configuration and interface modules

 src/bin/check_stride.rs          | 10 ++++++++
 src/bin/detect_text.rs           | 37 +++++++++++++++++++++++++++
 src/bin/draw_ascii.rs            | 37 +++++++++++++++++++++++++++
 src/bin/draw_ascii_grim.rs       | 32 ++++++++++++++++++++++++
 src/bin/find_text_box.rs         | 51 +++++++++++++++++++++++++++++++++++++
 src/bin/inspect_image_corners.rs | 24 ++++++++++++++++++
 src/bin/inspect_pixels.rs        | 27 ++++++++++++++++++++
 src/bin/list_unique_colors.rs    | 36 +++++++++++++++++++++++++++
 src/bin/verify_bg.rs             | 33 ++++++++++++++++++++++++
 src/bin/verify_pixels.rs         | 54 ++++++++++++++++++++++++++++++++++++++++
 src/main.rs                      | 27 ++++++++++++++++++--
 11 files changed, 366 insertions(+), 2 deletions(-)

diff --git a/src/bin/check_stride.rs b/src/bin/check_stride.rs
new file mode 100644
index 0000000..9f15a42
--- /dev/null
+++ b/src/bin/check_stride.rs
@@ -0,0 +1,10 @@
+use std::fs::File;
+
+fn main() {
+    let file = File::open("/home/lsgalante/.gemini/antigravity/brain/2aeef5fd-2989-49f9-a513-b732668c813b/current_screen_unified_2.png").unwrap();
+    let decoder = png::Decoder::new(file);
+    let reader = decoder.read_info().unwrap();
+    let info = reader.info();
+    println!("PNG Info: width={}, height={}, color_type={:?}, bit_depth={:?}, raw_bytes={}", 
+        info.width, info.height, info.color_type, info.bit_depth, info.raw_bytes());
+}
diff --git a/src/bin/detect_text.rs b/src/bin/detect_text.rs
new file mode 100644
index 0000000..3198920
--- /dev/null
+++ b/src/bin/detect_text.rs
@@ -0,0 +1,37 @@
+use std::fs::File;
+
+fn main() {
+    let file = File::open("/home/lsgalante/.gemini/antigravity/brain/2aeef5fd-2989-49f9-a513-b732668c813b/current_screen_unified_2.png").unwrap();
+    let decoder = png::Decoder::new(file);
+    let mut reader = decoder.read_info().unwrap();
+    let mut buf = vec![0; reader.output_buffer_size()];
+    let info = reader.next_frame(&mut buf).unwrap();
+    let width = info.width as usize;
+    let height = info.height as usize;
+    println!("Image size: {}x{}", width, height);
+
+    // Let's print ASCII representation of the region x = 3200..3840, y = 10..46 using horizontal difference
+    for y in 10..46 {
+        let mut row_chars = String::new();
+        for x in (3200..3840).step_by(2) {
+            let idx = (y * width + x) * 4;
+            let idx_prev = (y * width + (x - 2)) * 4;
+
+            let r = buf[idx] as i32;
+            let g = buf[idx + 1] as i32;
+            let b = buf[idx + 2] as i32;
+
+            let r_p = buf[idx_prev] as i32;
+            let g_p = buf[idx_prev + 1] as i32;
+            let b_p = buf[idx_prev + 2] as i32;
+
+            let diff = (r - r_p).abs() + (g - g_p).abs() + (b - b_p).abs();
+            if diff > 15 {
+                row_chars.push('#');
+            } else {
+                row_chars.push('.');
+            }
+        }
+        println!("{:2}: {}", y, row_chars);
+    }
+}
diff --git a/src/bin/draw_ascii.rs b/src/bin/draw_ascii.rs
new file mode 100644
index 0000000..fd24b60
--- /dev/null
+++ b/src/bin/draw_ascii.rs
@@ -0,0 +1,37 @@
+use std::fs::File;
+
+fn main() {
+    let file = File::open("/home/lsgalante/.gemini/antigravity/brain/2aeef5fd-2989-49f9-a513-b732668c813b/current_screen_unified.png").unwrap();
+    let decoder = png::Decoder::new(file);
+    let mut reader = decoder.read_info().unwrap();
+    let mut buf = vec![0; reader.output_buffer_size()];
+    let info = reader.next_frame(&mut buf).unwrap();
+    let width = info.width as usize;
+    let height = info.height as usize;
+    println!("Image size: {}x{}", width, height);
+
+    // Sample background pixel
+    let bg_idx = (20 * width + 100) * 4;
+    let bg_r = buf[bg_idx] as i32;
+    let bg_g = buf[bg_idx + 1] as i32;
+    let bg_b = buf[bg_idx + 2] as i32;
+    println!("Background color sampled at (100, 20): R={}, G={}, B={}", bg_r, bg_g, bg_b);
+
+    for y in (10..46).step_by(2) {
+        let mut row_chars = String::new();
+        for x in (2800..3840).step_by(2) {
+            let idx = (y * width + x) * 4;
+            let r = buf[idx] as i32;
+            let g = buf[idx + 1] as i32;
+            let b = buf[idx + 2] as i32;
+
+            let diff = (r - bg_r).abs() + (g - bg_g).abs() + (b - bg_b).abs();
+            if diff > 20 {
+                row_chars.push('#');
+            } else {
+                row_chars.push('.');
+            }
+        }
+        println!("{:2}: {}", y, row_chars);
+    }
+}
diff --git a/src/bin/draw_ascii_grim.rs b/src/bin/draw_ascii_grim.rs
new file mode 100644
index 0000000..a47bd8b
--- /dev/null
+++ b/src/bin/draw_ascii_grim.rs
@@ -0,0 +1,32 @@
+use std::fs::File;
+
+fn main() {
+    let file = File::open("/tmp/current_screen.png").unwrap();
+    let decoder = png::Decoder::new(file);
+    let mut reader = decoder.read_info().unwrap();
+    let mut buf = vec![0; reader.output_buffer_size()];
+    let info = reader.next_frame(&mut buf).unwrap();
+    let width = info.width as usize;
+    let height = info.height as usize;
+    let color_type = info.color_type;
+    println!("Image size: {}x{}, color_type: {:?}", width, height, color_type);
+
+    let bytes_per_pixel = match color_type {
+        png::ColorType::Rgb => 3,
+        png::ColorType::Rgba => 4,
+        png::ColorType::Grayscale => 1,
+        png::ColorType::GrayscaleAlpha => 2,
+        _ => panic!("Unsupported color type"),
+    };
+
+    // The actual status bar background color is R=69, G=69, B=89
+    let bg_r = 69;
+    let bg_g = 69;
+    let bg_b = 89;
+
+    println!("Strikethrough line pixels at y=30, x=3266..3344 (step by 8):");
+    for x in (3266..3344).step_by(8) {
+        let idx = (30 * width + x) * bytes_per_pixel;
+        println!("  x={}: R={}, G={}, B={}", x, buf[idx], buf[idx+1], buf[idx+2]);
+    }
+}
diff --git a/src/bin/find_text_box.rs b/src/bin/find_text_box.rs
new file mode 100644
index 0000000..5dc6617
--- /dev/null
+++ b/src/bin/find_text_box.rs
@@ -0,0 +1,51 @@
+use std::fs::File;
+
+fn main() {
+    let file = File::open("/home/lsgalante/.gemini/antigravity/brain/2aeef5fd-2989-49f9-a513-b732668c813b/current_screen_unified_2.png").unwrap();
+    let decoder = png::Decoder::new(file);
+    let mut reader = decoder.read_info().unwrap();
+    let mut buf = vec![0; reader.output_buffer_size()];
+    let info = reader.next_frame(&mut buf).unwrap();
+    let width = info.width as usize;
+    let bg_idx = (20 * width + 100) * 3;
+    let bg_r = buf[bg_idx] as i32;
+    let bg_g = buf[bg_idx + 1] as i32;
+    let bg_b = buf[bg_idx + 2] as i32;
+    println!("Background color sampled at (100, 20): R={}, G={}, B={}", bg_r, bg_g, bg_b);
+    
+    // Status bar is in y = 0..80
+    // Let's count non-background pixels in each column for y = 10..48
+    let mut col_intensity = vec![0; width];
+    for x in 0..width {
+        for y in 10..48 {
+            let idx = (y * width + x) * 3;
+            let r = buf[idx] as i32;
+            let g = buf[idx + 1] as i32;
+            let b = buf[idx + 2] as i32;
+            
+            let diff = (r - bg_r).abs() + (g - bg_g).abs() + (b - bg_b).abs();
+            if diff > 15 {
+                col_intensity[x] += 1;
+            }
+        }
+    }
+    
+    // Group columns into contiguous active segments
+    let mut in_segment = false;
+    let mut start_x = 0;
+    println!("Active segments in status bar (x from left to right):");
+    for x in 0..width {
+        let active = col_intensity[x] > 2; // threshold of 2 pixels
+        if active && !in_segment {
+            start_x = x;
+            in_segment = true;
+        } else if !active && in_segment {
+            let end_x = x - 1;
+            println!("  Segment at x = {}..{} (width = {})", start_x, end_x, end_x - start_x + 1);
+            in_segment = false;
+        }
+    }
+    if in_segment {
+        println!("  Segment at x = {}..{} (width = {})", start_x, width - 1, width - start_x);
+    }
+}
diff --git a/src/bin/inspect_image_corners.rs b/src/bin/inspect_image_corners.rs
new file mode 100644
index 0000000..fc0b3f0
--- /dev/null
+++ b/src/bin/inspect_image_corners.rs
@@ -0,0 +1,24 @@
+use std::fs::File;
+
+fn main() {
+    let file = File::open("/home/lsgalante/.gemini/antigravity/brain/2aeef5fd-2989-49f9-a513-b732668c813b/current_screen_unified.png").unwrap();
+    let decoder = png::Decoder::new(file);
+    let mut reader = decoder.read_info().unwrap();
+    let mut buf = vec![0; reader.output_buffer_size()];
+    let info = reader.next_frame(&mut buf).unwrap();
+    let width = info.width as usize;
+    let height = info.height as usize;
+    println!("Width: {}, Height: {}", width, height);
+
+    println!("Top row y=4 colors (x = 0, 100, 500, 1000, 2000, 3000, 3800):");
+    for x in &[0, 100, 500, 1000, 2000, 3000, 3800] {
+        let idx = (4 * width + x) * 4;
+        println!("x={}: R={}, G={}, B={}, A={}", x, buf[idx], buf[idx+1], buf[idx+2], buf[idx+3]);
+    }
+
+    println!("Row y=20 colors (x = 0, 100, 500, 1000, 2000, 3000, 3800):");
+    for x in &[0, 100, 500, 1000, 2000, 3000, 3800] {
+        let idx = (20 * width + x) * 4;
+        println!("x={}: R={}, G={}, B={}, A={}", x, buf[idx], buf[idx+1], buf[idx+2], buf[idx+3]);
+    }
+}
diff --git a/src/bin/inspect_pixels.rs b/src/bin/inspect_pixels.rs
new file mode 100644
index 0000000..043e37c
--- /dev/null
+++ b/src/bin/inspect_pixels.rs
@@ -0,0 +1,27 @@
+use std::fs::File;
+
+fn main() {
+    let file = File::open("/home/lsgalante/.gemini/antigravity/brain/2aeef5fd-2989-49f9-a513-b732668c813b/current_screen_3.png").unwrap();
+    let decoder = png::Decoder::new(file);
+    let mut reader = decoder.read_info().unwrap();
+    let mut buf = vec![0; reader.output_buffer_size()];
+    let info = reader.next_frame(&mut buf).unwrap();
+    
+    println!("Truly bright pixels for x = 3310..3390, y = 10..50:");
+    let mut found = 0;
+    for y in 10..50 {
+        for x in 3310..3390 {
+            let idx = (y * info.width as usize + x) * 4;
+            let r = buf[idx];
+            let g = buf[idx + 1];
+            let b = buf[idx + 2];
+            let a = buf[idx + 3];
+            
+            if r > 100 && g > 100 && b > 100 {
+                found += 1;
+                println!("y={}, x={}: R={}, G={}, B={}, A={}", y, x, r, g, b, a);
+            }
+        }
+    }
+    println!("Total truly bright pixels: {}", found);
+}
diff --git a/src/bin/list_unique_colors.rs b/src/bin/list_unique_colors.rs
new file mode 100644
index 0000000..884660e
--- /dev/null
+++ b/src/bin/list_unique_colors.rs
@@ -0,0 +1,36 @@
+use std::fs::File;
+use std::collections::HashMap;
+
+fn main() {
+    let file = File::open("/tmp/current_screen.png").unwrap();
+    let decoder = png::Decoder::new(file);
+    let mut reader = decoder.read_info().unwrap();
+    let mut buf = vec![0; reader.output_buffer_size()];
+    let info = reader.next_frame(&mut buf).unwrap();
+    let width = info.width as usize;
+    let bytes_per_pixel = match info.color_type {
+        png::ColorType::Rgb => 3,
+        png::ColorType::Rgba => 4,
+        _ => panic!("Unsupported color type"),
+    };
+
+    let mut color_counts = HashMap::new();
+    // Scan the window area: x from 12 to 1800 (physical), y from 68 to 2300 (physical)
+    for y in (68..2300).step_by(2) {
+        for x in (12..1800).step_by(2) {
+            let idx = (y * width + x) * bytes_per_pixel;
+            let r = buf[idx];
+            let g = buf[idx + 1];
+            let b = buf[idx + 2];
+            *color_counts.entry((r, g, b)).or_insert(0) += 1;
+        }
+    }
+
+    let mut sorted_colors: Vec<_> = color_counts.into_iter().collect();
+    sorted_colors.sort_by(|a, b| b.1.cmp(&a.1));
+
+    println!("Top 30 most common colors in the system interface window area:");
+    for (i, ((r, g, b), count)) in sorted_colors.iter().take(30).enumerate() {
+        println!("  #{}: R={}, G={}, B={} (count={})", i + 1, r, g, b, count);
+    }
+}
diff --git a/src/bin/verify_bg.rs b/src/bin/verify_bg.rs
new file mode 100644
index 0000000..38114e7
--- /dev/null
+++ b/src/bin/verify_bg.rs
@@ -0,0 +1,33 @@
+use std::fs::File;
+
+fn main() {
+    let file = File::open("/tmp/current_screen.png").expect("Failed to open screenshot");
+    let decoder = png::Decoder::new(file);
+    let mut reader = decoder.read_info().expect("Failed to read PNG info");
+    let mut buf = vec![0; reader.output_buffer_size()];
+    let info = reader.next_frame(&mut buf).expect("Failed to decode PNG frame");
+    let width = info.width as usize;
+    let height = info.height as usize;
+    let bytes_per_pixel = match info.color_type {
+        png::ColorType::Rgb => 3,
+        png::ColorType::Rgba => 4,
+        _ => panic!("Unsupported color type"),
+    };
+
+    let mut found = 0;
+    for y in 0..height {
+        for x in 0..width {
+            let idx = (y * width + x) * bytes_per_pixel;
+            let r = buf[idx];
+            let g = buf[idx + 1];
+            let b = buf[idx + 2];
+            if r < 30 && g < 30 && b > 50 {
+                found += 1;
+                if found <= 20 {
+                    println!("Pixel at ({}, {}): R={}, G={}, B={}", x, y, r, g, b);
+                }
+            }
+        }
+    }
+    println!("Total pixels matching: {}", found);
+}
diff --git a/src/bin/verify_pixels.rs b/src/bin/verify_pixels.rs
new file mode 100644
index 0000000..24bcf43
--- /dev/null
+++ b/src/bin/verify_pixels.rs
@@ -0,0 +1,54 @@
+use std::fs::File;
+
+fn main() {
+    let file = File::open("/home/lsgalante/.gemini/antigravity/brain/2aeef5fd-2989-49f9-a513-b732668c813b/current_screen_unified_2.png").unwrap();
+    let decoder = png::Decoder::new(file);
+    let mut reader = decoder.read_info().unwrap();
+    let mut buf = vec![0; reader.output_buffer_size()];
+    let info = reader.next_frame(&mut buf).unwrap();
+    let width = info.width as usize;
+
+    // Sample background at (100, 20)
+    let bg_idx = (20 * width + 100) * 3;
+    let bg_r = buf[bg_idx] as i32;
+    let bg_g = buf[bg_idx + 1] as i32;
+    let bg_b = buf[bg_idx + 2] as i32;
+    println!("Background color sampled at (100, 20): R={}, G={}, B={}", bg_r, bg_g, bg_b);
+
+    println!("Background color sampled at (3200, 20): R={}, G={}, B={}", buf[(20 * width + 3200) * 3], buf[(20 * width + 3200) * 3 + 1], buf[(20 * width + 3200) * 3 + 2]);
+    println!("Background color sampled at (1500, 20): R={}, G={}, B={}", buf[(20 * width + 1500) * 3], buf[(20 * width + 1500) * 3 + 1], buf[(20 * width + 1500) * 3 + 2]);
+
+    println!("Checking volume text region (x = 3264..3345, y = 12..44):");
+    let mut text_pixels = 0;
+    for y in 12..44 {
+        for x in 3264..3345 {
+            let idx = (y * width + x) * 3;
+            let r = buf[idx] as i32;
+            let g = buf[idx + 1] as i32;
+            let b = buf[idx + 2] as i32;
+
+            let diff = (r - bg_r).abs() + (g - bg_g).abs() + (b - bg_b).abs();
+            if diff > 15 {
+                text_pixels += 1;
+            }
+        }
+    }
+    println!("Found {} active pixels in volume region.", text_pixels);
+
+    // Let's also check a region that should be empty (e.g. x = 3200..3250, y = 12..44)
+    let mut empty_pixels = 0;
+    for y in 12..44 {
+        for x in 3200..3250 {
+            let idx = (y * width + x) * 3;
+            let r = buf[idx] as i32;
+            let g = buf[idx + 1] as i32;
+            let b = buf[idx + 2] as i32;
+
+            let diff = (r - bg_r).abs() + (g - bg_g).abs() + (b - bg_b).abs();
+            if diff > 15 {
+                empty_pixels += 1;
+            }
+        }
+    }
+    println!("Found {} active pixels in empty region.", empty_pixels);
+}
diff --git a/src/main.rs b/src/main.rs
index 0ecf64f..9d924d7 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -504,7 +504,7 @@ impl StatusApp {
                 right_x -= 16.0;
                 let is_muted = stats.volume_muted;
                 let color_val = if is_muted {
-                    color::TEXT_DIM
+                    read_disabled_color_from_config().unwrap_or(color::TEXT_DIM)
                 } else {
                     color::TEXT_ACCENT
                 };
@@ -1918,9 +1918,32 @@ fn main() {
     }
 }
 
+fn read_disabled_color_from_config() -> Option<[f32; 4]> {
+    let content = std::fs::read_to_string("/home/lsgalante/.config/clearwm/config.toml").ok()?;
+    parse_srgb_color_from_key(&content, "disabled_color")
+}
+
+fn parse_srgb_color_from_key(content: &str, key: &str) -> Option<[f32; 4]> {
+    for line in content.lines() {
+        let trimmed = line.trim();
+        if let Some(rest) = trimmed.strip_prefix(key) {
+            let rest = rest.trim_start_matches(|c: char| c == ' ' || c == '=' || c == '"');
+            let hex = rest.trim_end_matches('"').trim();
+            if let Some(rgb) = parse_hex(hex) {
+                let r = rgb[0] as f32 / 255.0;
+                let g = rgb[1] as f32 / 255.0;
+                let b = rgb[2] as f32 / 255.0;
+                return Some([r, g, b, 1.0]);
+            }
+        }
+    }
+    None
+}
+
 fn read_bg_color_from_config() -> Option<[f32; 4]> {
     let content = std::fs::read_to_string("/home/lsgalante/.config/clearwm/config.toml").ok()?;
-    parse_color_from_key(&content, "background_color")
+    parse_color_from_key(&content, "low_color")
+        .or_else(|| parse_color_from_key(&content, "background_color"))
 }
 
 fn parse_color_from_key(content: &str, key: &str) -> Option<[f32; 4]> {