aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/handlers/compositor.rs58
-rw-r--r--src/handlers/xdg_shell.rs3
-rw-r--r--src/layout/closing_window.rs2
-rw-r--r--src/layout/mod.rs20
-rw-r--r--src/layout/tile.rs101
-rw-r--r--src/niri.rs5
-rw-r--r--src/render_helpers/mod.rs81
-rw-r--r--src/render_helpers/surface.rs108
-rw-r--r--src/window/mapped.rs111
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()
}