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

commite044ef3398a6bb489aa8f0987cf62e5a06697792
parente8077c89fb
authorLucas Galante <[email protected]>
date2026-06-19 02:35
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 }