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

commitbb0f77a88e1af96dde05263f39943844e74f7345
parent58fdd95d27
authorLucas Galante <[email protected]>
date2026-07-04 16:49
Center viewport on mouse pointer when exiting overview mode

 src/server/window_manager.rs | 76 ++++++++++++++++++++++++++++----------------
 1 file changed, 48 insertions(+), 28 deletions(-)

diff --git a/src/server/window_manager.rs b/src/server/window_manager.rs
index f1d26e5..bd1efdf 100644
--- a/src/server/window_manager.rs
+++ b/src/server/window_manager.rs
@@ -2515,40 +2515,60 @@ fn get_closest_tag(x: f64, y: f64) -> i32 {
                 if self.mode == WindowManagerMode::Overview {
                     let mut viewport_w = 1920.0;
                     let mut viewport_h = 1080.0;
-                    let outputs_list = &mut (*self.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;
+                    let mut phys_x = 0.0;
+                    let mut phys_y = 0.0;
+                    let mut output_found = false;
+
+                    if let Some(seat) = self.first_seat() {
+                        let lx = (*seat).cursor.x();
+                        let ly = (*seat).cursor.y();
+                        let wlr_output = (*self.server).om.output_at(lx, ly);
+                        if !wlr_output.is_null() {
+                            let mut output_box = ffi::wlr_box { x: 0, y: 0, width: 0, height: 0 };
+                            ffi::wlr_output_layout_get_box((*self.server).om.output_layout, wlr_output, &mut output_box);
+                            viewport_w = output_box.width as f64;
+                            viewport_h = output_box.height as f64;
+                            phys_x = output_box.x as f64;
+                            phys_y = output_box.y as f64;
+                            output_found = true;
                         }
-                        curr_out = (*curr_out).next;
                     }
 
-                    if let Some(seat) = self.first_seat() {
-                        if let crate::seat::Focus::Window(fw) = (*seat).focused {
-                            if self.window_is_valid(fw) {
-                                let win_w = if (*fw).box_geom.width > 0 { (*fw).box_geom.width as f64 } else { 800.0 };
-                                let win_h = if (*fw).box_geom.height > 0 { (*fw).box_geom.height as f64 } else { 600.0 };
-                                let center_x = (*fw).virtual_x + win_w / 2.0;
-                                let center_y = (*fw).virtual_y + win_h / 2.0;
-                                self.desk_zoom = 1.0;
-                                self.mode = WindowManagerMode::Normal;
-                                self.desk_pan_x = center_x - viewport_w / 2.0;
-                                self.desk_pan_y = center_y - viewport_h / 2.0;
-                                self.stop_panning_animation();
-                                if matches!(self.state, WindowManagerState::Idle) {
-                                    self.update_viewport_local();
-                                } else {
-                                    self.dirty_windowing();
-                                }
-                                return;
+                    if !output_found {
+                        let outputs_list = &mut (*self.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;
+                                phys_x = wlr_box.x as f64;
+                                phys_y = wlr_box.y as f64;
+                                break;
                             }
+                            curr_out = (*curr_out).next;
                         }
                     }
+
+                    if let Some(seat) = self.first_seat() {
+                        let lx = (*seat).cursor.x();
+                        let ly = (*seat).cursor.y();
+                        let vx = self.desk_pan_x + (lx - phys_x) / self.desk_zoom;
+                        let vy = self.desk_pan_y + (ly - phys_y) / self.desk_zoom;
+                        self.desk_zoom = 1.0;
+                        self.mode = WindowManagerMode::Normal;
+                        self.desk_pan_x = vx - viewport_w / 2.0;
+                        self.desk_pan_y = vy - viewport_h / 2.0;
+                        self.stop_panning_animation();
+                        if matches!(self.state, WindowManagerState::Idle) {
+                            self.update_viewport_local();
+                        } else {
+                            self.dirty_windowing();
+                        }
+                        return;
+                    }
+
                     self.desk_zoom = 1.0;
                     self.mode = WindowManagerMode::Normal;
                     self.desk_pan_x = 0.0;