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

commitf3e610afec96051da8bfbe5b7d93f54d620f893d
parent8fa815647f
authorLucas Galante <[email protected]>
date2026-06-26 12:33
feat: refine Overview mode interaction to support click-and-drag window movement without automatic zoom-in, and only zoom/focus on click release

 src/server/cursor.rs       | 114 ++++++++++++++++++++++++++++++++-------------
 src/server/seat.rs         |   6 +++
 src/server/xdg_toplevel.rs |   6 +++
 3 files changed, 93 insertions(+), 33 deletions(-)

diff --git a/src/server/cursor.rs b/src/server/cursor.rs
index 10fad50..59c2416 100644
--- a/src/server/cursor.rs
+++ b/src/server/cursor.rs
@@ -575,41 +575,31 @@ unsafe extern "C" fn handle_button(listener: *mut ffi::wl_listener, data: *mut s
             }
 
             if !clicked_win.is_null() && !(*clicked_win).is_status_bar() {
-                let mut viewport_w = 1920.0;
-                let mut viewport_h = 1080.0;
-                let outputs_list = &mut (*server).om.outputs as *mut ffi::wl_list as *mut WlList;
-                let mut curr_out = (*outputs_list).next;
-                while curr_out != outputs_list {
-                    let output = crate::container_of!(curr_out, crate::output::Output, link);
-                    if (*output).sent.state == crate::output::OutputStateValue::Enabled {
-                        let wlr_box = (*output).sent.box_layout();
-                        viewport_w = wlr_box.width as f64;
-                        viewport_h = wlr_box.height as f64;
-                        break;
-                    }
-                    curr_out = (*curr_out).next;
-                }
-
-                let win_w = if (*clicked_win).box_geom.width > 0 { (*clicked_win).box_geom.width as f64 } else { 800.0 };
-                let win_h = if (*clicked_win).box_geom.height > 0 { (*clicked_win).box_geom.height as f64 } else { 600.0 };
-
-                let center_x = (*clicked_win).virtual_x + win_w / 2.0;
-                let center_y = (*clicked_win).virtual_y + win_h / 2.0;
-
-                (*server).wm.desk_zoom = 1.0;
-                (*server).wm.mode = crate::window_manager::WindowManagerMode::Normal;
-                (*server).wm.desk_pan_x = center_x - viewport_w / 2.0;
-                (*server).wm.desk_pan_y = center_y - viewport_h / 2.0;
-
-                seat.focus(Focus::Window(clicked_win));
-                if !seat.object.is_null() && !(*clicked_win).object.is_null() {
-                    ffi::wl_resource_post_event(seat.object, 4, (*clicked_win).object);
-                }
-
                 (*server).wm.stop_panning_animation();
-                (*server).wm.dirty_windowing();
-
+                let cursor_x = (*cursor.wlr_cursor).x;
+                let cursor_y = (*cursor.wlr_cursor).y;
+                seat.op = Some(crate::seat::SeatOp {
+                    sent_release: false,
+                    input: crate::seat::SeatOpInput::Pointer,
+                    start_x: cursor_x as i32,
+                    start_y: cursor_y as i32,
+                    x: cursor_x as i32,
+                    y: cursor_y as i32,
+                    window_ptr: clicked_win,
+                    op_type: crate::seat::PointerOpType::Move,
+                    start_win_x: (*clicked_win).box_geom.x,
+                    start_win_y: (*clicked_win).box_geom.y,
+                    start_win_w: (*clicked_win).box_geom.width as u32,
+                    start_win_h: (*clicked_win).box_geom.height as u32,
+                    start_win_virtual_x: (*clicked_win).virtual_x,
+                    start_win_virtual_y: (*clicked_win).virtual_y,
+                    start_tiling_mode: (*clicked_win).tiling_mode,
+                    start_mode_locked: (*clicked_win).mode_locked,
+                    started_in_overview: true,
+                });
+                cursor.op_start_pointer();
                 cursor.pressed.insert((*event).button, None);
+                cursor.set_xcursor(b"grab\0".as_ptr() as *const _);
                 return;
             }
         }
@@ -679,6 +669,9 @@ unsafe extern "C" fn handle_button(listener: *mut ffi::wl_listener, data: *mut s
                         start_win_h: (*target_win).box_geom.height as u32,
                         start_win_virtual_x: (*target_win).virtual_x,
                         start_win_virtual_y: (*target_win).virtual_y,
+                        start_tiling_mode: (*target_win).tiling_mode,
+                        start_mode_locked: (*target_win).mode_locked,
+                        started_in_overview: (*(*seat).server).wm.mode == crate::window_manager::WindowManagerMode::Overview,
                     });
                     cursor.op_start_pointer();
                     cursor.pressed.insert((*event).button, None);
@@ -739,6 +732,9 @@ unsafe extern "C" fn handle_button(listener: *mut ffi::wl_listener, data: *mut s
                             start_win_h: (*border_target_win).box_geom.height as u32,
                             start_win_virtual_x: (*border_target_win).virtual_x,
                             start_win_virtual_y: (*border_target_win).virtual_y,
+                            start_tiling_mode: (*border_target_win).tiling_mode,
+                            start_mode_locked: (*border_target_win).mode_locked,
+                            started_in_overview: (*(*seat).server).wm.mode == crate::window_manager::WindowManagerMode::Overview,
                         });
                         cursor.op_start_pointer();
                         cursor.pressed.insert((*event).button, None);
