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

commit12fbc32dab5334fe5dfd85be8c5ba3ec14916411
parentd529d32f20
authorLucas Galante <[email protected]>
date2026-06-25 14:51
Do not pan to center window if 75% or more of it is visible in the viewport

 src/server/seat.rs | 59 +++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 43 insertions(+), 16 deletions(-)

diff --git a/src/server/seat.rs b/src/server/seat.rs
index 405c4eb..f3c8312 100644
--- a/src/server/seat.rs
+++ b/src/server/seat.rs
@@ -457,23 +457,50 @@ impl Seat {
                             let wm = &mut (*self.server).wm;
                             let scale = wm.desk_zoom;
 
-                            let target_x = (*window).virtual_x + (fw / 2.0 - viewport_w / 2.0) / scale;
-                            let target_y = (*window).virtual_y + (fh / 2.0 - viewport_h / 2.0) / scale;
-
-                            wm.target_desk_pan_x = Some(target_x);
-                            wm.target_desk_pan_y = Some(target_y);
-
-                            if wm.animation_timer.is_null() {
-                                let event_loop = ffi::wl_display_get_event_loop((*self.server).wl_server);
-                                wm.animation_timer = ffi::wl_event_loop_add_timer(
-                                    event_loop,
-                                    Some(crate::window_manager::handle_panning_animation_tick),
-                                    wm as *mut crate::window_manager::WindowManager as *mut _,
-                                );
-                            }
+                            // Calculate window visibility percentage in viewport
+                            let v_w = viewport_w / scale;
+                            let v_h = viewport_h / scale;
+                            let v_left = wm.desk_pan_x;
+                            let v_right = v_left + v_w;
+                            let v_top = wm.desk_pan_y;
+                            let v_bottom = v_top + v_h;
+
+                            let w_left = (*window).virtual_x;
+                            let w_top = (*window).virtual_y;
+                            let w_right = w_left + fw;
+                            let w_bottom = w_top + fh;
+
+                            let i_left = w_left.max(v_left);
+                            let i_right = w_right.min(v_right);
+                            let i_top = w_top.max(v_top);
+                            let i_bottom = w_bottom.min(v_bottom);
+
+                            let i_w = (i_right - i_left).max(0.0);
+                            let i_h = (i_bottom - i_top).max(0.0);
+                            let i_area = i_w * i_h;
+                            let w_area = fw * fh;
+
+                            let visible_percent = if w_area > 0.0 { i_area / w_area } else { 0.0 };
+
+                            if visible_percent < 0.75 {
+                                let target_x = (*window).virtual_x + (fw / 2.0 - viewport_w / 2.0) / scale;
+                                let target_y = (*window).virtual_y + (fh / 2.0 - viewport_h / 2.0) / scale;
+
+                                wm.target_desk_pan_x = Some(target_x);
+                                wm.target_desk_pan_y = Some(target_y);
+
+                                if wm.animation_timer.is_null() {
+                                    let event_loop = ffi::wl_display_get_event_loop((*self.server).wl_server);
+                                    wm.animation_timer = ffi::wl_event_loop_add_timer(
+                                        event_loop,
+                                        Some(crate::window_manager::handle_panning_animation_tick),
+                                        wm as *mut crate::window_manager::WindowManager as *mut _,
+                                    );
+                                }
 
-                            if !wm.animation_timer.is_null() {
-                                ffi::wl_event_source_timer_update(wm.animation_timer, 16);
+                                if !wm.animation_timer.is_null() {
+                                    ffi::wl_event_source_timer_update(wm.animation_timer, 16);
+                                }
                             }
                         }
                     }