diff options
| author | srdusr <[email protected]> | 2025-03-03 01:47:00 +0200 |
|---|---|---|
| committer | srdusr <[email protected]> | 2025-03-03 01:47:00 +0200 |
| commit | f83082a3b9b75e6f1bc4187850bea1b7408cffca (patch) | |
| tree | 4135aaa04f4aeea60a597062883d0bcf9c7f2867 /crates/wayland/src/winit | |
| parent | d303c276e289c9c7146cf74ccad2743246922248 (diff) | |
| download | srdwm-f83082a3b9b75e6f1bc4187850bea1b7408cffca.tar.gz srdwm-f83082a3b9b75e6f1bc4187850bea1b7408cffca.zip | |
Fix VT-switch DPMS blank-screen and CSD corner-crop staircase bugs
VT-switch resume: reasserting the CRTC's mode-setting state was never
enough on its own - display power (DPMS) is separate KMS state, and
nothing here ever touched it after a real switch-away-and-back. Page
flips kept succeeding with zero errors logged for the rest of a real
30+ minute session while the panel itself simply stayed dark, which is
what actually explains a user report of the screen and keyboard input
never recovering after one VT switch. Sets DPMS-on unconditionally on
every resume now, the same property zwlr_output_power_v1 already
writes for an explicit client request.
Corner rendering: both backends' side-strip crop (the fix that keeps a
window's flat left/right border strips from poking a solid-coloured
square through the top/bottom strip's own rounded curve) only ever
activated for `w.decorated` windows. An undecorated/CSD window's crop
depends on its *content* actually getting masked to match - the
winit backend never checked that at all, so every CSD window with a
nonzero border_width got the uncropped, "staircase" artifact
unconditionally, confirmed live via a highlighted border colour and
raw pixel sampling. Ported the udev backend's own `border_curve_is_safe`
check (decorated OR content-will-be-masked) into winit, using the
cheap "does this surface have subsurface children" test both content-
masking code paths already gate success on, rather than duplicating
either one's real (comparatively expensive) rendering work just to
probe it.
Full workspace build + clippy -D warnings + test suite (378 tests) green.
Diffstat (limited to 'crates/wayland/src/winit')
| -rw-r--r-- | crates/wayland/src/winit/render.rs | 49 |
1 files changed, 42 insertions, 7 deletions
diff --git a/crates/wayland/src/winit/render.rs b/crates/wayland/src/winit/render.rs index c245aa2..f4cb7af 100644 --- a/crates/wayland/src/winit/render.rs +++ b/crates/wayland/src/winit/render.rs @@ -201,6 +201,37 @@ impl WaylandPlatform { // really committed - see `effective_frame`'s own doc comment // and the matching comment in `udev/render.rs`'s render loop. let frame = self.state.effective_frame(id, geom); + // Whether this window's *content* will actually get its + // corners rounded this frame - an undecorated (CSD) window's + // border has no titlebar band to safely absorb its own top/ + // bottom strip's curve-only "extra" rows into (see `decoration:: + // border_top_visible_rows`'s doc comment), so cropping them -- + // and the flat side strips below, which would otherwise poke a + // solid-coloured straight line through that curve's own + // transparent cutout - is only safe when the *content* is + // also going to be cut to match. This used to check `w.decorated` + // alone, which is wrong for exactly the CSD case those crops + // exist for in the first place: an undecorated window's border + // never got cropped at all, regardless of whether its content + // masking would actually succeed, guaranteeing the square- + // meets-curve artifact this doc comment is describing on every + // single CSD window with a nonzero `border_width` - reported + // live (screenshot + raw pixel sampling) as a hard right-angle + // "staircase" where a smooth curve should be, on both a CSD + // window (Firefox, content masking legitimately in play) and, + // via the matching bug in `udev/render.rs`, windows this same + // reasoning also affects there. `rounded_content_element`'s own + // (and `rounded_corners_pixman::masked_content_buffer`'s, on + // the udev backend) only real failure mode is a surface with + // subsurface children - checking that directly here is the + // same cheap, single-condition test both of those already + // gate on internally, without needing to actually run either + // one's real (comparatively expensive) rendering work twice + // just to ask "would this have worked". + let content_will_be_masked = rounded_corners_enabled + && self.wm.borrow().resizing_window() != Some(id) + && self.state.id_to_window.get(&id).and_then(crate::elements::window_wl_surface).is_some_and(|surface| smithay::wayland::compositor::get_children(&surface).is_empty()); + let border_curve_is_safe = w.decorated || content_will_be_masked; if let Some(deco) = self.state.decorations.get(&id) { // Fragment-clipped, same as udev/render.rs's matching titlebar // push - see that comment for why all-or-nothing (skip @@ -252,7 +283,7 @@ impl WaylandPlatform { // titlebar band to safely absorb this buffer's own // corner-curve-only extra rows, so they're cropped // away instead of landing on real content. - let (row0, rows, shift) = decoration::border_top_visible_rows(w.decorated, w.border_width, w.corner_radius); + let (row0, rows, shift) = decoration::border_top_visible_rows(border_curve_is_safe, w.border_width, w.corner_radius); let pos = (strips[0].x as f64, (strips[0].y + shift as i32) as f64); let src = Some(Rectangle::new(Point::from((0.0, row0 as f64)), Size::from((strips[0].width as f64, rows as f64)))); match MemoryRenderBufferRenderElement::from_buffer(renderer, pos, buffer, None, src, None, Kind::Unspecified) { @@ -268,7 +299,7 @@ impl WaylandPlatform { if let Some(buffer) = self.state.border_bottom_decorations.get(&id) { // See `decoration::border_bottom_visible_rows`'s // own doc comment. - let (row0, rows, shift) = decoration::border_bottom_visible_rows(w.decorated, w.border_width, w.corner_radius); + let (row0, rows, shift) = decoration::border_bottom_visible_rows(border_curve_is_safe, w.border_width, w.corner_radius); let pos = (strips[1].x as f64, (strips[1].y - shift as i32) as f64); let src = Some(Rectangle::new(Point::from((0.0, row0 as f64)), Size::from((strips[1].width as f64, rows as f64)))); match MemoryRenderBufferRenderElement::from_buffer(renderer, pos, buffer, None, src, None, Kind::Unspecified) { @@ -286,11 +317,15 @@ impl WaylandPlatform { // solid fill bled through the curve's own transparent // cutout as a straight vertical line poking out of an // otherwise correctly-rounded corner - reported live, - // confirmed via raw pixel sampling on the udev backend; - // this backend shares the identical strip geometry and was - // never actually confirmed clean, just never specifically - // screenshotted the same way. - let extra = if w.decorated { w.border_width.max(w.corner_radius).saturating_sub(w.border_width) } else { 0 }; + // confirmed via raw pixel sampling: a hard right-angle + // "staircase" instead of a curve, on an undecorated (CSD) + // window specifically, since `border_curve_is_safe` (not + // `w.decorated` alone - see this window's own doc comment + // above) is what actually decides whether this crop is + // safe to apply, and the CSD case is exactly the one + // `w.decorated` alone always answered "no" to regardless + // of whether content masking would really succeed. + let extra = if border_curve_is_safe { w.border_width.max(w.corner_radius).saturating_sub(w.border_width) } else { 0 }; let mut side_strips = [strips[2], strips[3]]; for s in &mut side_strips { s.y += extra as i32; |