From 4d60eae82e7ce9ccb5e6d06c8f98f77dcde866ab Mon Sep 17 00:00:00 2001 From: Ivan Molodetskikh Date: Fri, 28 Jun 2024 12:35:12 +0400 Subject: Fix blocked-out + popups and rounded corners window screencasts --- src/niri.rs | 64 +++++++++++++-------------------------- src/render_helpers/solid_color.rs | 4 +++ src/window/mapped.rs | 61 ++++++++++++++++++++++++++++++++++++- 3 files changed, 85 insertions(+), 44 deletions(-) diff --git a/src/niri.rs b/src/niri.rs index 7314bdb4..856f4fc5 100644 --- a/src/niri.rs +++ b/src/niri.rs @@ -1270,11 +1270,10 @@ impl State { }; let scale = Scale::from(output.current_scale().fractional_scale()); - let bbox = window.bbox_with_popups(); - let size = bbox.size.to_physical_precise_ceil(scale); + let bbox = window.bbox_with_popups().to_physical_precise_up(scale); let refresh = output.current_mode().unwrap().refresh as u32; - (CastTarget::Window { id }, size, refresh, true) + (CastTarget::Window { id }, bbox.size, refresh, true) } }; @@ -3502,10 +3501,12 @@ impl Niri { continue; }; - let bbox = mapped.window.bbox_with_popups(); - let size = bbox.size.to_physical_precise_ceil(scale); + let bbox = mapped + .window + .bbox_with_popups() + .to_physical_precise_up(scale); - match cast.ensure_size(size) { + match cast.ensure_size(bbox.size) { Ok(CastSizeChange::Ready) => (), Ok(CastSizeChange::Pending) => continue, Err(err) => { @@ -3519,23 +3520,9 @@ impl Niri { } // FIXME: pointer. - let elements = mapped.render( - renderer, - mapped.window.geometry().loc.to_f64(), - scale, - 1., - RenderTarget::Screencast, - ); - let geo = elements - .iter() - .map(|ele| ele.geometry(scale)) - .reduce(|a, b| a.merge(b)) - .unwrap_or_default(); - let elements = elements.iter().rev().map(|elem| { - RelocateRenderElement::from_element(elem, geo.loc.upscale(-1), Relocate::Relative) - }); + let elements = mapped.render_for_screen_cast(renderer, scale).rev(); - if cast.dequeue_buffer_and_render(renderer, elements, size, scale) { + if cast.dequeue_buffer_and_render(renderer, elements, bbox.size, scale) { cast.last_frame_time = target_presentation_time; } } @@ -3580,8 +3567,10 @@ impl Niri { .unwrap(); let scale = Scale::from(output.current_scale().fractional_scale()); - let bbox = mapped.window.bbox_with_popups(); - let size = bbox.size.to_physical_precise_ceil(scale); + let bbox = mapped + .window + .bbox_with_popups() + .to_physical_precise_up(scale); let mut elements = None; let mut casts_to_stop = vec![]; @@ -3596,7 +3585,7 @@ impl Niri { continue; } - match cast.ensure_size(size) { + match cast.ensure_size(bbox.size) { Ok(CastSizeChange::Ready) => (), Ok(CastSizeChange::Pending) => continue, Err(err) => { @@ -3609,27 +3598,16 @@ impl Niri { continue; } - let (elements, geo) = elements.get_or_insert_with(|| { + let elements = elements.get_or_insert_with(|| { // FIXME: pointer. - let elements = mapped.render( - renderer, - mapped.window.geometry().loc.to_f64(), - scale, - 1., - RenderTarget::Screencast, - ); - let geo = elements - .iter() - .map(|ele| ele.geometry(scale)) - .reduce(|a, b| a.merge(b)) - .unwrap_or_default(); - (elements, geo) - }); - let elements = elements.iter().rev().map(|elem| { - RelocateRenderElement::from_element(elem, geo.loc.upscale(-1), Relocate::Relative) + mapped + .render_for_screen_cast(renderer, scale) + .rev() + .collect::>() }); + let elements = elements.iter(); - if cast.dequeue_buffer_and_render(renderer, elements, size, scale) { + if cast.dequeue_buffer_and_render(renderer, elements, bbox.size, scale) { cast.last_frame_time = target_presentation_time; } } diff --git a/src/render_helpers/solid_color.rs b/src/render_helpers/solid_color.rs index 82144785..83923dbb 100644 --- a/src/render_helpers/solid_color.rs +++ b/src/render_helpers/solid_color.rs @@ -112,6 +112,10 @@ impl SolidColorRenderElement { pub fn color(&self) -> [f32; 4] { self.color } + + pub fn geo(&self) -> Rectangle { + self.geometry + } } impl Element for SolidColorRenderElement { diff --git a/src/window/mapped.rs b/src/window/mapped.rs index 18ace780..8b6b8e61 100644 --- a/src/window/mapped.rs +++ b/src/window/mapped.rs @@ -2,7 +2,7 @@ use std::cell::{Cell, RefCell}; use std::cmp::{max, min}; use std::time::Duration; -use niri_config::WindowRule; +use niri_config::{CornerRadius, WindowRule}; use smithay::backend::renderer::element::surface::render_elements_from_surface_tree; use smithay::backend::renderer::element::{Id, Kind}; use smithay::backend::renderer::gles::GlesRenderer; @@ -22,6 +22,8 @@ use crate::layout::{ InteractiveResizeData, LayoutElement, LayoutElementRenderElement, LayoutElementRenderSnapshot, }; use crate::niri::WindowOffscreenId; +use crate::niri_render_elements; +use crate::render_helpers::border::BorderRenderElement; use crate::render_helpers::renderer::NiriRenderer; use crate::render_helpers::snapshot::RenderSnapshot; use crate::render_helpers::solid_color::{SolidColorBuffer, SolidColorRenderElement}; @@ -76,6 +78,14 @@ pub struct Mapped { last_interactive_resize_start: Cell>, } +niri_render_elements! { + WindowCastRenderElements => { + Layout = LayoutElementRenderElement, + // Blocked-out window with rounded corners. + Border = BorderRenderElement, + } +} + static MAPPED_ID_COUNTER: IdCounter = IdCounter::new(); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -246,6 +256,55 @@ impl Mapped { pub fn last_interactive_resize_start(&self) -> &Cell> { &self.last_interactive_resize_start } + + pub fn render_for_screen_cast( + &self, + renderer: &mut R, + scale: Scale, + ) -> impl DoubleEndedIterator> { + let bbox = self.window.bbox_with_popups().to_physical_precise_up(scale); + + let has_border_shader = BorderRenderElement::has_shader(renderer); + let rules = self.rules(); + let radius = rules.geometry_corner_radius.unwrap_or_default(); + let window_size = self + .size() + .to_f64() + .to_physical_precise_round(scale) + .to_logical(scale); + let radius = radius.fit_to(window_size.w as f32, window_size.h as f32); + + let location = self.window.geometry().loc.to_f64() - bbox.loc.to_logical(scale); + let elements = self.render(renderer, location, scale, 1., RenderTarget::Screencast); + + elements.into_iter().map(move |elem| { + if let LayoutElementRenderElement::SolidColor(elem) = &elem { + // In this branch we're rendering a blocked-out window with a solid color. We need + // to render it with a rounded corner shader even if clip_to_geometry is false, + // because in this case we're assuming that the unclipped window CSD already has + // corners rounded to the user-provided radius, so our blocked-out rendering should + // match that radius. + if radius != CornerRadius::default() && has_border_shader { + let geo = elem.geo(); + return BorderRenderElement::new( + geo.size, + Rectangle::from_loc_and_size((0., 0.), geo.size), + elem.color(), + elem.color(), + 0., + Rectangle::from_loc_and_size((0., 0.), geo.size), + 0., + radius, + scale.x as f32, + ) + .with_location(geo.loc) + .into(); + } + } + + WindowCastRenderElements::from(elem) + }) + } } impl Drop for Mapped { -- cgit