From 281378656bdf9520e5f89d31864b9b2f822d4e3e Mon Sep 17 00:00:00 2001 From: srdusr <99972264+srdusr@users.noreply.github.com> Date: Fri, 23 Aug 2024 22:23:00 +0200 Subject: Round the bottom border strip's corners to match the top MISSING.md listed the border frame's bottom/left/right strips as staying square while the top one (and the titlebar above it) rounds -- "unrelated to client content rounding... not attempted." The left/ right strips genuinely can't participate (border_strips' geometry has them span only the height between the top and bottom strips, no corner to round), but the bottom strip is exactly the same shape as the top one and had no reason left to stay square. decoration::render_border_bottom mirrors render_border_top exactly (round_bottom_corners mirrors round_top_corners), cached the same way in a new border_bottom_decorations map, and drawn in both render loops via the same all-or-nothing occlusion check the top strip already uses - pulled out of the left/right strips' per-fragment occlusion splitting into its own dedicated bitmap path, matching top's existing trade-off (cropping a rounded bitmap's source rect per fragment is real extra work for a strip this thin) rather than inventing a new one. One real bug caught before it shipped: round_bottom_corners' corner- centre math (height - r - 1) panics on unsigned underflow whenever the radius clamp lands on the strip's own full height (a real, common case - a 2px-thick test strip hits it immediately). Fixed by computing the centre as a signed offset instead, mirroring how the existing dx/dy distance math already avoids the same class of issue. --- crates/wayland/src/udev/platform.rs | 1 + crates/wayland/src/udev/render.rs | 29 +++++++++++++++++++++-------- 2 files changed, 22 insertions(+), 8 deletions(-) (limited to 'crates/wayland/src/udev') diff --git a/crates/wayland/src/udev/platform.rs b/crates/wayland/src/udev/platform.rs index 8043e20..f562da2 100644 --- a/crates/wayland/src/udev/platform.rs +++ b/crates/wayland/src/udev/platform.rs @@ -178,6 +178,7 @@ impl UdevPlatform { dead_layer_surfaces: HashSet::new(), decorations: HashMap::new(), border_top_decorations: HashMap::new(), + border_bottom_decorations: HashMap::new(), shadow_buffers: HashMap::new(), rounded_corners_program: None, content_epoch: HashMap::new(), diff --git a/crates/wayland/src/udev/render.rs b/crates/wayland/src/udev/render.rs index 65c21dd..caf0e0e 100644 --- a/crates/wayland/src/udev/render.rs +++ b/crates/wayland/src/udev/render.rs @@ -236,12 +236,13 @@ impl CompState { if w.border_width > 0 { let color = crate::state::effective_border_color(w.border_color, focused == Some(id)); let strips = decoration::border_strips(geom, w.border_width); - // Strip 0 (top) rounded to match the titlebar under - // it - see `render_border_top`'s doc comment - so - // it's a cached bitmap (rebuilt only in + // Strips 0/1 (top/bottom) rounded on their own two + // corners - see `render_border_top`/ + // `render_border_bottom`'s doc comments - so both + // are cached bitmaps (rebuilt only in // `redraw_decoration_buffer`, same as the titlebar // itself), not rasterized fresh here every frame. - // Not fragment-clipped like the other three strips + // Not fragment-clipped like the left/right strips // below - cropping a bitmap's source rect per // fragment is real extra work for a strip that's // only `border_width` pixels tall to begin with, so @@ -257,9 +258,21 @@ impl CompState { } } } - // The other three strips are persistent - // `SolidColorBuffer`s updated in place, not rebuilt - // with a fresh `Id` every frame - see + // Same all-or-nothing bitmap treatment as the top + // strip, for its own two corners - see + // `decoration::render_border_bottom`'s doc comment. + if strips[1].width > 0 && strips[1].height > 0 && !strips[1].subtract_all(&occluders).is_empty() { + if let Some(buffer) = self.border_bottom_decorations.get(&id) { + let pos = ((strips[1].x - origin.x) as f64, (strips[1].y - origin.y) as f64); + match MemoryRenderBufferRenderElement::from_buffer(&mut udev.renderer, pos, buffer, None, None, None, Kind::Unspecified) { + Ok(elem) => custom_elements.push(crate::elements::OverlayElement::Memory(elem)), + Err(e) => log::warn!("udev: failed to import bottom border buffer: {e}"), + } + } + } + // The remaining two strips (left/right) are + // persistent `SolidColorBuffer`s updated in place, + // not rebuilt with a fresh `Id` every frame - see // `elements::border_side_render_element`'s doc // comment for why that distinction is load-bearing // for damage tracking, not cosmetic. Each strip is @@ -269,7 +282,7 @@ impl CompState { // here. let pool = self.border_side_buffers.entry(id).or_default(); let mut buf_index = 0; - for strip in &strips[1..] { + for strip in &strips[2..] { if strip.width == 0 || strip.height == 0 { continue; } -- cgit v1.2.3