git.lucas.co / cce-ui
GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git

commit17b279a63421436703d5980c037e400de5fbea19
parenta9c2c781ae
authorLucas Galante <[email protected]>
date2026-09-10 13:40
fix(button_strip): record last_scale on the horizontal path too, or tick redraws every frame

`generate_rotated_labels` set `last_scale` only after its `!self.vertical`
early-out, so a horizontal strip's cache never matched in `tick`: every
frame it regenerated (a no-op for horizontal) and reported a change, and
the window redrew at 60 fps for as long as the strip was visible.
cce-gallery, which has one, sat at 6% CPU while idle and made the compositor
render a frame per vsync — ~15% of a core and 200 wakeups/s on an idle
desktop, measured live. With the scale recorded before the early-out the
gallery goes to zero frames at rest.

Co-Authored-By: Claude Fable 5.1 <[email protected]>

 src/widget/input/button_strip.rs | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/src/widget/input/button_strip.rs b/src/widget/input/button_strip.rs
index 80459ad..ad3665a 100644
--- a/src/widget/input/button_strip.rs
+++ b/src/widget/input/button_strip.rs
@@ -146,6 +146,14 @@ impl ButtonStrip {
         self.last_padding = Some(current_padding);
         let current_font = self.current_font();
         self.last_font = Some(current_font);
+        // Recorded BEFORE the horizontal early-out below. It used to be set
+        // only on the vertical path, so a horizontal strip's `tick` saw
+        // `last_scale == None` on every frame, regenerated, and reported a
+        // change — one ButtonStrip made its whole window redraw at 60 fps
+        // forever (cce-gallery, and through it the compositor, sat at ~15%
+        // CPU with nothing happening).
+        let scale = crate::scale::scale_factor().max(1.0);
+        self.last_scale = Some(scale);
 
         self.tab_text_quads.clear();
         if !self.vertical || self.buttons.is_empty() {
@@ -162,8 +170,6 @@ impl ButtonStrip {
         let inactive_b = (active_b as f32 * 0.78) as u8;
 
         let (font_fam, font_size) = self.current_font_parsed();
-        let scale = crate::scale::scale_factor().max(1.0);
-        self.last_scale = Some(scale);
 
         for (i, page_name) in self.buttons.iter().enumerate() {
             let color = if self.selected == Some(i) {