git.lucas.co / cce-compositor
Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git

commit611d9cea7b65a902bf0224b076e94caaf2762a2e
parentf45ea5ac5f
authorLucas Galante <[email protected]>
date2026-06-27 15:15
feat(server): support click-to-drag resizing via transparent virtual borders for CSD and borderless windows

 src/server/cursor.rs | 11 +++++++++-
 src/server/window.rs | 61 +++++++++++++++++++++++++++++++---------------------
 2 files changed, 46 insertions(+), 26 deletions(-)

diff --git a/src/server/cursor.rs b/src/server/cursor.rs
index 1946d71..5a4b3ff 100644
--- a/src/server/cursor.rs
+++ b/src/server/cursor.rs
@@ -1698,7 +1698,16 @@ pub unsafe fn get_border_zone(window: *mut crate::window::Window, lx: f64, ly: f
         return BorderZone::None;
     }
     
-    let bw = (*window).rendering_requested.border.width as f64;
+    if (*window).rendering_requested.circular {
+        return BorderZone::None;
+    }
+
+    let is_virtual_border = !(*window).wm_requested.ssd || (*window).rendering_requested.border.width == 0;
+    let bw = if is_virtual_border {
+        8.0
+    } else {
+        (*window).rendering_requested.border.width as f64
+    };
     if bw <= 0.0 {
         return BorderZone::None;
     }
diff --git a/src/server/window.rs b/src/server/window.rs
index 6a26ee6..61b9bbb 100644
--- a/src/server/window.rs
+++ b/src/server/window.rs
@@ -1749,7 +1749,8 @@ impl Window {
         ffi::wlr_scene_rect_set_color(self.window_background, bg_color.as_ptr());
         ffi::wlr_scene_node_set_enabled(self.window_background as *mut ffi::wlr_scene_node, !requested.hidden && self.wm_requested.ssd);
 
-        if requested.circular || requested.border.width == 0 || !self.wm_requested.ssd {
+        let is_virtual_border = !self.wm_requested.ssd || requested.border.width == 0;
+        if requested.circular {
             ffi::wlr_scene_node_set_enabled(self.border.left as *mut ffi::wlr_scene_node, false);
             ffi::wlr_scene_node_set_enabled(self.border.right as *mut ffi::wlr_scene_node, false);
             ffi::wlr_scene_node_set_enabled(self.border.top as *mut ffi::wlr_scene_node, false);
@@ -1767,54 +1768,64 @@ impl Window {
         let clip_empty = requested.content_clip.width == 0 && requested.content_clip.height == 0;
         if clip_empty || ffi::wlr_box_intersection(&mut intersect, &content, &requested.content_clip) {
             let border = &requested.border;
-            let color: [f32; 4] = [
-                (border.r as f64 / u32::MAX as f64) as f32,
-                (border.g as f64 / u32::MAX as f64) as f32,
-                (border.b as f64 / u32::MAX as f64) as f32,
-                (border.a as f64 / u32::MAX as f64) as f32,
-            ];
+            let border_width = if is_virtual_border { 8 } else { border.width };
+            let color: [f32; 4] = if is_virtual_border {
+                [0.0, 0.0, 0.0, 0.0]
+            } else {
+                [
+                    (border.r as f64 / u32::MAX as f64) as f32,
+                    (border.g as f64 / u32::MAX as f64) as f32,
+                    (border.b as f64 / u32::MAX as f64) as f32,
+                    (border.a as f64 / u32::MAX as f64) as f32,
+                ]
+            };
 
             let mut left = ffi::wlr_box {
-                x: -(border.width as i32),
+                x: -(border_width as i32),
                 y: 0,
-                width: border.width as i32,
+                width: border_width as i32,
                 height: content.height,
             };
             let mut right = ffi::wlr_box {
                 x: content.width,
                 y: 0,
-                width: border.width as i32,
+                width: border_width as i32,
                 height: content.height,
             };
             let mut top = ffi::wlr_box {
                 x: 0,
-                y: -(border.width as i32),
+                y: -(border_width as i32),
                 width: content.width,
-                height: border.width as i32,
+                height: border_width as i32,
             };
             let mut bottom = ffi::wlr_box {
                 x: 0,
                 y: content.height,
                 width: content.width,
-                height: border.width as i32,
+                height: border_width as i32,
             };
 
-            if border.edges.top {
-                left.y -= border.width as i32;
-                left.height += border.width as i32;
-                right.y -= border.width as i32;
-                right.height += border.width as i32;
+            let edge_left = if is_virtual_border { true } else { border.edges.left };
+            let edge_right = if is_virtual_border { true } else { border.edges.right };
+            let edge_top = if is_virtual_border { true } else { border.edges.top };
+            let edge_bottom = if is_virtual_border { true } else { border.edges.bottom };
+
+            if edge_top {
+                left.y -= border_width as i32;
+                left.height += border_width as i32;
+                right.y -= border_width as i32;
+                right.height += border_width as i32;
             }
-            if border.edges.bottom {
-                left.height += border.width as i32;
-                right.height += border.width as i32;
+            if edge_bottom {
+                left.height += border_width as i32;
+                right.height += border_width as i32;
             }
 
             let mut edges = [
-                ("left", &mut left, self.border.left, border.edges.left),
-                ("right", &mut right, self.border.right, border.edges.right),
-                ("top", &mut top, self.border.top, border.edges.top),
-                ("bottom", &mut bottom, self.border.bottom, border.edges.bottom),
+                ("left", &mut left, self.border.left, edge_left),
+                ("right", &mut right, self.border.right, edge_right),
+                ("top", &mut top, self.border.top, edge_top),
+                ("bottom", &mut bottom, self.border.bottom, edge_bottom),
             ];
 
             for (_, edge_box, rect, enabled) in &mut edges {