git.lucas.co / cce-gallery
widget gallery and compositor test bench

commitdaea231222e785b60bb83478997ba8c4f98f2016
parentf6c478da63
authorLucas Galante <[email protected]>
date2026-06-01 06:56
Support hover animation tick loop, transition from clearwm to ccec text, change wgpu power preference to LowPower, and untrack target build folder

 .gitignore  |  1 +
 Cargo.lock  |  2 ++
 README.md   |  6 +++---
 src/main.rs | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 4 files changed, 61 insertions(+), 8 deletions(-)

diff --git a/.gitignore b/.gitignore
index a57d260..679ede6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@ screenshots/
 logs/
 tmp/
 *.log
+target/
diff --git a/Cargo.lock b/Cargo.lock
index 1b919b5..ded1d91 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -199,7 +199,9 @@ dependencies = [
  "serde",
  "smithay-client-toolkit",
  "tokio",
+ "wayland-backend",
  "wayland-client",
+ "wayland-scanner",
  "wgpu",
  "xkeysym",
 ]
diff --git a/README.md b/README.md
index f67bf35..40a3d03 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,8 @@
 # Clear Test Suite
 
 This repository contains integration and verification tests for the `clear` desktop environment programs, specifically:
-- `clear-river` (Wayland compositor with background blur support)
-- `clearwm` (window manager / layout agent)
+- `clear-computing-environment-server` (Wayland compositor with background blur support)
+- `ccec` (window manager / layout agent)
 - `clear-ui` (WebGPU-based desktop widget system)
 
 The tests run in a **headless Wayland session** using the `headless` backend of `wlroots` to ensure portability and automated execution.
@@ -16,7 +16,7 @@ The tests run in a **headless Wayland session** using the `headless` backend of
 - Python 3.x
 - `Pillow` (for screenshot color analysis)
 - `grim` (for Wayland screenshot capture)
-- `clear-river` and `clearwm` built/installed
+- `clear-computing-environment-server` and `ccec` built/installed
 
 ## Running the Suite
 
diff --git a/src/main.rs b/src/main.rs
index 1243ceb..bc34203 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,6 +1,6 @@
 use clear_ui::widget::{
     Button, Checkbox, ContentBg, Dropdown, Header, Label, Paginator, Panel, ProgressBar, RangeSlider, Slider, Spinbox, StatusBar,
-    TextLabel, Toggle, Widget, Trackpad,
+    TextLabel, Toggle, Widget, Trackpad, hover_animation,
 };
 
 use glyphon::{
@@ -164,7 +164,7 @@ impl State {
 
         let adapter = instance
             .request_adapter(&wgpu::RequestAdapterOptions {
-                power_preference: wgpu::PowerPreference::HighPerformance,
+                power_preference: wgpu::PowerPreference::LowPower,
                 compatible_surface: Some(&surface),
                 force_fallback_adapter: false,
             })
@@ -338,7 +338,7 @@ impl State {
                      split, grid), fullscreening,\n\
                      dragging, and resizing.\n\n\
                      Testing layout:\n\
-                     cascades in clearwm."
+                     cascades in ccec."
                 ).with_font_size(11.0).with_color([0x83, 0x83, 0x8a])), // 24 (Info panel description)
                 Box::new(RangeSlider::new().with_label("RangeSlider")), // 25 (RangeSlider widget)
                 Box::new(Trackpad::new().with_label("Trackpad")), // 26 (Trackpad widget)
@@ -450,15 +450,20 @@ impl State {
         let sw = self.width;
         let sh = self.height;
         let mut verts = Vec::new();
+        hover_animation::reset_frame_registration();
         for (i, w) in self.widgets.iter().enumerate() {
             if !self.is_widget_visible(i) {
                 continue;
             }
             verts.extend(widget_vertices(w.as_ref(), sw, sh));
-            for (qx, qy, qw, qh, qc) in w.extra_quads() {
+            for (qx, qy, qw, qh, qc) in w.all_quads() {
                 verts.extend(quad_vertices(qx, qy, qw, qh, sw, sh, qc));
             }
         }
+        hover_animation::post_render_check();
+        if let Some((qx, qy, qw, qh, qc)) = hover_animation::get_quad() {
+            verts.extend(quad_vertices(qx, qy, qw, qh, sw, sh, qc));
+        }
         verts
     }
 
@@ -684,6 +689,37 @@ impl State {
         self.queue.submit(std::iter::once(encoder.finish()));
         output.present();
     }
+
+    fn tick(&mut self, dt: f32) -> bool {
+        let mut changed = false;
+        if hover_animation::tick(dt) {
+            changed = true;
+        }
+        let is_child = self.is_child;
+        let current_page = self.current_page;
+        let is_visible = |index: usize| -> bool {
+            if is_child {
+                return true;
+            }
+            match index {
+                0..=2 => true,
+                3..=13 | 25 | 26 => current_page == Page::Widgets,
+                14..=24 => current_page == Page::Windows,
+                _ => false,
+            }
+        };
+        for (i, w) in self.widgets.iter_mut().enumerate() {
+            if is_visible(i) {
+                if w.tick(dt) {
+                    changed = true;
+                }
+            }
+        }
+        if changed {
+            self.upload_vertices();
+        }
+        changed
+    }
 }
 
 fn demo_positions(sw: f32, sh: f32) -> Vec<(f32, f32, f32, f32)> {
@@ -1160,7 +1196,7 @@ impl PointerHandler for AppState {
                                                       split, grid), fullscreening,\n\
                                                       dragging, and resizing.\n\n\
                                                       Testing layout:\n\
-                                                      cascades in clearwm.",
+                                                      cascades in ccec.",
                                                 1 => "An anchored sub-surface\n\
                                                       popup (xdg_popup).\n\
                                                       Usually transient context\n\
@@ -1475,6 +1511,7 @@ fn main() {
     let loop_handle = event_loop.handle();
     WaylandSource::new(conn, event_queue).insert(loop_handle).unwrap();
 
+    let mut last_tick = std::time::Instant::now();
     loop {
         event_loop
             .dispatch(std::time::Duration::from_millis(16), &mut app)
@@ -1483,6 +1520,19 @@ fn main() {
             break;
         }
 
+        let now = std::time::Instant::now();
+        let mut dt = now.duration_since(last_tick).as_secs_f32();
+        last_tick = now;
+        if dt > 0.1 {
+            dt = 0.1;
+        }
+
+        if let Some(state) = &mut app.state {
+            if state.tick(dt) {
+                app.redraw = true;
+            }
+        }
+
         if app.redraw {
             app.redraw = false;
             if let Some(state) = &mut app.state {