Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
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();
}
}