GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
Rename clear-inspector-v1 protocol to cce-inspector-v1
...clear-inspector-v1.xml => cce-inspector-v1.xml} | 4 +-
src/backend/window_runner.rs | 6 +-
src/main.rs | 8 +-
src/protocol.rs | 8 +-
src/widget/container/window.rs | 102 ++++++++++++++++-----
src/widget/mod.rs | 1 +
6 files changed, 91 insertions(+), 38 deletions(-)
diff --git a/protocol/clear-inspector-v1.xml b/protocol/cce-inspector-v1.xml
similarity index 96%
rename from protocol/clear-inspector-v1.xml
rename to protocol/cce-inspector-v1.xml
index abefd7f..f578b75 100644
--- a/protocol/clear-inspector-v1.xml
+++ b/protocol/cce-inspector-v1.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
-<protocol name="clear_inspector_v1">
+<protocol name="cce_inspector_v1">
<copyright>
Copyright © 2026 Antigravity
</copyright>
- <interface name="zclear_inspector_v1" version="1">
+ <interface name="zcce_inspector_v1" version="1">
<description summary="query information about client surface states and layouts">
This interface allows cce-ui client applications to register their surfaces
and publish their internal widget trees and state to the compositor.
diff --git a/src/backend/window_runner.rs b/src/backend/window_runner.rs
index e45b170..adf6c55 100644
--- a/src/backend/window_runner.rs
+++ b/src/backend/window_runner.rs
@@ -1842,11 +1842,11 @@ impl<A: Application> wayland_client::Dispatch<wl_registry::WlRegistry, GlobalLis
) {}
}
-impl<A: Application> wayland_client::Dispatch<crate::protocol::zclear_inspector_v1::ZclearInspectorV1, ()> for EngineState<A> {
+impl<A: Application> wayland_client::Dispatch<crate::protocol::zcce_inspector_v1::ZcceInspectorV1, ()> for EngineState<A> {
fn event(
_state: &mut Self,
- _proxy: &crate::protocol::zclear_inspector_v1::ZclearInspectorV1,
- _event: crate::protocol::zclear_inspector_v1::Event,
+ _proxy: &crate::protocol::zcce_inspector_v1::ZcceInspectorV1,
+ _event: crate::protocol::zcce_inspector_v1::Event,
_data: &(),
_conn: &Connection,
_qh: &QueueHandle<Self>,
diff --git a/src/main.rs b/src/main.rs
index b86443a..6ff2210 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -921,7 +921,7 @@ struct AppState {
pressed_key: Option<PressedKey>,
key_repeat_delay: std::time::Duration,
key_repeat_interval: std::time::Duration,
- inspector: Option<cce_ui::protocol::zclear_inspector_v1::ZclearInspectorV1>,
+ inspector: Option<cce_ui::protocol::zcce_inspector_v1::ZcceInspectorV1>,
last_inspector_update: std::time::Instant,
last_serialized: String,
}
@@ -1519,11 +1519,11 @@ impl ProvidesRegistryState for AppState {
) {}
}
-impl wayland_client::Dispatch<cce_ui::protocol::zclear_inspector_v1::ZclearInspectorV1, ()> for AppState {
+impl wayland_client::Dispatch<cce_ui::protocol::zcce_inspector_v1::ZcceInspectorV1, ()> for AppState {
fn event(
_state: &mut Self,
- _proxy: &cce_ui::protocol::zclear_inspector_v1::ZclearInspectorV1,
- _event: cce_ui::protocol::zclear_inspector_v1::Event,
+ _proxy: &cce_ui::protocol::zcce_inspector_v1::ZcceInspectorV1,
+ _event: cce_ui::protocol::zcce_inspector_v1::Event,
_data: &(),
_conn: &Connection,
_qh: &QueueHandle<Self>,
diff --git a/src/protocol.rs b/src/protocol.rs
index de3fa5e..bd403a3 100644
--- a/src/protocol.rs
+++ b/src/protocol.rs
@@ -1,17 +1,17 @@
#[allow(dead_code, non_camel_case_types, unused_unsafe, unused_variables)]
#[allow(non_upper_case_globals, non_snake_case, unused_imports, missing_docs, clippy::all)]
-pub mod zclear_inspector_v1 {
+pub mod zcce_inspector_v1 {
pub mod client {
use wayland_client;
use wayland_client::protocol::*;
pub mod __interfaces {
use wayland_client::protocol::__interfaces::*;
- wayland_scanner::generate_interfaces!("protocol/clear-inspector-v1.xml");
+ wayland_scanner::generate_interfaces!("protocol/cce-inspector-v1.xml");
}
use self::__interfaces::*;
- wayland_scanner::generate_client_code!("protocol/clear-inspector-v1.xml");
+ wayland_scanner::generate_client_code!("protocol/cce-inspector-v1.xml");
}
- pub use self::client::zclear_inspector_v1::*;
+ pub use self::client::zcce_inspector_v1::*;
}
diff --git a/src/widget/container/window.rs b/src/widget/container/window.rs
index d0608ed..8a4867f 100644
--- a/src/widget/container/window.rs
+++ b/src/widget/container/window.rs
@@ -4,7 +4,9 @@ use crate::widget::display::TextLabel;
#[derive(Debug, Clone)]
pub struct Window {
- pub base: Layer,
+ pub base: Widget,
+ pub children: Vec<*mut (dyn Element + 'static)>,
+ pub parent: Option<*mut (dyn Element + 'static)>,
pub border_color: Option<[f32; 4]>,
pub border_thickness: f32,
pub radius: f32,
@@ -15,7 +17,9 @@ pub struct Window {
impl Window {
pub fn new(x: f32, y: f32, w: f32, h: f32) -> Self {
Self {
- base: Layer::new(x, y, w, h),
+ base: Widget::new_rect(x, y, w, h),
+ children: Vec::new(),
+ parent: None,
border_color: None,
border_thickness: 1.0,
radius: 12.0,
@@ -43,11 +47,11 @@ impl Window {
impl Element for Window {
fn base(&self) -> Option<&Widget> {
- Some(&self.base.base)
+ Some(&self.base)
}
fn base_mut(&mut self) -> Option<&mut Widget> {
- Some(&mut self.base.base)
+ Some(&mut self.base)
}
fn as_any(&self) -> &dyn std::any::Any {
@@ -67,11 +71,14 @@ impl Element for Window {
}
fn rect(&self) -> (f32, f32, f32, f32) {
- self.base.rect()
+ (self.base.x, self.base.y, self.base.w, self.base.h)
}
fn set_rect(&mut self, x: f32, y: f32, w: f32, h: f32) {
- self.base.set_rect(x, y, w, h);
+ self.base.x = x;
+ self.base.y = y;
+ self.base.w = w;
+ self.base.h = h;
}
fn color(&self) -> [f32; 4] {
@@ -84,13 +91,12 @@ impl Element for Window {
fn set_visible(&mut self, visible: bool) {
self.visible = visible;
- self.base.visible = visible;
}
fn add_child(&mut self, child: *mut (dyn Element + 'static), ctx: &mut UiContext) {
- let id = self.base.base.id();
- let self_ptr = self.as_ptr();
- self.base.children.push(child);
+ let id = self.base.id();
+ let self_ptr = self.as_ptr_mut();
+ self.children.push(child);
unsafe {
if let Some(c_id) = (*child).base().map(|b| b.id()) {
ctx.register_widget(c_id, child);
@@ -101,23 +107,25 @@ impl Element for Window {
}
fn clear_children(&mut self, ctx: &mut UiContext) {
- self.base.clear_children(ctx);
+ self.children.clear();
+ let id = self.base.id();
+ ctx.clear_children_ids(id);
}
- fn children(&self, ctx: &UiContext) -> Vec<*mut (dyn Element + 'static)> {
- self.base.children(ctx)
+ fn children(&self, _ctx: &UiContext) -> Vec<*mut (dyn Element + 'static)> {
+ self.children.clone()
}
- fn set_parent(&mut self, parent: Option<*mut (dyn Element + 'static)>, ctx: &mut UiContext) {
- self.base.set_parent(parent, ctx);
+ fn set_parent(&mut self, parent: Option<*mut (dyn Element + 'static)>, _ctx: &mut UiContext) {
+ self.parent = parent;
}
- fn parent(&self, ctx: &UiContext) -> Option<*mut (dyn Element + 'static)> {
- self.base.parent(ctx)
+ fn parent(&self, _ctx: &UiContext) -> Option<*mut (dyn Element + 'static)> {
+ self.parent
}
fn set_modifiers(&mut self, ctrl: bool, shift: bool, alt: bool) {
- for &child_ptr in &self.base.children {
+ for &child_ptr in &self.children {
unsafe {
(*child_ptr).set_modifiers(ctrl, shift, alt);
}
@@ -150,24 +158,64 @@ impl Element for Window {
let (wx, wy, ww, wh) = self.rect();
quads.push((wx, wy, ww, wh, bg_color));
}
- quads.extend(self.base.all_quads(ctx));
+ for &child_ptr in &self.children {
+ let widget = unsafe { &*child_ptr };
+ let cc = widget.color();
+ if cc[3] > 0.0 {
+ let (wx, wy, ww, wh) = widget.rect();
+ quads.push((wx, wy, ww, wh, cc));
+ }
+ quads.extend(widget.all_quads(ctx));
+ }
quads
}
fn text_labels(&self) -> Vec<TextLabel> {
- self.base.text_labels()
+ if !self.visible {
+ return Vec::new();
+ }
+ let mut labels = Vec::new();
+ for &child_ptr in &self.children {
+ let widget = unsafe { &*child_ptr };
+ labels.extend(widget.text_labels());
+ }
+ labels
}
fn text_labels_with_bounds(&self, ctx: &UiContext) -> Vec<(TextLabel, Option<[f32; 4]>)> {
- self.base.text_labels_with_bounds(ctx)
+ if !self.visible {
+ return Vec::new();
+ }
+ let mut result = Vec::new();
+ for &child_ptr in &self.children {
+ let widget = unsafe { &*child_ptr };
+ result.extend(widget.text_labels_with_bounds(ctx));
+ }
+ result
}
fn text_labels_with_font_and_bounds(&self, ctx: &UiContext) -> Vec<(TextLabel, Option<String>, Option<[f32; 4]>)> {
- self.base.text_labels_with_font_and_bounds(ctx)
+ if !self.visible {
+ return Vec::new();
+ }
+ let mut result = Vec::new();
+ for &child_ptr in &self.children {
+ let widget = unsafe { &*child_ptr };
+ result.extend(widget.text_labels_with_font_and_bounds(ctx));
+ }
+ result
}
fn get_text_items(&self) -> Vec<(&glyphon::Buffer, f32, f32, glyphon::Color)> {
- self.base.get_text_items()
+ if !self.visible {
+ return Vec::new();
+ }
+ let mut result = Vec::new();
+ for &child_ptr in &self.children {
+ let widget = unsafe { &*child_ptr };
+ result.extend(widget.get_text_items());
+ }
+ result
}
fn hit_test(&self, px: f32, py: f32, ctx: &UiContext) -> bool {
@@ -204,6 +252,10 @@ impl Element for Window {
}
true
}
+
+ fn is_window(&self) -> bool {
+ true
+ }
}
impl Drop for Window {
@@ -234,11 +286,11 @@ mod tests {
fn test_window_visibility() {
let mut win = Window::new(0.0, 0.0, 100.0, 100.0);
assert!(win.visible());
- assert!(win.base.visible);
+ assert!(win.visible);
win.set_visible(false);
assert!(!win.visible());
- assert!(!win.base.visible);
+ assert!(!win.visible);
}
#[test]
diff --git a/src/widget/mod.rs b/src/widget/mod.rs
index af96410..be933ae 100644
--- a/src/widget/mod.rs
+++ b/src/widget/mod.rs
@@ -496,6 +496,7 @@ pub trait Element {
fn is_plate(&self) -> bool { false }
fn is_page(&self) -> bool { false }
fn is_layer(&self) -> bool { false }
+ fn is_window(&self) -> bool { false }
fn rounded_corners(&self) -> (bool, bool, bool, bool) { (false, false, false, false) }
fn corner_radius(&self) -> f32 { 12.0 }