@@ -776,6 +772,9 @@ unsafe extern "C" fn handle_button(listener: *mut ffi::wl_listener, data: *mut s
                             start_win_h: (*border_target_win).box_geom.height as u32,
                             start_win_virtual_x: (*border_target_win).virtual_x,
                             start_win_virtual_y: (*border_target_win).virtual_y,
+                            start_tiling_mode: (*border_target_win).tiling_mode,
+                            start_mode_locked: (*border_target_win).mode_locked,
+                            started_in_overview: (*(*seat).server).wm.mode == crate::window_manager::WindowManagerMode::Overview,
                         });
                         cursor.op_start_pointer();
                         cursor.pressed.insert((*event).button, None);
@@ -833,6 +832,55 @@ unsafe extern "C" fn handle_button(listener: *mut ffi::wl_listener, data: *mut s
             let cursor_x = (*cursor.wlr_cursor).x;
             let cursor_y = (*cursor.wlr_cursor).y;
             seat.op_update(cursor_x as i32, cursor_y as i32);
+            
+            let op = seat.op.unwrap();
+            if op.started_in_overview && (*event).button == 0x110 {
+                let moved = (cursor_x as i32 - op.start_x).abs() > 5 || (cursor_y as i32 - op.start_y).abs() > 5;
+                if !moved && !op.window_ptr.is_null() {
+                    let win_ptr = op.window_ptr;
+                    // Restore original tiling mode & lock status
+                    (*win_ptr).tiling_mode = op.start_tiling_mode;
+                    (*win_ptr).mode_locked = op.start_mode_locked;
+                    
+                    let server = seat.server;
+                    if !(*win_ptr).closed && !(*win_ptr).is_status_bar() {
+                        let mut viewport_w = 1920.0;
+                        let mut viewport_h = 1080.0;
+                        let outputs_list = &mut (*server).om.outputs as *mut ffi::wl_list as *mut WlList;
+                        let mut curr_out = (*outputs_list).next;
+                        while curr_out != outputs_list {
+                            let output = crate::container_of!(curr_out, crate::output::Output, link);
+                            if (*output).sent.state == crate::output::OutputStateValue::Enabled {
+                                let wlr_box = (*output).sent.box_layout();
+                                viewport_w = wlr_box.width as f64;
+                                viewport_h = wlr_box.height as f64;
+                                break;
+                            }
+                            curr_out = (*curr_out).next;
+                        }
+
+                        let win_w = if (*win_ptr).box_geom.width > 0 { (*win_ptr).box_geom.width as f64 } else { 800.0 };
+                        let win_h = if (*win_ptr).box_geom.height > 0 { (*win_ptr).box_geom.height as f64 } else { 600.0 };
+
+                        let center_x = (*win_ptr).virtual_x + win_w / 2.0;
+                        let center_y = (*win_ptr).virtual_y + win_h / 2.0;
+
+                        (*server).wm.desk_zoom = 1.0;
+                        (*server).wm.mode = crate::window_manager::WindowManagerMode::Normal;
+                        (*server).wm.desk_pan_x = center_x - viewport_w / 2.0;
+                        (*server).wm.desk_pan_y = center_y - viewport_h / 2.0;
+
+                        seat.focus(Focus::Window(win_ptr));
+                        if !seat.object.is_null() && !(*win_ptr).object.is_null() {
+                            ffi::wl_resource_post_event(seat.object, 4, (*win_ptr).object);
+                        }
+
+                        (*server).wm.stop_panning_animation();
+                        (*server).wm.dirty_windowing();
+                    }
+                }
+            }
+            
             seat.op_end();
             cursor.pressed.remove(&(*event).button);
             return;
diff --git a/src/server/seat.rs b/src/server/seat.rs
index d542213..e07d9c5 100644
--- a/src/server/seat.rs
+++ b/src/server/seat.rs
@@ -29,6 +29,9 @@ pub struct SeatOp {
     pub start_win_h: u32,
     pub start_win_virtual_x: f64,
     pub start_win_virtual_y: f64,
+    pub start_tiling_mode: crate::tiling::TilingMode,
+    pub start_mode_locked: bool,
+    pub started_in_overview: bool,
 }
 
 #[derive(Clone, Copy, PartialEq, Debug)]
@@ -1315,6 +1318,9 @@ unsafe extern "C" fn seat_op_start_pointer(
             start_win_h: 0,
             start_win_virtual_x: 0.0,
             start_win_virtual_y: 0.0,
+            start_tiling_mode: crate::tiling::TilingMode::Floating,
+            start_mode_locked: false,
+            started_in_overview: false,
         });
         (*(*seat).server).wm.stop_panning_animation();
         (*seat).cursor.op_start_pointer();
diff --git a/src/server/xdg_toplevel.rs b/src/server/xdg_toplevel.rs
index c569178..181693c 100644
--- a/src/server/xdg_toplevel.rs
+++ b/src/server/xdg_toplevel.rs
@@ -676,6 +676,9 @@ unsafe extern "C" fn handle_request_move(
             start_win_h: (*window).box_geom.height as u32,
             start_win_virtual_x: (*window).virtual_x,
             start_win_virtual_y: (*window).virtual_y,
+            start_tiling_mode: (*window).tiling_mode,
+            start_mode_locked: (*window).mode_locked,
+            started_in_overview: (*(*window).server).wm.mode == crate::window_manager::WindowManagerMode::Overview,
         });
         cursor.op_start_pointer();
         cursor.set_xcursor(b"grab\0".as_ptr() as *const _);
@@ -728,6 +731,9 @@ unsafe extern "C" fn handle_request_resize(
             start_win_h: (*window).box_geom.height as u32,
             start_win_virtual_x: (*window).virtual_x,
             start_win_virtual_y: (*window).virtual_y,
+            start_tiling_mode: (*window).tiling_mode,
+            start_mode_locked: (*window).mode_locked,
+            started_in_overview: (*(*window).server).wm.mode == crate::window_manager::WindowManagerMode::Overview,
         });
         cursor.op_start_pointer();
         let cursor_name = crate::cursor::get_resize_cursor_name(edges);