widget gallery and compositor test bench
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 {