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

commit61a7955aee784da12a46e502ec78144b6d55cf10
parent60a166dd61
authorLucas Galante <[email protected]>
date2026-06-15 15:36
fix: restrict resize zone to outer border edge and implement layout resize preservation for floating windows

 src/server/cursor.rs         | 20 ++++++++++++++------
 src/server/seat.rs           |  9 +++++++++
 src/server/window_manager.rs | 41 +++++++++++++++++++++++++++++++++++++++--
 3 files changed, 62 insertions(+), 8 deletions(-)

diff --git a/src/server/cursor.rs b/src/server/cursor.rs
index 52f3f79..90aed1f 100644
--- a/src/server/cursor.rs
+++ b/src/server/cursor.rs
@@ -1211,18 +1211,26 @@ pub unsafe fn get_border_zone(window: *mut crate::window::Window, lx: f64, ly: f
     }
 
     if rx >= -bw && rx < content_w + bw && ry >= -bw && ry < content_h + bw {
+        let threshold = if bw <= 3.0 { bw / 2.0 } else { 3.0 };
+
         let dist_left = rx + bw;
         let dist_right = (content_w + bw) - rx;
         let dist_top = ry + bw;
         let dist_bottom = (content_h + bw) - ry;
 
-        let corner_threshold = bw + 2.0;
-        let left = dist_left < corner_threshold;
-        let right = dist_right < corner_threshold;
-        let top = dist_top < corner_threshold;
-        let bottom = dist_bottom < corner_threshold;
+        let min_dist = dist_left.min(dist_right).min(dist_top).min(dist_bottom);
+
+        if min_dist >= 0.0 && min_dist < threshold {
+            let delta = threshold + 1.0;
+            let left = dist_left < delta;
+            let right = dist_right < delta;
+            let top = dist_top < delta;
+            let bottom = dist_bottom < delta;
 
-        return BorderZone::Resize(crate::window::Edges { top, bottom, left, right });
+            return BorderZone::Resize(crate::window::Edges { top, bottom, left, right });
+        } else {
+            return BorderZone::Move;
+        }
     }
 
     BorderZone::None
diff --git a/src/server/seat.rs b/src/server/seat.rs
index 38b1b30..fa3a312 100644
--- a/src/server/seat.rs
+++ b/src/server/seat.rs
@@ -856,6 +856,7 @@ impl Seat {
                         (*win).box_geom.x = new_x;
                         (*win).box_geom.y = new_y;
 
+                        (*win).wm_requested.resizing = true;
                         (*win).wm_requested.dimensions = Some(crate::window::Dimensions {
                             width: new_w,
                             height: new_h,
@@ -876,6 +877,14 @@ impl Seat {
     pub unsafe fn op_end(&mut self) {
         if let Some(op) = self.op.take() {
             log::debug!("end seat op");
+            let win = op.window_ptr;
+            if !win.is_null() && !(*win).closed {
+                if let PointerOpType::Resize { .. } = op.op_type {
+                    (*win).wm_requested.resizing = false;
+                    (*win).manage_finish();
+                    (*self.server).wm.dirty_windowing();
+                }
+            }
             match op.input {
                 SeatOpInput::Pointer => {
                     self.cursor.op_end_pointer();
diff --git a/src/server/window_manager.rs b/src/server/window_manager.rs
index 5aff2be..fcef2a1 100644
--- a/src/server/window_manager.rs
+++ b/src/server/window_manager.rs
@@ -583,6 +583,39 @@ impl WindowManager {
         self.global_layout
     }
 
+    pub unsafe fn get_active_resize_dimensions(&self, win_ptr: *mut Window) -> Option<(u32, u32)> {
+        let seats_list = &(*self.server).input_manager.seats as *const ffi::wl_list as *const WlList as *mut WlList;
+        let mut curr_seat = (*seats_list).next;
+        while curr_seat != seats_list {
+            let seat = crate::container_of!(curr_seat, crate::seat::Seat, link);
+            if let Some(ref op) = (*seat).op {
+                if op.window_ptr == win_ptr {
+                    if let crate::seat::PointerOpType::Resize { edges } = op.op_type {
+                        let dx = op.x - op.start_x;
+                        let dy = op.y - op.start_y;
+                        let mut new_w = op.start_win_w;
+                        let mut new_h = op.start_win_h;
+
+                        if edges.left {
+                            new_w = std::cmp::max(50, op.start_win_w as i32 - dx) as u32;
+                        } else if edges.right {
+                            new_w = std::cmp::max(50, op.start_win_w as i32 + dx) as u32;
+                        }
+
+                        if edges.top {
+                            new_h = std::cmp::max(50, op.start_win_h as i32 - dy) as u32;
+                        } else if edges.bottom {
+                            new_h = std::cmp::max(50, op.start_win_h as i32 + dy) as u32;
+                        }
+                        return Some((new_w, new_h));
+                    }
+                }
+            }
+            curr_seat = (*curr_seat).next;
+        }
+        None
+    }
+
     pub unsafe fn arrange_views(&mut self) {
         log::info!("Monolithic arrange_views triggered. Windows: {}", self.windows.count());
         for (idx, &win_ptr) in self.windows.iter().enumerate() {
@@ -938,14 +971,18 @@ impl WindowManager {
                     };
                 } else {
                     let fbw = self.layout.floating_border_width;
-                    let mut fw = if (*win_ptr).box_geom.width > 0 {
+                    let mut fw = if let Some(resize_size) = self.get_active_resize_dimensions(win_ptr) {
+                        resize_size.0 as i32
+                    } else if (*win_ptr).box_geom.width > 0 {
                         (*win_ptr).box_geom.width as i32
                     } else if (*win_ptr).wm_scheduled.dimensions_hint.min_width > 32 {
                         (*win_ptr).wm_scheduled.dimensions_hint.min_width as i32
                     } else {
                         usable_w * 2 / 3
                     };
-                    let mut fh = if (*win_ptr).box_geom.height > 0 {
+                    let mut fh = if let Some(resize_size) = self.get_active_resize_dimensions(win_ptr) {
+                        resize_size.1 as i32
+                    } else if (*win_ptr).box_geom.height > 0 {
                         (*win_ptr).box_geom.height as i32
                     } else if (*win_ptr).wm_scheduled.dimensions_hint.min_height > 32 {
                         (*win_ptr).wm_scheduled.dimensions_hint.min_height as i32