aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/layout/mod.rs32
-rw-r--r--src/layout/tile.rs29
-rw-r--r--src/render_helpers/mod.rs37
-rw-r--r--src/window/mapped.rs111
4 files changed, 194 insertions, 15 deletions
diff --git a/src/layout/mod.rs b/src/layout/mod.rs
index 5ca48ad6..83715364 100644
--- a/src/layout/mod.rs
+++ b/src/layout/mod.rs
@@ -51,7 +51,7 @@ use self::workspace::{compute_working_area, Column, ColumnWidth, OutputId, Works
use crate::niri_render_elements;
use crate::render_helpers::renderer::NiriRenderer;
use crate::render_helpers::snapshot::RenderSnapshot;
-use crate::render_helpers::{BakedBuffer, RenderTarget};
+use crate::render_helpers::{BakedBuffer, RenderTarget, SplitElements};
use crate::utils::output_size;
use crate::window::ResolvedWindowRules;
@@ -108,7 +108,31 @@ pub trait LayoutElement {
scale: Scale<f64>,
alpha: f32,
target: RenderTarget,
- ) -> Vec<LayoutElementRenderElement<R>>;
+ ) -> SplitElements<LayoutElementRenderElement<R>>;
+
+ /// Renders the non-popup parts of the element.
+ fn render_normal<R: NiriRenderer>(
+ &self,
+ renderer: &mut R,
+ location: Point<i32, Logical>,
+ scale: Scale<f64>,
+ alpha: f32,
+ target: RenderTarget,
+ ) -> Vec<LayoutElementRenderElement<R>> {
+ self.render(renderer, location, scale, alpha, target).normal
+ }
+
+ /// Renders the popups of the element.
+ fn render_popups<R: NiriRenderer>(
+ &self,
+ renderer: &mut R,
+ location: Point<i32, Logical>,
+ scale: Scale<f64>,
+ alpha: f32,
+ target: RenderTarget,
+ ) -> Vec<LayoutElementRenderElement<R>> {
+ self.render(renderer, location, scale, alpha, target).popups
+ }
fn request_size(&mut self, size: Size<i32, Logical>, animate: bool);
fn request_fullscreen(&self, size: Size<i32, Logical>);
@@ -1984,8 +2008,8 @@ mod tests {
_scale: Scale<f64>,
_alpha: f32,
_target: RenderTarget,
- ) -> Vec<LayoutElementRenderElement<R>> {
- vec![]
+ ) -> SplitElements<LayoutElementRenderElement<R>> {
+ SplitElements::default()
}
fn request_size(&mut self, size: Size<i32, Logical>, _animate: bool) {
diff --git a/src/layout/tile.rs b/src/layout/tile.rs
index 0e06dd1b..b1790df5 100644
--- a/src/layout/tile.rs
+++ b/src/layout/tile.rs
@@ -536,18 +536,31 @@ impl<W: LayoutElement> Tile<W> {
let window_render_loc = location + window_loc;
let area = Rectangle::from_loc_and_size(window_render_loc, animated_window_size);
- let gles_renderer = renderer.as_gles_renderer();
-
// If we're resizing, try to render a shader, or a fallback.
let mut resize_shader = None;
+ let mut resize_popups = None;
let mut resize_fallback = None;
if let Some(resize) = &self.resize_animation {
- if let Some(shader) = ResizeRenderElement::shader(gles_renderer) {
+ resize_popups = Some(
+ self.window
+ .render_popups(renderer, window_render_loc, scale, alpha, target)
+ .into_iter()
+ .map(Into::into),
+ );
+
+ if let Some(shader) = ResizeRenderElement::shader(renderer) {
+ let gles_renderer = renderer.as_gles_renderer();
+
if let Some(texture_from) = resize.snapshot.texture(gles_renderer, scale, target) {
- let window_elements =
- self.window
- .render(gles_renderer, Point::from((0, 0)), scale, 1., target);
+ let window_elements = self.window.render_normal(
+ gles_renderer,
+ Point::from((0, 0)),
+ scale,
+ 1.,
+ target,
+ );
+
let current = render_to_encompassing_texture(
gles_renderer,
scale,
@@ -605,8 +618,10 @@ impl<W: LayoutElement> Tile<W> {
);
}
- let rv = resize_shader
+ let rv = resize_popups
.into_iter()
+ .flatten()
+ .chain(resize_shader)
.chain(resize_fallback)
.chain(window.into_iter().flatten());
diff --git a/src/render_helpers/mod.rs b/src/render_helpers/mod.rs
index 0be48bc6..16abe1ae 100644
--- a/src/render_helpers/mod.rs
+++ b/src/render_helpers/mod.rs
@@ -49,6 +49,13 @@ pub struct BakedBuffer<B> {
pub dst: Option<Size<i32, Logical>>,
}
+/// Render elements split into normal and popup.
+#[derive(Debug)]
+pub struct SplitElements<E> {
+ pub normal: Vec<E>,
+ pub popups: Vec<E>,
+}
+
pub trait ToRenderElement {
type RenderElement;
@@ -61,6 +68,36 @@ pub trait ToRenderElement {
) -> Self::RenderElement;
}
+impl<E> Default for SplitElements<E> {
+ fn default() -> Self {
+ Self {
+ normal: Vec::new(),
+ popups: Vec::new(),
+ }
+ }
+}
+
+impl<E> IntoIterator for SplitElements<E> {
+ type Item = E;
+ type IntoIter = std::iter::Chain<std::vec::IntoIter<E>, std::vec::IntoIter<E>>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.popups.into_iter().chain(self.normal)
+ }
+}
+
+impl<E> SplitElements<E> {
+ pub fn iter(&self) -> std::iter::Chain<std::slice::Iter<E>, std::slice::Iter<E>> {
+ self.popups.iter().chain(&self.normal)
+ }
+
+ pub fn into_vec(self) -> Vec<E> {
+ let Self { normal, mut popups } = self;
+ popups.extend(normal);
+ popups
+ }
+}
+
impl ToRenderElement for BakedBuffer<TextureBuffer<GlesTexture>> {
type RenderElement = PrimaryGpuTextureRenderElement;
diff --git a/src/window/mapped.rs b/src/window/mapped.rs
index 90598431..6ebb7a32 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::{AsRenderElements, Id, Kind};
+use smithay::backend::renderer::element::surface::render_elements_from_surface_tree;
+use smithay::backend::renderer::element::{Id, Kind};
use smithay::backend::renderer::gles::GlesRenderer;
use smithay::desktop::space::SpaceElement as _;
use smithay::desktop::{PopupManager, Window};
@@ -23,7 +24,7 @@ use crate::niri::WindowOffscreenId;
use crate::render_helpers::renderer::NiriRenderer;
use crate::render_helpers::snapshot::RenderSnapshot;
use crate::render_helpers::surface::render_snapshot_from_surface_tree;
-use crate::render_helpers::{BakedBuffer, RenderTarget};
+use crate::render_helpers::{BakedBuffer, RenderTarget, SplitElements};
#[derive(Debug)]
pub struct Mapped {
@@ -203,6 +204,63 @@ impl LayoutElement for Mapped {
scale: Scale<f64>,
alpha: f32,
target: RenderTarget,
+ ) -> SplitElements<LayoutElementRenderElement<R>> {
+ let mut rv = SplitElements::default();
+
+ let block_out = match self.rules.block_out_from {
+ None => false,
+ Some(BlockOutFrom::Screencast) => target == RenderTarget::Screencast,
+ Some(BlockOutFrom::ScreenCapture) => target != RenderTarget::Output,
+ };
+
+ 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),
+ scale,
+ alpha,
+ Kind::Unspecified,
+ );
+ rv.normal.push(elem.into());
+ } else {
+ let buf_pos = location - self.window.geometry().loc;
+
+ 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;
+
+ rv.popups.extend(render_elements_from_surface_tree(
+ renderer,
+ popup.wl_surface(),
+ (buf_pos + offset).to_physical_precise_round(scale),
+ scale,
+ alpha,
+ Kind::Unspecified,
+ ));
+ }
+
+ rv.normal = render_elements_from_surface_tree(
+ renderer,
+ surface,
+ buf_pos.to_physical_precise_round(scale),
+ scale,
+ alpha,
+ Kind::Unspecified,
+ );
+ }
+
+ rv
+ }
+
+ fn render_normal<R: NiriRenderer>(
+ &self,
+ renderer: &mut R,
+ location: Point<i32, Logical>,
+ scale: Scale<f64>,
+ alpha: f32,
+ target: RenderTarget,
) -> Vec<LayoutElementRenderElement<R>> {
let block_out = match self.rules.block_out_from {
None => false,
@@ -223,8 +281,53 @@ impl LayoutElement for Mapped {
vec![elem.into()]
} else {
let buf_pos = location - self.window.geometry().loc;
- let buf_pos = buf_pos.to_physical_precise_round(scale);
- self.window.render_elements(renderer, buf_pos, scale, alpha)
+ let surface = self.toplevel().wl_surface();
+ render_elements_from_surface_tree(
+ renderer,
+ surface,
+ buf_pos.to_physical_precise_round(scale),
+ scale,
+ alpha,
+ Kind::Unspecified,
+ )
+ }
+ }
+
+ fn render_popups<R: NiriRenderer>(
+ &self,
+ renderer: &mut R,
+ location: Point<i32, Logical>,
+ scale: Scale<f64>,
+ alpha: f32,
+ target: RenderTarget,
+ ) -> Vec<LayoutElementRenderElement<R>> {
+ let block_out = match self.rules.block_out_from {
+ None => false,
+ Some(BlockOutFrom::Screencast) => target == RenderTarget::Screencast,
+ Some(BlockOutFrom::ScreenCapture) => target != RenderTarget::Output,
+ };
+
+ if block_out {
+ vec![]
+ } else {
+ let mut rv = vec![];
+
+ let buf_pos = location - self.window.geometry().loc;
+ 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;
+
+ rv.extend(render_elements_from_surface_tree(
+ renderer,
+ popup.wl_surface(),
+ (buf_pos + offset).to_physical_precise_round(scale),
+ scale,
+ alpha,
+ Kind::Unspecified,
+ ));
+ }
+
+ rv
}
}