Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
borders: corner handles follow the window silhouette arc
The corner zones' ring radius came from the border{corner_radius=} key
(8 in practice) while the window silhouette curves at the widened
backplate radius (~35): the corner piece rounded only its outermost tip
and diverged from the window arc underneath. The ring now derives from
the same silhouette chain as the corner clip and background plate
(widen_corner_radius over backplate_radius_base), so the band wraps the
window corner concentrically; square windows keep the square L.
border_corner_len takes the outer arc radius and floors the zone at
arc + half a band, or a wide arc would overflow the corner piece — the
pointer zones pass the same value, so grab geometry stays in lockstep
with the visuals. The border corner_radius key is no longer consumed.
Co-Authored-By: Claude Fable 5 <[email protected]>
src/server/cursor.rs | 9 +++++++++
src/server/window.rs | 25 ++++++++++++++++++-------
2 files changed, 27 insertions(+), 7 deletions(-)
diff --git a/src/server/cursor.rs b/src/server/cursor.rs
index a784707..d094974 100644
--- a/src/server/cursor.rs
+++ b/src/server/cursor.rs
@@ -2757,9 +2757,18 @@ pub unsafe fn get_border_zone(window: *mut crate::window::Window, lx: f64, ly: f
// resize on both adjacent edges, so the top corners still resize.
// Derived in unscaled units (both inputs are unscaled), then brought
// into screen space alongside the band.
+ // Same silhouette-derived outer-arc radius as draw_borders, so the
+ // pointer's corner squares track the visual corner rings exactly.
+ let r_in = crate::window::widen_corner_radius(
+ (*window).backplate_radius_base(),
+ geom.width,
+ geom.height,
+ ) as f64;
+ let r_out = if r_in > 0.0 { r_in + bw_unscaled } else { 0.0 };
let corner_len = crate::window::border_corner_len(
bw_unscaled,
(*(*window).server).wm.layout.border_corner_length,
+ r_out,
) * scale;
let dist_left = rx + bw;
diff --git a/src/server/window.rs b/src/server/window.rs
index 04f43a6..496b44e 100644
--- a/src/server/window.rs
+++ b/src/server/window.rs
@@ -180,9 +180,13 @@ pub struct FsAnim {
/// Shared by the visual segments (draw_borders) and the pointer zones
/// (cursor.rs get_border_zone) so they always agree. `configured` comes from
/// `border { corner_length= }`; 0 picks the auto formula. Never shorter than
-/// the band width, so a corner is at least its diagonal square.
-pub fn border_corner_len(bw: f64, configured: i32) -> f64 {
- if configured > 0 {
+/// the band width, so a corner is at least its diagonal square. `r_out` is
+/// the corner ring's OUTER arc radius (the window silhouette radius plus the
+/// band; 0 for square windows): the zone must reach past the arc plus half a
+/// band of straight arm, or the widened window corners (~35 logical px)
+/// overflow the corner piece and the arc gets truncated mid-sweep.
+pub fn border_corner_len(bw: f64, configured: i32, r_out: f64) -> f64 {
+ let cl = if configured > 0 {
// Configured lengths predate the band doubling — scale them the same
// way, and keep at least half a band of straight arm (arm = cl − bw)
// so a corner can never collapse to a bare square. (corner_length=16
@@ -192,7 +196,8 @@ pub fn border_corner_len(bw: f64, configured: i32) -> f64 {
// 3× band: the corner arms reach well down each edge (they also
// carry the rounded-corner arc, which eats into the straight run).
(3.0 * bw).max(24.0)
- }
+ };
+ cl.max(r_out + 0.5 * bw)
}
/// Floor on the border grab/reveal band, in unscaled layout pixels. Borders
@@ -3167,7 +3172,15 @@ impl Window {
let bw = band;
let layout = &(*self.server).wm.layout;
- let cl = border_corner_len(bw as f64, layout.border_corner_length) as i32;
+ // The corner ring follows the WINDOW's silhouette: the widened
+ // backplate radius the corner clip and background plate use
+ // (bg_radius above) — not the retired border{corner_radius=}
+ // key, whose separate (much tighter) arc rounded only the
+ // corner piece's outermost tip while the window curved away
+ // underneath it.
+ let r_in = bg_radius;
+ let r_out = if r_in > 0 { r_in + bw } else { 0 };
+ let cl = border_corner_len(bw as f64, layout.border_corner_length, r_out as f64) as i32;
let g = layout.border_segment_gap;
let arm = cl - bw;
// Edge bars span between the corner zones, inset by the gap.
@@ -3239,8 +3252,6 @@ impl Window {
// PHYSICAL px on the final (foam-clipped) box; r_in == 0
// degenerates to the old square L.
let rr = |v: f64| -> u16 { (v.max(0.0) as i32).clamp(0, u16::MAX as i32) as u16 };
- let r_in = border.corner_radius as i32;
- let r_out = if r_in > 0 { r_in + bw } else { 0 };
let s = self.scale;
let ri = rr(r_in as f64 * s);
let ro = rr(r_out as f64 * s);