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

commit198a4420abf2c05ecb75f80c78d164d24ace286f
parented0c87a0d4
authorLucas Galante <[email protected]>
date2026-08-24 10:55
window: the file chooser opens centered on the current view

cce-filesystem-chooser joins cce-authenticator in the view-centered modal
class: it is spawned BY an action in the current view and must be answered
immediately, but it mapped wherever the file manager was last used — squares
away from the app that opened it.

Doing that exposed a hole in the centering itself: the redo-on-commit latch
was Utility-only, on the reasoning that a Floating modal always has restored
or arrange-given geometry. A Floating SELF-SIZER on its first run has
neither, so the chooser was centered against the 400x400 mapped-size floor —
x=440 instead of x=190 for a 900x500 dialog on a 1280 output. The latch now
arms for any mode with unknown geometry, and the commit handler adopts a
pending-centered Floating window's first real size and redoes the centering,
in both toplevel handlers. Verified in a shadow session with the camera
panned to a non-origin square: the chooser lands centered in that view.

 src/server/window.rs       | 22 ++++++++++++++--------
 src/server/xdg_toplevel.rs | 22 ++++++++++++++++++++++
 2 files changed, 36 insertions(+), 8 deletions(-)

diff --git a/src/server/window.rs b/src/server/window.rs
index 11c7cf0..ae5721c 100644
--- a/src/server/window.rs
+++ b/src/server/window.rs
@@ -1144,7 +1144,12 @@ impl Window {
     /// per-app window rules assign a tiling MODE, not a placement, so there
     /// is nothing there to hang this off yet.
     fn is_view_centered_modal(app_id: &str) -> bool {
-        app_id == "cce-authenticator"
+        // The polkit prompt, and the file chooser cce-files runs in --select/
+        // --save mode: both are spawned BY an action in the current view and
+        // must be answered immediately — a remembered position is actively
+        // wrong for them (the chooser used to map wherever the file manager
+        // was last used, squares away from the app that opened it).
+        app_id == "cce-authenticator" || app_id == "cce-filesystem-chooser"
     }
 
     unsafe fn try_center_on_view(&mut self) {
@@ -1180,13 +1185,14 @@ impl Window {
         // the first frame is not wildly off, and latch a redo for the commit
         // that brings the truth.
         //
-        // Utility only, because it is the only mode whose size arrives after
-        // map — and so the only one the commit path will ever consume this
-        // for. A Floating modal either has restored geometry (`try_restore`
-        // filled `box_geom` before we got here) or is being given a size by
-        // the arrange pass rather than reporting one.
-        self.pending_view_center = self.tiling_mode == crate::tiling::TilingMode::Utility
-            && (self.box_geom.width <= 0 || self.box_geom.height <= 0);
+        // Any mode with unknown geometry latches the redo — not Utility only.
+        // The file chooser disproved the old Utility-only reasoning: a
+        // FLOATING self-sizer on its first ever run has no restored geometry
+        // and no arrange-given size either, so it was centered against the
+        // 400x400 floor and stuck there, ~250px off for a 900x500 dialog.
+        // A Floating modal with restored geometry still skips the latch
+        // (box_geom is already filled by the time we run).
+        self.pending_view_center = self.box_geom.width <= 0 || self.box_geom.height <= 0;
         self.apply_view_centering();
     }
 
diff --git a/src/server/xdg_toplevel.rs b/src/server/xdg_toplevel.rs
index f922056..ce6fc40 100644
--- a/src/server/xdg_toplevel.rs
+++ b/src/server/xdg_toplevel.rs
@@ -472,6 +472,17 @@ unsafe extern "C" fn handle_map(listener: *mut ffi::wl_listener, _data: *mut std
         // against a size it had not committed yet; redo it now that it has.
         (*(*toplevel).window).take_pending_view_center();
         (*(*(*toplevel).window).server).wm.dirty_windowing();
+    } else if (*(*toplevel).window).pending_view_center
+        && new_geometry.width > 0
+        && new_geometry.height > 0
+    {
+        // A view-centered FLOATING window whose first size just arrived (the
+        // file chooser): adopt the geometry and redo the centering, or the
+        // map-time 400x400-floor placement stands for a 900x500 dialog.
+        (*(*toplevel).window).box_geom.width = new_geometry.width;
+        (*(*toplevel).window).box_geom.height = new_geometry.height;
+        (*(*toplevel).window).take_pending_view_center();
+        (*(*(*toplevel).window).server).wm.dirty_windowing();
     }
 }
 
@@ -531,6 +542,17 @@ unsafe extern "C" fn handle_ack_configure(
         // against a size it had not committed yet; redo it now that it has.
         (*(*toplevel).window).take_pending_view_center();
         (*(*(*toplevel).window).server).wm.dirty_windowing();
+    } else if (*(*toplevel).window).pending_view_center
+        && new_geometry.width > 0
+        && new_geometry.height > 0
+    {
+        // A view-centered FLOATING window whose first size just arrived (the
+        // file chooser): adopt the geometry and redo the centering, or the
+        // map-time 400x400-floor placement stands for a 900x500 dialog.
+        (*(*toplevel).window).box_geom.width = new_geometry.width;
+        (*(*toplevel).window).box_geom.height = new_geometry.height;
+        (*(*toplevel).window).take_pending_view_center();
+        (*(*(*toplevel).window).server).wm.dirty_windowing();
     }
 }