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

commitfe46e6e09853a34b587a92edf79db3dbf4b361c9
parent7fcfb97ed3
authorLucas Galante <[email protected]>
date2026-06-24 12:29
feat: automatically center focused floating window by panning viewport

 src/server/seat.rs | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/src/server/seat.rs b/src/server/seat.rs
index 1fed336..477dc0f 100644
--- a/src/server/seat.rs
+++ b/src/server/seat.rs
@@ -387,6 +387,58 @@ impl Seat {
                 }
             }
             Focus::Window(window) => {
+                if !window.is_null() && (*window).tiling_mode == crate::tiling::TilingMode::Floating {
+                    let outputs_list = &mut (*self.server).om.outputs as *mut ffi::wl_list as *mut WlList;
+                    let mut curr_out = (*outputs_list).next;
+                    let mut target_output: *mut crate::output::Output = std::ptr::null_mut();
+                    while curr_out != outputs_list {
+                        let output = crate::container_of!(curr_out, crate::output::Output, link);
+                        if (*output).sent.state == crate::output::OutputStateValue::Enabled {
+                            if target_output.is_null() {
+                                target_output = output;
+                            }
+                            let wlr_box = (*output).sent.box_layout();
+                            let wx = (*window).box_geom.x;
+                            let wy = (*window).box_geom.y;
+                            if wx >= wlr_box.x && wx < wlr_box.x + wlr_box.width
+                                && wy >= wlr_box.y && wy < wlr_box.y + wlr_box.height
+                            {
+                                target_output = output;
+                                break;
+                            }
+                        }
+                        curr_out = (*curr_out).next;
+                    }
+
+                    if !target_output.is_null() {
+                        let wlr_box = (*target_output).sent.box_layout();
+                        let viewport_w = wlr_box.width as f64;
+                        let viewport_h = wlr_box.height as f64;
+
+                        let fw = if (*window).box_geom.width > 0 {
+                            (*window).box_geom.width as f64
+                        } else if (*window).wm_scheduled.dimensions_hint.min_width > 32 {
+                            (*window).wm_scheduled.dimensions_hint.min_width as f64
+                        } else {
+                            800.0
+                        };
+                        let fh = if (*window).box_geom.height > 0 {
+                            (*window).box_geom.height as f64
+                        } else if (*window).wm_scheduled.dimensions_hint.min_height > 32 {
+                            (*window).wm_scheduled.dimensions_hint.min_height as f64
+                        } else {
+                            600.0
+                        };
+
+                        let wm = &mut (*self.server).wm;
+                        let scale = wm.desk_zoom;
+
+                        wm.desk_pan_x = (*window).virtual_x + (fw / 2.0 - viewport_w / 2.0) / scale;
+                        wm.desk_pan_y = (*window).virtual_y + (fh / 2.0 - viewport_h / 2.0) / scale;
+                        wm.dirty_windowing();
+                    }
+                }
+
                 // Focus root surface of window
                 let surface = (*window).root_surface();
                 if !surface.is_null() {