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

commit4232d2170dd2aff94a52ad968b20e3cf4f4ade63
parentf741e5e23d
authorLucas Galante <[email protected]>
date2026-06-17 11:12
Support context menu in active_popup surface and completely disable main canvas overlay text clipping

 src/backend/window_runner.rs | 74 +++++++++++++++++++++++++-------------------
 1 file changed, 42 insertions(+), 32 deletions(-)

diff --git a/src/backend/window_runner.rs b/src/backend/window_runner.rs
index 1036b62..1fd2a40 100644
--- a/src/backend/window_runner.rs
+++ b/src/backend/window_runner.rs
@@ -881,15 +881,7 @@ pub trait Application: Sized + 'static {
     fn render_popovers(&self, _pc: &mut dyn crate::layout::RenderTarget) {}
     
     fn text_areas(&self, scale_f32: f32, bounds: TextBounds) -> Vec<TextArea<'_>> {
-        let mut overlay_rects = Vec::new();
-        if crate::widget::context_menu::is_visible() {
-            overlay_rects.push((
-                crate::widget::context_menu::x(),
-                crate::widget::context_menu::y(),
-                crate::widget::context_menu::w(),
-                crate::widget::context_menu::h(),
-            ));
-        }
+        let overlay_rects: Vec<(f32, f32, f32, f32)> = Vec::new();
 
         self.text_items().iter().map(|ti| {
             let mut item_bounds = if let Some([l, t, r, b]) = ti.bounds {
@@ -2018,32 +2010,51 @@ pub fn run<A: Application>() {
         }
 
         let active_popovers = crate::widget::popovers::get_active();
-        if !active_popovers.is_empty() {
-            let popover_widget = unsafe { &*active_popovers[0] };
-            if let Some((px, py, pw, ph)) = popover_widget.popover_rect() {
-                if engine_state.active_popup.is_none() {
-                    let wl_surface = engine_state.compositor_state.create_surface(&engine_state.qh);
-                    wl_surface.set_buffer_scale(engine_state.scale_factor as i32);
-                    
-                    let positioner = XdgPositioner::new(&engine_state.xdg_shell_state).unwrap();
-                    positioner.set_size(pw as i32, ph as i32);
-                    
+        let context_menu_visible = crate::widget::context_menu::is_visible();
+        if !active_popovers.is_empty() || context_menu_visible {
+            let (px, py, pw, ph, is_context_menu) = if !active_popovers.is_empty() {
+                let popover_widget = unsafe { &*active_popovers[0] };
+                let (x, y, w, h) = popover_widget.popover_rect().unwrap();
+                (x, y, w, h, false)
+            } else {
+                (
+                    crate::widget::context_menu::x(),
+                    crate::widget::context_menu::y(),
+                    crate::widget::context_menu::w(),
+                    crate::widget::context_menu::h(),
+                    true,
+                )
+            };
+            if engine_state.active_popup.is_none() {
+                let wl_surface = engine_state.compositor_state.create_surface(&engine_state.qh);
+                wl_surface.set_buffer_scale(engine_state.scale_factor as i32);
+                
+                let positioner = XdgPositioner::new(&engine_state.xdg_shell_state).unwrap();
+                positioner.set_size(pw as i32, ph as i32);
+                
+                if !is_context_menu {
+                    let popover_widget = unsafe { &*active_popovers[0] };
                     let (rx, ry, rw, rh) = popover_widget.rect();
                     positioner.set_anchor_rect(rx as i32, ry as i32, rw as i32, rh as i32);
                     positioner.set_anchor(Anchor::BottomLeft);
                     positioner.set_gravity(Gravity::BottomRight);
-                    positioner.set_constraint_adjustment(
-                        ConstraintAdjustment::SlideX | ConstraintAdjustment::SlideY
-                    );
-                    
-                    let parent_xdg_surface = XdgSurface::xdg_surface(engine_state.window.as_ref().unwrap());
-                    let sctk_popup = Popup::new(
-                        parent_xdg_surface,
-                        &positioner,
-                        &engine_state.qh,
-                        &engine_state.compositor_state,
-                        &engine_state.xdg_shell_state,
-                    ).unwrap();
+                } else {
+                    positioner.set_anchor_rect(px as i32, py as i32, 1, 1);
+                    positioner.set_anchor(Anchor::TopLeft);
+                    positioner.set_gravity(Gravity::BottomRight);
+                }
+                positioner.set_constraint_adjustment(
+                    ConstraintAdjustment::SlideX | ConstraintAdjustment::SlideY
+                );
+                
+                let parent_xdg_surface = XdgSurface::xdg_surface(engine_state.window.as_ref().unwrap());
+                let sctk_popup = Popup::new(
+                    parent_xdg_surface,
+                    &positioner,
+                    &engine_state.qh,
+                    &engine_state.compositor_state,
+                    &engine_state.xdg_shell_state,
+                ).unwrap();
                     
                     let display_ptr = conn.backend().display_id().as_ptr() as *mut std::ffi::c_void;
                     let surface_ptr = sctk_popup.wl_surface().id().as_ptr() as *mut std::ffi::c_void;
@@ -2079,7 +2090,6 @@ pub fn run<A: Application>() {
                         vertex_buffer: None,
                     });
                 }
-            }
         } else {
             if engine_state.active_popup.is_some() {
                 engine_state.active_popup = None;