status bar
git clone https://git.lucas.co/cce-status-interface.git
fix: stat modules size to a widest-plausible template, not the live text
Sizing cpu/memory/battery/volume/brightness to their live text made the
surface resize whenever the value crossed a digit boundary ("Cpu 9.9%" ↔
"Cpu 10.2%" is 95px ↔ 104px). Each resize re-arranged the whole status
strip, and through the compositor's stale configure echo the module and
its neighbors ping-ponged at frame rate — ~3300 alternating configures in
five minutes of CPU load hovering near 10%, visible as the tray/cpu
jitter.
stable_text_width() measures the wider of the live text and a per-module
template ("Cpu 99.9%", "Bat 100%", …; memory pins the used part to the
constant total, "Mem 62.4/62.4G") so ordinary value changes never change
the surface size. Verified: 110 consecutive cpu rebuilds at one width
where the flap reproduced before.
Co-Authored-By: Claude Fable 5 <[email protected]>
src/modules.rs | 42 ++++++++++++++++++++++++++++++++----------
1 file changed, 32 insertions(+), 10 deletions(-)
diff --git a/src/modules.rs b/src/modules.rs
index 4410a9c..0951cba 100644
--- a/src/modules.rs
+++ b/src/modules.rs
@@ -62,6 +62,25 @@ pub trait StatusModule {
);
}
+/// A stat module's width from the WIDER of its live text and a
+/// widest-plausible template ("Cpu 99.9%"), plus padding. Sizing to the live
+/// text alone made the surface resize whenever the value crossed a digit
+/// boundary ("Cpu 9.9%" ↔ "Cpu 10.2%"), which re-arranged the whole status
+/// strip and — through the compositor's configure echo — ping-ponged the
+/// module and its neighbors at frame rate (the tray/cpu jitter).
+fn stable_text_width(
+ font_system: &mut FontSystem,
+ text: &str,
+ template: &str,
+ font_size: f32,
+ font_family: &str,
+ padding: f32,
+) -> f32 {
+ let live = Label::new_with_family(font_system, text, font_size, [0.0, 0.0, 0.0, 1.0], font_family).w;
+ let tmpl = Label::new_with_family(font_system, template, font_size, [0.0, 0.0, 0.0, 1.0], font_family).w;
+ live.max(tmpl) + 2.0 * padding
+}
+
pub struct WindowModule;
impl StatusModule for WindowModule {
@@ -295,8 +314,7 @@ impl StatusModule for BatteryModule {
} else {
"Bat 100%"
};
- let label = Label::new_with_family(font_system, text, font_size, [0.0, 0.0, 0.0, 1.0], font_family);
- label.w + 2.0 * padding
+ stable_text_width(font_system, text, "Bat 100%", font_size, font_family, padding)
}
fn render(
@@ -361,8 +379,7 @@ impl StatusModule for VolumeModule {
} else {
"Vol 100%"
};
- let label = Label::new_with_family(font_system, text, font_size, [0.0, 0.0, 0.0, 1.0], font_family);
- label.w + 2.0 * padding
+ stable_text_width(font_system, text, "Vol 100%", font_size, font_family, padding)
}
fn render(
@@ -440,8 +457,7 @@ impl StatusModule for BrightnessModule {
} else {
"Bri 100%"
};
- let label = Label::new_with_family(font_system, text, font_size, [0.0, 0.0, 0.0, 1.0], font_family);
- label.w + 2.0 * padding
+ stable_text_width(font_system, text, "Bri 100%", font_size, font_family, padding)
}
fn render(
@@ -501,8 +517,15 @@ impl StatusModule for MemoryModule {
} else {
"Mem 0.0/0.0G"
};
- let label = Label::new_with_family(font_system, text, font_size, [0.0, 0.0, 0.0, 1.0], font_family);
- label.w + 2.0 * padding
+ // "Mem 8.2/62.4G" → "Mem 62.4/62.4G": used pinned to the total, the
+ // widest this machine's readout gets.
+ let template = text
+ .rsplit('/')
+ .next()
+ .and_then(|total| total.strip_suffix('G'))
+ .map(|total| format!("Mem {total}/{total}G"))
+ .unwrap_or_else(|| text.to_string());
+ stable_text_width(font_system, text, &template, font_size, font_family, padding)
}
fn render(
@@ -560,8 +583,7 @@ impl StatusModule for CpuModule {
} else {
"Cpu 0.0%"
};
- let label = Label::new_with_family(font_system, text, font_size, [0.0, 0.0, 0.0, 1.0], font_family);
- label.w + 2.0 * padding
+ stable_text_width(font_system, text, "Cpu 99.9%", font_size, font_family, padding)
}
fn render(