diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/handlers/compositor.rs | 58 | ||||
| -rw-r--r-- | src/handlers/xdg_shell.rs | 3 | ||||
| -rw-r--r-- | src/layout/closing_window.rs | 2 | ||||
| -rw-r--r-- | src/layout/mod.rs | 20 | ||||
| -rw-r--r-- | src/layout/tile.rs | 101 | ||||
| -rw-r--r-- | src/niri.rs | 5 | ||||
| -rw-r--r-- | src/render_helpers/mod.rs | 81 | ||||
| -rw-r--r-- | src/render_helpers/surface.rs | 108 | ||||
| -rw-r--r-- | src/window/mapped.rs | 111 |
9 files changed, 284 insertions, 205 deletions
diff --git a/src/handlers/compositor.rs b/src/handlers/compositor.rs index 2e657151..9473de10 100644 --- a/src/handlers/compositor.rs +++ b/src/handlers/compositor.rs @@ -16,6 +16,7 @@ use smithay::wayland::dmabuf::get_dmabuf; use smithay::wayland::shm::{ShmHandler, ShmState}; use smithay::{delegate_compositor, delegate_shm}; +use crate::layout::LayoutElement; use crate::niri::{ClientState, State}; use crate::window::{InitialConfigureState, Mapped, ResolvedWindowRules, Unmapped}; @@ -80,6 +81,33 @@ impl CompositorHandler for State { fn commit(&mut self, surface: &WlSurface) { let _span = tracy_client::span!("CompositorHandler::commit"); + let mut root_surface = surface.clone(); + while let Some(parent) = get_parent(&root_surface) { + root_surface = parent; + } + + // Update the cached root surface. + self.niri + .root_surface + .insert(surface.clone(), root_surface.clone()); + + // Check if this root surface got unmapped to snapshot it before on_commit_buffer_handler() + // overwrites the buffer. + if surface == &root_surface { + let got_unmapped = with_states(surface, |states| { + let attrs = states.cached_state.current::<SurfaceAttributes>(); + matches!(attrs.buffer, Some(BufferAssignment::Removed)) + }); + + if got_unmapped { + if let Some((mapped, _)) = self.niri.layout.find_window_and_output(surface) { + self.backend.with_primary_renderer(|renderer| { + mapped.render_and_store_snapshot(renderer); + }); + } + } + } + on_commit_buffer_handler::<Self>(surface); self.backend.early_import(surface); @@ -87,11 +115,6 @@ impl CompositorHandler for State { return; } - let mut root_surface = surface.clone(); - while let Some(parent) = get_parent(&root_surface) { - root_surface = parent; - } - if surface == &root_surface { // This is a root surface commit. It might have mapped a previously-unmapped toplevel. if let Entry::Occupied(entry) = self.niri.unmapped_windows.entry(surface.clone()) { @@ -195,8 +218,11 @@ impl CompositorHandler for State { false }); - // Must start the close animation before window.on_commit(). - if !is_mapped { + if is_mapped { + // The surface remains mapped; clear any cached render snapshot. + let _ = mapped.take_last_render(); + } else { + // Must start the close animation before window.on_commit(). self.backend.with_primary_renderer(|renderer| { self.niri .layout @@ -288,6 +314,24 @@ impl CompositorHandler for State { } } } + + fn destroyed(&mut self, surface: &WlSurface) { + // Clients may destroy their subsurfaces before the main surface. Ensure we have a snapshot + // when that happens, so that the closing animation includes all these subsurfaces. + // + // Test client: alacritty with CSD. + if let Some(root) = self.niri.root_surface.get(surface) { + if let Some((mapped, _)) = self.niri.layout.find_window_and_output(root) { + self.backend.with_primary_renderer(|renderer| { + mapped.render_and_store_snapshot(renderer); + }); + } + } + + self.niri + .root_surface + .retain(|k, v| k != surface && v != surface); + } } impl BufferHandler for State { diff --git a/src/handlers/xdg_shell.rs b/src/handlers/xdg_shell.rs index 2cbaad25..53001459 100644 --- a/src/handlers/xdg_shell.rs +++ b/src/handlers/xdg_shell.rs @@ -383,6 +383,9 @@ impl XdgShellHandler for State { let output = output.clone(); self.backend.with_primary_renderer(|renderer| { + mapped.render_and_store_snapshot(renderer); + }); + self.backend.with_primary_renderer(|renderer| { self.niri .layout .start_close_animation_for_window(renderer, &window); diff --git a/src/layout/closing_window.rs b/src/layout/closing_window.rs index ec565ebf..3de0d51f 100644 --- a/src/layout/closing_window.rs +++ b/src/layout/closing_window.rs @@ -59,7 +59,7 @@ impl ClosingWindow { #[allow(clippy::too_many_arguments)] pub fn new<E: RenderElement<GlesRenderer>>( renderer: &mut GlesRenderer, - snapshot: RenderSnapshot<E>, + snapshot: RenderSnapshot<E, E>, scale: i32, center: Point<i32, Logical>, pos: Point<i32, Logical>, diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 18870025..073ae804 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -36,10 +36,11 @@ use std::time::Duration; use niri_config::{CenterFocusedColumn, Config, Struts}; use niri_ipc::SizeChange; -use smithay::backend::renderer::element::solid::SolidColorRenderElement; +use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement}; use smithay::backend::renderer::element::surface::WaylandSurfaceRenderElement; +use smithay::backend::renderer::element::texture::TextureBuffer; use smithay::backend::renderer::element::Id; -use smithay::backend::renderer::gles::GlesRenderer; +use smithay::backend::renderer::gles::{GlesRenderer, GlesTexture}; use smithay::output::Output; use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface; use smithay::utils::{Logical, Point, Scale, Size, Transform}; @@ -48,9 +49,8 @@ use self::monitor::Monitor; pub use self::monitor::MonitorRenderElement; use self::workspace::{compute_working_area, Column, ColumnWidth, OutputId, Workspace}; use crate::niri_render_elements; -use crate::render_helpers::primary_gpu_texture::PrimaryGpuTextureRenderElement; use crate::render_helpers::renderer::NiriRenderer; -use crate::render_helpers::{RenderSnapshot, RenderTarget}; +use crate::render_helpers::{BakedBuffer, RenderSnapshot, RenderTarget}; use crate::utils::output_size; use crate::window::ResolvedWindowRules; @@ -67,12 +67,8 @@ niri_render_elements! { } } -niri_render_elements! { - LayoutElementSnapshotRenderElements => { - Texture = PrimaryGpuTextureRenderElement, - SolidColor = SolidColorRenderElement, - } -} +pub type LayoutElementRenderSnapshot = + RenderSnapshot<BakedBuffer<TextureBuffer<GlesTexture>>, BakedBuffer<SolidColorBuffer>>; pub trait LayoutElement { /// Type that can be used as a unique ID of this element. @@ -110,7 +106,7 @@ pub trait LayoutElement { target: RenderTarget, ) -> Vec<LayoutElementRenderElement<R>>; - fn take_last_render(&self) -> RenderSnapshot<LayoutElementSnapshotRenderElements>; + fn take_last_render(&self) -> LayoutElementRenderSnapshot; fn request_size(&self, size: Size<i32, Logical>); fn request_fullscreen(&self, size: Size<i32, Logical>); @@ -1930,7 +1926,7 @@ mod tests { vec![] } - fn take_last_render(&self) -> RenderSnapshot<LayoutElementSnapshotRenderElements> { + fn take_last_render(&self) -> LayoutElementRenderSnapshot { RenderSnapshot::default() } diff --git a/src/layout/tile.rs b/src/layout/tile.rs index fb825184..5cc89073 100644 --- a/src/layout/tile.rs +++ b/src/layout/tile.rs @@ -3,22 +3,19 @@ use std::rc::Rc; use std::time::Duration; use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement}; -use smithay::backend::renderer::element::utils::{ - Relocate, RelocateRenderElement, RescaleRenderElement, -}; +use smithay::backend::renderer::element::utils::RescaleRenderElement; use smithay::backend::renderer::element::{Element, Kind}; use smithay::backend::renderer::gles::GlesRenderer; use smithay::utils::{Logical, Point, Rectangle, Scale, Size}; use super::focus_ring::{FocusRing, FocusRingRenderElement}; -use super::{ - LayoutElement, LayoutElementRenderElement, LayoutElementSnapshotRenderElements, Options, -}; +use super::{LayoutElement, LayoutElementRenderElement, Options}; use crate::animation::Animation; use crate::niri_render_elements; use crate::render_helpers::offscreen::OffscreenRenderElement; +use crate::render_helpers::primary_gpu_texture::PrimaryGpuTextureRenderElement; use crate::render_helpers::renderer::NiriRenderer; -use crate::render_helpers::{RenderSnapshot, RenderTarget}; +use crate::render_helpers::{RenderSnapshot, RenderTarget, ToRenderElement}; /// Toplevel window with decorations. #[derive(Debug)] @@ -65,7 +62,7 @@ niri_render_elements! { niri_render_elements! { TileSnapshotRenderElement => { - LayoutElement = RelocateRenderElement<LayoutElementSnapshotRenderElements>, + Texture = PrimaryGpuTextureRenderElement, FocusRing = FocusRingRenderElement, SolidColor = SolidColorRenderElement, } @@ -417,52 +414,70 @@ impl<W: LayoutElement> Tile<W> { } } - pub fn take_snapshot_for_close_anim( + fn render_snapshot<C>( &self, renderer: &mut GlesRenderer, scale: Scale<f64>, view_size: Size<i32, Logical>, - ) -> RenderSnapshot<TileSnapshotRenderElement> { - let snapshot = self.window.take_last_render(); - if snapshot.contents.is_empty() { - return RenderSnapshot::default(); - } + contents: Vec<C>, + ) -> Vec<TileSnapshotRenderElement> + where + C: ToRenderElement<RenderElement: Into<TileSnapshotRenderElement>>, + { + let alpha = if self.is_fullscreen { + 1. + } else { + self.window.rules().opacity.unwrap_or(1.).clamp(0., 1.) + }; - let mut process = |contents| { - let mut rv = vec![]; + let mut rv = vec![]; - let buf_pos = - (self.window_loc() + self.window.buf_loc()).to_physical_precise_round(scale); - for elem in contents { - let elem = RelocateRenderElement::from_element(elem, buf_pos, Relocate::Relative); - rv.push(elem.into()); - } + for baked in contents { + let elem = baked.to_render_element(self.window_loc(), scale, alpha, Kind::Unspecified); + rv.push(elem.into()); + } - if let Some(width) = self.effective_border_width() { - rv.extend( - self.border - .render(renderer, Point::from((width, width)), scale, view_size) - .map(Into::into), - ); - } + if let Some(width) = self.effective_border_width() { + rv.extend( + self.border + .render(renderer, Point::from((width, width)), scale, view_size) + .map(Into::into), + ); + } - if self.is_fullscreen { - let elem = SolidColorRenderElement::from_buffer( - &self.fullscreen_backdrop, - Point::from((0, 0)), - scale, - 1., - Kind::Unspecified, - ); - rv.push(elem.into()); - } + if self.is_fullscreen { + let elem = SolidColorRenderElement::from_buffer( + &self.fullscreen_backdrop, + Point::from((0, 0)), + scale, + 1., + Kind::Unspecified, + ); + rv.push(elem.into()); + } - rv - }; + rv + } + + pub fn take_snapshot_for_close_anim( + &self, + renderer: &mut GlesRenderer, + scale: Scale<f64>, + view_size: Size<i32, Logical>, + ) -> RenderSnapshot<TileSnapshotRenderElement, TileSnapshotRenderElement> { + let snapshot = self.window.take_last_render(); + if snapshot.contents.is_empty() { + return RenderSnapshot::default(); + } RenderSnapshot { - contents: process(snapshot.contents), - blocked_out_contents: process(snapshot.blocked_out_contents), + contents: self.render_snapshot(renderer, scale, view_size, snapshot.contents), + blocked_out_contents: self.render_snapshot( + renderer, + scale, + view_size, + snapshot.blocked_out_contents, + ), block_out_from: snapshot.block_out_from, } } diff --git a/src/niri.rs b/src/niri.rs index 1eedcffa..f14f7dcd 100644 --- a/src/niri.rs +++ b/src/niri.rs @@ -151,6 +151,10 @@ pub struct Niri { // Windows which don't have a buffer attached yet. pub unmapped_windows: HashMap<WlSurface, Unmapped>, + // Cached root surface for every surface, so that we can access it in destroyed() where the + // normal get_parent() is cleared out. + pub root_surface: HashMap<WlSurface, WlSurface>, + pub output_state: HashMap<Output, OutputState>, pub output_by_name: HashMap<String, Output>, @@ -1318,6 +1322,7 @@ impl Niri { output_state: HashMap::new(), output_by_name: HashMap::new(), unmapped_windows: HashMap::new(), + root_surface: HashMap::new(), monitors_active: true, devices: HashSet::new(), diff --git a/src/render_helpers/mod.rs b/src/render_helpers/mod.rs index c6c9fed1..e780de4e 100644 --- a/src/render_helpers/mod.rs +++ b/src/render_helpers/mod.rs @@ -3,15 +3,19 @@ use std::ptr; use anyhow::{ensure, Context}; use niri_config::BlockOutFrom; use smithay::backend::allocator::Fourcc; -use smithay::backend::renderer::element::RenderElement; +use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement}; +use smithay::backend::renderer::element::texture::{TextureBuffer, TextureRenderElement}; +use smithay::backend::renderer::element::{Kind, RenderElement}; use smithay::backend::renderer::gles::{GlesMapping, GlesRenderer, GlesTexture}; use smithay::backend::renderer::sync::SyncPoint; use smithay::backend::renderer::{buffer_dimensions, Bind, ExportMem, Frame, Offscreen, Renderer}; use smithay::reexports::wayland_server::protocol::wl_buffer::WlBuffer; use smithay::reexports::wayland_server::protocol::wl_shm; -use smithay::utils::{Physical, Rectangle, Scale, Size, Transform}; +use smithay::utils::{Logical, Physical, Point, Rectangle, Scale, Size, Transform}; use smithay::wayland::shm; +use self::primary_gpu_texture::PrimaryGpuTextureRenderElement; + pub mod gradient; pub mod offscreen; pub mod primary_gpu_pixel_shader; @@ -32,20 +36,85 @@ pub enum RenderTarget { ScreenCapture, } +/// Buffer with location, src and dst. +#[derive(Debug)] +pub struct BakedBuffer<B> { + pub buffer: B, + pub location: Point<i32, Logical>, + pub src: Option<Rectangle<f64, Logical>>, + pub dst: Option<Size<i32, Logical>>, +} + /// Snapshot of a render. #[derive(Debug)] -pub struct RenderSnapshot<E> { +pub struct RenderSnapshot<C, B> { /// Contents for a normal render. - pub contents: Vec<E>, + pub contents: Vec<C>, /// Blocked-out contents. - pub blocked_out_contents: Vec<E>, + pub blocked_out_contents: Vec<B>, /// Where the contents were blocked out from at the time of the snapshot. pub block_out_from: Option<BlockOutFrom>, } -impl<E> Default for RenderSnapshot<E> { +pub trait ToRenderElement { + type RenderElement; + + fn to_render_element( + &self, + location: Point<i32, Logical>, + scale: Scale<f64>, + alpha: f32, + kind: Kind, + ) -> Self::RenderElement; +} + +impl ToRenderElement for BakedBuffer<TextureBuffer<GlesTexture>> { + type RenderElement = PrimaryGpuTextureRenderElement; + + fn to_render_element( + &self, + location: Point<i32, Logical>, + scale: Scale<f64>, + alpha: f32, + kind: Kind, + ) -> Self::RenderElement { + let elem = TextureRenderElement::from_texture_buffer( + (location + self.location).to_physical_precise_round(scale), + &self.buffer, + Some(alpha), + self.src, + self.dst, + kind, + ); + PrimaryGpuTextureRenderElement(elem) + } +} + +impl ToRenderElement for BakedBuffer<SolidColorBuffer> { + type RenderElement = SolidColorRenderElement; + + fn to_render_element( + &self, + location: Point<i32, Logical>, + scale: Scale<f64>, + alpha: f32, + kind: Kind, + ) -> Self::RenderElement { + SolidColorRenderElement::from_buffer( + &self.buffer, + (location + self.location) + .to_physical_precise_round(scale) + .to_i32_round(), + scale, + alpha, + kind, + ) + } +} + +impl<C, B> Default for RenderSnapshot<C, B> { fn default() -> Self { Self { contents: Default::default(), diff --git a/src/render_helpers/surface.rs b/src/render_helpers/surface.rs index ae7ffc32..21141b30 100644 --- a/src/render_helpers/surface.rs +++ b/src/render_helpers/surface.rs @@ -1,41 +1,25 @@ -use smithay::backend::renderer::element::surface::WaylandSurfaceRenderElement; -use smithay::backend::renderer::element::texture::{TextureBuffer, TextureRenderElement}; -use smithay::backend::renderer::element::Kind; -use smithay::backend::renderer::gles::GlesRenderer; +use smithay::backend::renderer::element::texture::TextureBuffer; +use smithay::backend::renderer::gles::{GlesRenderer, GlesTexture}; use smithay::backend::renderer::utils::{import_surface, RendererSurfaceStateUserData}; use smithay::backend::renderer::Renderer as _; use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface; -use smithay::utils::{Physical, Point, Scale}; +use smithay::utils::{Logical, Point}; use smithay::wayland::compositor::{with_surface_tree_downward, TraversalAction}; -use super::primary_gpu_texture::PrimaryGpuTextureRenderElement; -use super::renderer::NiriRenderer; -use crate::layout::{LayoutElementRenderElement, LayoutElementSnapshotRenderElements}; +use super::BakedBuffer; -/// Renders elements from a surface tree, as well as saves them as textures into `storage`. -/// -/// Saved textures are based at (0, 0) to facilitate later offscreening. This is why the location -/// argument is split into `location` and `offset`: the former is ignored for saved textures, but -/// the latter isn't (for things like popups). -#[allow(clippy::too_many_arguments)] -pub fn render_and_save_from_surface_tree<R: NiriRenderer>( - renderer: &mut R, +/// Renders elements from a surface tree as textures into `storage`. +pub fn render_snapshot_from_surface_tree( + renderer: &mut GlesRenderer, surface: &WlSurface, - location: Point<f64, Physical>, - offset: Point<f64, Physical>, - scale: Scale<f64>, - alpha: f32, - kind: Kind, - elements: &mut Vec<LayoutElementRenderElement<R>>, - storage: &mut Option<&mut Vec<LayoutElementSnapshotRenderElements>>, + location: Point<i32, Logical>, + storage: &mut Vec<BakedBuffer<TextureBuffer<GlesTexture>>>, ) { - let _span = tracy_client::span!("render_and_save_from_surface_tree"); - - let base_pos = location; + let _span = tracy_client::span!("render_snapshot_from_surface_tree"); with_surface_tree_downward( surface, - location + offset, + location, |_, states, location| { let mut location = *location; let data = states.data_map.get::<RendererSurfaceStateUserData>(); @@ -44,7 +28,7 @@ pub fn render_and_save_from_surface_tree<R: NiriRenderer>( let data = &*data.borrow(); if let Some(view) = data.view() { - location += view.offset.to_f64().to_physical(scale); + location += view.offset; TraversalAction::DoChildren(location) } else { TraversalAction::SkipChildren @@ -53,62 +37,44 @@ pub fn render_and_save_from_surface_tree<R: NiriRenderer>( TraversalAction::SkipChildren } }, - |surface, states, location| { + |_, states, location| { let mut location = *location; let data = states.data_map.get::<RendererSurfaceStateUserData>(); if let Some(data) = data { if let Some(view) = data.borrow().view() { - location += view.offset.to_f64().to_physical(scale); + location += view.offset; } else { return; } - let elem = match WaylandSurfaceRenderElement::from_surface( - renderer, surface, states, location, alpha, kind, - ) { - Ok(elem) => elem, - Err(err) => { - warn!("failed to import surface: {err:?}"); - return; - } - }; - - elements.push(elem.into()); - - if let Some(storage) = storage { - let renderer = renderer.as_gles_renderer(); - // FIXME (possibly in Smithay): this causes a re-upload for shm textures. - if let Err(err) = import_surface(renderer, states) { - warn!("failed to import surface: {err:?}"); - return; - } + if let Err(err) = import_surface(renderer, states) { + warn!("failed to import surface: {err:?}"); + return; + } - let data = data.borrow(); - let view = data.view().unwrap(); - let Some(texture) = data.texture::<GlesRenderer>(renderer.id()) else { - return; - }; + let data = data.borrow(); + let view = data.view().unwrap(); + let Some(texture) = data.texture::<GlesRenderer>(renderer.id()) else { + return; + }; - let buffer = TextureBuffer::from_texture( - renderer, - texture.clone(), - data.buffer_scale(), - data.buffer_transform(), - None, - ); + let buffer = TextureBuffer::from_texture( + renderer, + texture.clone(), + data.buffer_scale(), + data.buffer_transform(), + None, + ); - let elem = TextureRenderElement::from_texture_buffer( - location - base_pos, - &buffer, - Some(alpha), - Some(view.src), - Some(view.dst), - kind, - ); + let baked = BakedBuffer { + buffer, + location, + src: Some(view.src), + dst: Some(view.dst), + }; - storage.push(PrimaryGpuTextureRenderElement(elem).into()); - } + storage.push(baked); } }, |_, _, _| true, diff --git a/src/window/mapped.rs b/src/window/mapped.rs index 7210f8b0..58f733ba 100644 --- a/src/window/mapped.rs +++ b/src/window/mapped.rs @@ -3,7 +3,8 @@ use std::cmp::{max, min}; use niri_config::{BlockOutFrom, WindowRule}; use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement}; -use smithay::backend::renderer::element::{Id, Kind}; +use smithay::backend::renderer::element::{AsRenderElements, Id, Kind}; +use smithay::backend::renderer::gles::GlesRenderer; use smithay::desktop::space::SpaceElement as _; use smithay::desktop::{PopupManager, Window}; use smithay::output::Output; @@ -15,13 +16,11 @@ use smithay::wayland::compositor::{send_surface_state, with_states}; use smithay::wayland::shell::xdg::{SurfaceCachedState, ToplevelSurface}; use super::{ResolvedWindowRules, WindowRef}; -use crate::layout::{ - LayoutElement, LayoutElementRenderElement, LayoutElementSnapshotRenderElements, -}; +use crate::layout::{LayoutElement, LayoutElementRenderElement, LayoutElementRenderSnapshot}; use crate::niri::WindowOffscreenId; use crate::render_helpers::renderer::NiriRenderer; -use crate::render_helpers::surface::render_and_save_from_surface_tree; -use crate::render_helpers::{RenderSnapshot, RenderTarget}; +use crate::render_helpers::surface::render_snapshot_from_surface_tree; +use crate::render_helpers::{BakedBuffer, RenderSnapshot, RenderTarget}; #[derive(Debug)] pub struct Mapped { @@ -43,7 +42,7 @@ pub struct Mapped { block_out_buffer: RefCell<SolidColorBuffer>, /// Snapshot of the last render for use in the close animation. - last_render: RefCell<RenderSnapshot<LayoutElementSnapshotRenderElements>>, + last_render: RefCell<LayoutElementRenderSnapshot>, } impl Mapped { @@ -95,6 +94,42 @@ impl Mapped { self.is_focused = is_focused; self.need_to_recompute_rules = true; } + + pub fn render_and_store_snapshot(&self, renderer: &mut GlesRenderer) { + let mut snapshot = self.last_render.borrow_mut(); + if !snapshot.contents.is_empty() { + return; + } + + snapshot.contents.clear(); + snapshot.blocked_out_contents.clear(); + snapshot.block_out_from = self.rules.block_out_from; + + let mut buffer = self.block_out_buffer.borrow_mut(); + buffer.resize(self.window.geometry().size); + snapshot.blocked_out_contents = vec![BakedBuffer { + buffer: buffer.clone(), + location: Point::from((0, 0)), + src: None, + dst: None, + }]; + + let buf_pos = self.window.geometry().loc.upscale(-1); + + let surface = self.toplevel().wl_surface(); + for (popup, popup_offset) in PopupManager::popups_for_surface(surface) { + let offset = self.window.geometry().loc + popup_offset - popup.geometry().loc; + + render_snapshot_from_surface_tree( + renderer, + popup.wl_surface(), + buf_pos + offset, + &mut snapshot.contents, + ); + } + + render_snapshot_from_surface_tree(renderer, surface, buf_pos, &mut snapshot.contents); + } } impl LayoutElement for Mapped { @@ -131,10 +166,9 @@ impl LayoutElement for Mapped { Some(BlockOutFrom::ScreenCapture) => target != RenderTarget::Output, }; - let mut buffer = self.block_out_buffer.borrow_mut(); - buffer.resize(self.window.geometry().size); - if block_out { + let mut buffer = self.block_out_buffer.borrow_mut(); + buffer.resize(self.window.geometry().size); let elem = SolidColorRenderElement::from_buffer( &buffer, location.to_physical_precise_round(scale), @@ -146,64 +180,11 @@ impl LayoutElement for Mapped { } else { let buf_pos = location - self.window.geometry().loc; let buf_pos = buf_pos.to_physical_precise_round(scale); - - let mut elements = vec![]; - - // If we're rendering for output, save into last_render. - let mut last_render = self.last_render.borrow_mut(); - // FIXME: when preview-render is active, last render contents will never update. - let mut storage = if target == RenderTarget::Output { - last_render.contents.clear(); - last_render.block_out_from = self.rules.block_out_from; - last_render.blocked_out_contents = vec![SolidColorRenderElement::from_buffer( - &buffer, - (0, 0), - scale, - alpha, - Kind::Unspecified, - ) - .into()]; - - Some(&mut last_render.contents) - } else { - None - }; - - let surface = self.toplevel().wl_surface(); - for (popup, popup_offset) in PopupManager::popups_for_surface(surface) { - let offset = (self.window.geometry().loc + popup_offset - popup.geometry().loc) - .to_physical_precise_round(scale); - - render_and_save_from_surface_tree( - renderer, - popup.wl_surface(), - buf_pos, - offset, - scale, - alpha, - Kind::Unspecified, - &mut elements, - &mut storage, - ); - } - - render_and_save_from_surface_tree( - renderer, - surface, - buf_pos, - Point::from((0., 0.)), - scale, - alpha, - Kind::Unspecified, - &mut elements, - &mut storage, - ); - - elements + self.window.render_elements(renderer, buf_pos, scale, alpha) } } - fn take_last_render(&self) -> RenderSnapshot<LayoutElementSnapshotRenderElements> { + fn take_last_render(&self) -> LayoutElementRenderSnapshot { self.last_render.take() } |
