mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-24 02:01:18 +07:00
Refactor rendering to push-based instead of pull-based (#3113)
Our current rendering code constructs and returns complex `-> impl Iterator<Item = SomeRenderElement>` types that are collected into a vector at the top level Niri::render(). This causes some problems: - It's hard to write logic around returning iterators. Especially things like conditions, since the returned iterator must have a single type, you can't branch and return different iterators. This will be solved by gen fn but alas it's not here yet. - In many cases, the returned `-> impl Iterator` will borrow from &self leading to complex lifetimes. In certain cases, it is also desirable for it to borrow the &mut NiriRenderer, which causes a lot of issues because it's exclusive (&mut). - Sometimes those issues are too hard to deal with, leading to the escape hatch of allocating and returning a temporary Vec<SomeRenderElement>, like in Scrolling/FloatingSpace::render_elements(). These allocations are unfortunate because they are not really necessary. - It's impossible to use some downstream combinators with this `-> impl Iterator` approach, leading to functions like Smithay's render_elements_from_surface_tree() returning a Vec. This is extra unfortunate because it results in a temporary allocation per Wayland toplevel/popup. - It's hard to properly create profiling spans for the rendering functions since the spans are dropped when the (lazy) iterator is returned and not when all the code actually completes. - The code compiles down to complex state machines in generated iterator types with logic located in Iterator::next(), which makes it annoying to follow in debuggers and profiling tools. This refactor changes the code to push-based iteration: rendering functions receive a push() closure that they call to push their render elements. It solves all of the aforementioned problems: - The logic becomes simpler. Just use conditionals and loops as normal. - No borrowing and lifetimes since we're not returning anything. - All temporary Vecs are removed because the problems they worked around no longer exist. - The new push_elements_from_surface_tree() helper is the same as render_elements_from_surface_tree() but doesn't allocate a temporary Vec since it's not necessary; the push() closure can be passed down. - Profiling spans work normally since the function returns when it ran all of the logic. - The code compiles down to normal functions and calls as expected. Generally, the iterator approach gives these advantages: - You can wrap the returned items in the upstream logic. This is possible in exactly the same way with the push closure. - You can decide to cut the iterator short in the upstream logic. This is not possible with push-based iteration, but we don't actually use it anywhere. I chose the push closure type to be &mut dyn FnMut(SomeRenderElement). It's deliberately not a generic impl FnMut() to avoid duplicating the rendering logic when it's called from several different places. But it's still a normal closure that can capture the outside context. While my original idea for this refactor was to simplify the logic while getting rid of temporary Vecs, it also appears to have brought a consistent 2-3x speedup to the whole render list construction. On an old Eee PC laptop I even observed a 8x speedup. The refactor also results in smaller binary size, presumably due to removing many iterator combinators and state tracking.
This commit is contained in:
committed by
GitHub
parent
1a63089d67
commit
7f132ecf95
@@ -89,11 +89,8 @@ impl TestCase for GradientArea {
|
|||||||
1.,
|
1.,
|
||||||
1.,
|
1.,
|
||||||
);
|
);
|
||||||
rv.extend(
|
|
||||||
self.border
|
self.border
|
||||||
.render(renderer, g_loc)
|
.render(renderer, g_loc, &mut |elem| rv.push(Box::new(elem) as _));
|
||||||
.map(|elem| Box::new(elem) as _),
|
|
||||||
);
|
|
||||||
|
|
||||||
rv.extend(
|
rv.extend(
|
||||||
[BorderRenderElement::new(
|
[BorderRenderElement::new(
|
||||||
|
|||||||
@@ -268,12 +268,14 @@ impl TestCase for Layout {
|
|||||||
_size: Size<i32, Physical>,
|
_size: Size<i32, Physical>,
|
||||||
) -> Vec<Box<dyn RenderElement<GlesRenderer>>> {
|
) -> Vec<Box<dyn RenderElement<GlesRenderer>>> {
|
||||||
self.layout.update_render_elements(Some(&self.output));
|
self.layout.update_render_elements(Some(&self.output));
|
||||||
|
|
||||||
|
let mut rv = Vec::new();
|
||||||
self.layout
|
self.layout
|
||||||
.monitor_for_output(&self.output)
|
.monitor_for_output(&self.output)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.render_elements(renderer, RenderTarget::Output, true)
|
.render_workspaces(renderer, RenderTarget::Output, true, &mut |elem| {
|
||||||
.flat_map(|(_, _, iter)| iter)
|
rv.push(Box::new(elem) as _)
|
||||||
.map(|elem| Box::new(elem) as _)
|
});
|
||||||
.collect()
|
rv
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,9 +119,15 @@ impl TestCase for Tile {
|
|||||||
true,
|
true,
|
||||||
Rectangle::new(Point::from((-location.x, -location.y)), size.to_logical(1.)),
|
Rectangle::new(Point::from((-location.x, -location.y)), size.to_logical(1.)),
|
||||||
);
|
);
|
||||||
self.tile
|
|
||||||
.render(renderer, location, true, RenderTarget::Output)
|
let mut rv = Vec::new();
|
||||||
.map(|elem| Box::new(elem) as _)
|
self.tile.render(
|
||||||
.collect()
|
renderer,
|
||||||
|
location,
|
||||||
|
true,
|
||||||
|
RenderTarget::Output,
|
||||||
|
&mut |elem| rv.push(Box::new(elem) as _),
|
||||||
|
);
|
||||||
|
rv
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,16 +52,15 @@ impl TestCase for Window {
|
|||||||
.to_f64()
|
.to_f64()
|
||||||
.downscale(2.);
|
.downscale(2.);
|
||||||
|
|
||||||
self.window
|
let mut rv = Vec::new();
|
||||||
.render(
|
self.window.render_normal(
|
||||||
renderer,
|
renderer,
|
||||||
location,
|
location,
|
||||||
Scale::from(1.),
|
Scale::from(1.),
|
||||||
1.,
|
1.,
|
||||||
RenderTarget::Output,
|
RenderTarget::Output,
|
||||||
)
|
&mut |elem| rv.push(Box::new(elem) as _),
|
||||||
.into_iter()
|
);
|
||||||
.map(|elem| Box::new(elem) as _)
|
rv
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use niri::layout::{
|
|||||||
use niri::render_helpers::offscreen::OffscreenData;
|
use niri::render_helpers::offscreen::OffscreenData;
|
||||||
use niri::render_helpers::renderer::NiriRenderer;
|
use niri::render_helpers::renderer::NiriRenderer;
|
||||||
use niri::render_helpers::solid_color::{SolidColorBuffer, SolidColorRenderElement};
|
use niri::render_helpers::solid_color::{SolidColorBuffer, SolidColorRenderElement};
|
||||||
use niri::render_helpers::{RenderTarget, SplitElements};
|
use niri::render_helpers::RenderTarget;
|
||||||
use niri::utils::transaction::Transaction;
|
use niri::utils::transaction::Transaction;
|
||||||
use niri::window::ResolvedWindowRules;
|
use niri::window::ResolvedWindowRules;
|
||||||
use smithay::backend::renderer::element::Kind;
|
use smithay::backend::renderer::element::Kind;
|
||||||
@@ -149,36 +149,30 @@ impl LayoutElement for TestWindow {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render<R: NiriRenderer>(
|
fn render_normal<R: NiriRenderer>(
|
||||||
&self,
|
&self,
|
||||||
_renderer: &mut R,
|
_renderer: &mut R,
|
||||||
location: Point<f64, Logical>,
|
location: Point<f64, Logical>,
|
||||||
_scale: Scale<f64>,
|
_scale: Scale<f64>,
|
||||||
alpha: f32,
|
alpha: f32,
|
||||||
_target: RenderTarget,
|
_target: RenderTarget,
|
||||||
) -> SplitElements<LayoutElementRenderElement<R>> {
|
push: &mut dyn FnMut(LayoutElementRenderElement<R>),
|
||||||
|
) {
|
||||||
let inner = self.inner.borrow();
|
let inner = self.inner.borrow();
|
||||||
|
|
||||||
SplitElements {
|
push(
|
||||||
normal: vec![
|
SolidColorRenderElement::from_buffer(&inner.buffer, location, alpha, Kind::Unspecified)
|
||||||
SolidColorRenderElement::from_buffer(
|
|
||||||
&inner.buffer,
|
|
||||||
location,
|
|
||||||
alpha,
|
|
||||||
Kind::Unspecified,
|
|
||||||
)
|
|
||||||
.into(),
|
.into(),
|
||||||
|
);
|
||||||
|
push(
|
||||||
SolidColorRenderElement::from_buffer(
|
SolidColorRenderElement::from_buffer(
|
||||||
&inner.csd_shadow_buffer,
|
&inner.csd_shadow_buffer,
|
||||||
location
|
location - Point::from((inner.csd_shadow_width, inner.csd_shadow_width)).to_f64(),
|
||||||
- Point::from((inner.csd_shadow_width, inner.csd_shadow_width)).to_f64(),
|
|
||||||
alpha,
|
alpha,
|
||||||
Kind::Unspecified,
|
Kind::Unspecified,
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
],
|
);
|
||||||
popups: vec![],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn request_size(
|
fn request_size(
|
||||||
|
|||||||
+44
-26
@@ -1,8 +1,6 @@
|
|||||||
use niri_config::utils::MergeWith as _;
|
use niri_config::utils::MergeWith as _;
|
||||||
use niri_config::{Config, LayerRule};
|
use niri_config::{Config, LayerRule};
|
||||||
use smithay::backend::renderer::element::surface::{
|
use smithay::backend::renderer::element::surface::WaylandSurfaceRenderElement;
|
||||||
render_elements_from_surface_tree, WaylandSurfaceRenderElement,
|
|
||||||
};
|
|
||||||
use smithay::backend::renderer::element::Kind;
|
use smithay::backend::renderer::element::Kind;
|
||||||
use smithay::desktop::{LayerSurface, PopupManager};
|
use smithay::desktop::{LayerSurface, PopupManager};
|
||||||
use smithay::utils::{Logical, Point, Scale, Size};
|
use smithay::utils::{Logical, Point, Scale, Size};
|
||||||
@@ -15,7 +13,8 @@ use crate::niri_render_elements;
|
|||||||
use crate::render_helpers::renderer::NiriRenderer;
|
use crate::render_helpers::renderer::NiriRenderer;
|
||||||
use crate::render_helpers::shadow::ShadowRenderElement;
|
use crate::render_helpers::shadow::ShadowRenderElement;
|
||||||
use crate::render_helpers::solid_color::{SolidColorBuffer, SolidColorRenderElement};
|
use crate::render_helpers::solid_color::{SolidColorBuffer, SolidColorRenderElement};
|
||||||
use crate::render_helpers::{RenderTarget, SplitElements};
|
use crate::render_helpers::surface::push_elements_from_surface_tree;
|
||||||
|
use crate::render_helpers::RenderTarget;
|
||||||
use crate::utils::{baba_is_float_offset, round_logical_in_physical};
|
use crate::utils::{baba_is_float_offset, round_logical_in_physical};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -156,14 +155,13 @@ impl MappedLayer {
|
|||||||
Point::from((0., y))
|
Point::from((0., y))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render<R: NiriRenderer>(
|
pub fn render_normal<R: NiriRenderer>(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut R,
|
renderer: &mut R,
|
||||||
location: Point<f64, Logical>,
|
location: Point<f64, Logical>,
|
||||||
target: RenderTarget,
|
target: RenderTarget,
|
||||||
) -> SplitElements<LayerSurfaceRenderElement<R>> {
|
push: &mut dyn FnMut(LayerSurfaceRenderElement<R>),
|
||||||
let mut rv = SplitElements::default();
|
) {
|
||||||
|
|
||||||
let scale = Scale::from(self.scale);
|
let scale = Scale::from(self.scale);
|
||||||
let alpha = self.rules.opacity.unwrap_or(1.).clamp(0., 1.);
|
let alpha = self.rules.opacity.unwrap_or(1.).clamp(0., 1.);
|
||||||
let location = location + self.bob_offset();
|
let location = location + self.bob_offset();
|
||||||
@@ -179,40 +177,60 @@ impl MappedLayer {
|
|||||||
alpha,
|
alpha,
|
||||||
Kind::Unspecified,
|
Kind::Unspecified,
|
||||||
);
|
);
|
||||||
rv.normal.push(elem.into());
|
push(elem.into());
|
||||||
} else {
|
} else {
|
||||||
// Layer surfaces don't have extra geometry like windows.
|
// Layer surfaces don't have extra geometry like windows.
|
||||||
let buf_pos = location;
|
let buf_pos = location;
|
||||||
|
|
||||||
|
let surface = self.surface.wl_surface();
|
||||||
|
push_elements_from_surface_tree(
|
||||||
|
renderer,
|
||||||
|
surface,
|
||||||
|
buf_pos.to_physical_precise_round(scale),
|
||||||
|
scale,
|
||||||
|
alpha,
|
||||||
|
Kind::ScanoutCandidate,
|
||||||
|
&mut |elem| push(elem.into()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let location = location.to_physical_precise_round(scale).to_logical(scale);
|
||||||
|
self.shadow
|
||||||
|
.render(renderer, location, &mut |elem| push(elem.into()));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render_popups<R: NiriRenderer>(
|
||||||
|
&self,
|
||||||
|
renderer: &mut R,
|
||||||
|
location: Point<f64, Logical>,
|
||||||
|
target: RenderTarget,
|
||||||
|
push: &mut dyn FnMut(LayerSurfaceRenderElement<R>),
|
||||||
|
) {
|
||||||
|
let scale = Scale::from(self.scale);
|
||||||
|
let alpha = self.rules.opacity.unwrap_or(1.).clamp(0., 1.);
|
||||||
|
let location = location + self.bob_offset();
|
||||||
|
|
||||||
|
if target.should_block_out(self.rules.block_out_from) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Layer surfaces don't have extra geometry like windows.
|
||||||
|
let buf_pos = location;
|
||||||
|
|
||||||
let surface = self.surface.wl_surface();
|
let surface = self.surface.wl_surface();
|
||||||
for (popup, popup_offset) in PopupManager::popups_for_surface(surface) {
|
for (popup, popup_offset) in PopupManager::popups_for_surface(surface) {
|
||||||
// Layer surfaces don't have extra geometry like windows.
|
// Layer surfaces don't have extra geometry like windows.
|
||||||
let offset = popup_offset - popup.geometry().loc;
|
let offset = popup_offset - popup.geometry().loc;
|
||||||
|
|
||||||
rv.popups.extend(render_elements_from_surface_tree(
|
push_elements_from_surface_tree(
|
||||||
renderer,
|
renderer,
|
||||||
popup.wl_surface(),
|
popup.wl_surface(),
|
||||||
(buf_pos + offset.to_f64()).to_physical_precise_round(scale),
|
(buf_pos + offset.to_f64()).to_physical_precise_round(scale),
|
||||||
scale,
|
scale,
|
||||||
alpha,
|
alpha,
|
||||||
Kind::ScanoutCandidate,
|
Kind::ScanoutCandidate,
|
||||||
));
|
&mut |elem| push(elem.into()),
|
||||||
}
|
|
||||||
|
|
||||||
rv.normal = render_elements_from_surface_tree(
|
|
||||||
renderer,
|
|
||||||
surface,
|
|
||||||
buf_pos.to_physical_precise_round(scale),
|
|
||||||
scale,
|
|
||||||
alpha,
|
|
||||||
Kind::ScanoutCandidate,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let location = location.to_physical_precise_round(scale).to_logical(scale);
|
|
||||||
rv.normal
|
|
||||||
.extend(self.shadow.render(renderer, location).map(Into::into));
|
|
||||||
|
|
||||||
rv
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-11
@@ -1053,15 +1053,14 @@ impl<W: LayoutElement> FloatingSpace<W> {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_elements<R: NiriRenderer>(
|
pub fn render<R: NiriRenderer>(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut R,
|
renderer: &mut R,
|
||||||
view_rect: Rectangle<f64, Logical>,
|
view_rect: Rectangle<f64, Logical>,
|
||||||
target: RenderTarget,
|
target: RenderTarget,
|
||||||
focus_ring: bool,
|
focus_ring: bool,
|
||||||
) -> Vec<FloatingSpaceRenderElement<R>> {
|
push: &mut dyn FnMut(FloatingSpaceRenderElement<R>),
|
||||||
let mut rv = Vec::new();
|
) {
|
||||||
|
|
||||||
let scale = Scale::from(self.scale);
|
let scale = Scale::from(self.scale);
|
||||||
|
|
||||||
// Draw the closing windows on top of the other windows.
|
// Draw the closing windows on top of the other windows.
|
||||||
@@ -1069,7 +1068,7 @@ impl<W: LayoutElement> FloatingSpace<W> {
|
|||||||
// FIXME: I guess this should rather preserve the stacking order when the window is closed.
|
// FIXME: I guess this should rather preserve the stacking order when the window is closed.
|
||||||
for closing in self.closing_windows.iter().rev() {
|
for closing in self.closing_windows.iter().rev() {
|
||||||
let elem = closing.render(renderer.as_gles_renderer(), view_rect, scale, target);
|
let elem = closing.render(renderer.as_gles_renderer(), view_rect, scale, target);
|
||||||
rv.push(elem.into());
|
push(elem.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let active = self.active_window_id.clone();
|
let active = self.active_window_id.clone();
|
||||||
@@ -1077,13 +1076,10 @@ impl<W: LayoutElement> FloatingSpace<W> {
|
|||||||
// For the active tile, draw the focus ring.
|
// For the active tile, draw the focus ring.
|
||||||
let focus_ring = focus_ring && Some(tile.window().id()) == active.as_ref();
|
let focus_ring = focus_ring && Some(tile.window().id()) == active.as_ref();
|
||||||
|
|
||||||
rv.extend(
|
tile.render(renderer, tile_pos, focus_ring, target, &mut |elem| {
|
||||||
tile.render(renderer, tile_pos, focus_ring, target)
|
push(elem.into())
|
||||||
.map(Into::into),
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rv
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn interactive_resize_begin(&mut self, window: W::Id, edges: ResizeEdge) -> bool {
|
pub fn interactive_resize_begin(&mut self, window: W::Id, edges: ResizeEdge) -> bool {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use std::iter::zip;
|
use std::iter::zip;
|
||||||
|
|
||||||
use arrayvec::ArrayVec;
|
|
||||||
use niri_config::{CornerRadius, Gradient, GradientRelativeTo};
|
use niri_config::{CornerRadius, Gradient, GradientRelativeTo};
|
||||||
use smithay::backend::renderer::element::{Element as _, Kind};
|
use smithay::backend::renderer::element::{Element as _, Kind};
|
||||||
use smithay::utils::{Logical, Point, Rectangle, Size};
|
use smithay::utils::{Logical, Point, Rectangle, Size};
|
||||||
@@ -220,18 +219,17 @@ impl FocusRing {
|
|||||||
&self,
|
&self,
|
||||||
renderer: &mut impl NiriRenderer,
|
renderer: &mut impl NiriRenderer,
|
||||||
location: Point<f64, Logical>,
|
location: Point<f64, Logical>,
|
||||||
) -> impl Iterator<Item = FocusRingRenderElement> {
|
push: &mut dyn FnMut(FocusRingRenderElement),
|
||||||
let mut rv = ArrayVec::<_, 8>::new();
|
) {
|
||||||
|
|
||||||
if self.config.off {
|
if self.config.off {
|
||||||
return rv.into_iter();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let border_width = -self.locations[0].y;
|
let border_width = -self.locations[0].y;
|
||||||
|
|
||||||
// If drawing as a border with width = 0, then there's nothing to draw.
|
// If drawing as a border with width = 0, then there's nothing to draw.
|
||||||
if self.is_border && border_width == 0. {
|
if self.is_border && border_width == 0. {
|
||||||
return rv.into_iter();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let has_border_shader = BorderRenderElement::has_shader(renderer);
|
let has_border_shader = BorderRenderElement::has_shader(renderer);
|
||||||
@@ -244,7 +242,7 @@ impl FocusRing {
|
|||||||
SolidColorRenderElement::from_buffer(buffer, location, alpha, Kind::Unspecified)
|
SolidColorRenderElement::from_buffer(buffer, location, alpha, Kind::Unspecified)
|
||||||
.into()
|
.into()
|
||||||
};
|
};
|
||||||
rv.push(elem);
|
push(elem);
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.is_border {
|
if self.is_border {
|
||||||
@@ -258,8 +256,6 @@ impl FocusRing {
|
|||||||
location + self.locations[0],
|
location + self.locations[0],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
rv.into_iter()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn width(&self) -> f64 {
|
pub fn width(&self) -> f64 {
|
||||||
|
|||||||
@@ -59,7 +59,8 @@ impl InsertHintElement {
|
|||||||
&self,
|
&self,
|
||||||
renderer: &mut impl NiriRenderer,
|
renderer: &mut impl NiriRenderer,
|
||||||
location: Point<f64, Logical>,
|
location: Point<f64, Logical>,
|
||||||
) -> impl Iterator<Item = FocusRingRenderElement> {
|
push: &mut dyn FnMut(FocusRingRenderElement),
|
||||||
self.inner.render(renderer, location)
|
) {
|
||||||
|
self.inner.render(renderer, location, push)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+27
-22
@@ -64,7 +64,7 @@ use crate::render_helpers::renderer::NiriRenderer;
|
|||||||
use crate::render_helpers::snapshot::RenderSnapshot;
|
use crate::render_helpers::snapshot::RenderSnapshot;
|
||||||
use crate::render_helpers::solid_color::{SolidColorBuffer, SolidColorRenderElement};
|
use crate::render_helpers::solid_color::{SolidColorBuffer, SolidColorRenderElement};
|
||||||
use crate::render_helpers::texture::TextureBuffer;
|
use crate::render_helpers::texture::TextureBuffer;
|
||||||
use crate::render_helpers::{BakedBuffer, RenderTarget, SplitElements};
|
use crate::render_helpers::{BakedBuffer, RenderTarget};
|
||||||
use crate::rubber_band::RubberBand;
|
use crate::rubber_band::RubberBand;
|
||||||
use crate::utils::transaction::{Transaction, TransactionBlocker};
|
use crate::utils::transaction::{Transaction, TransactionBlocker};
|
||||||
use crate::utils::{
|
use crate::utils::{
|
||||||
@@ -159,7 +159,11 @@ pub trait LayoutElement {
|
|||||||
scale: Scale<f64>,
|
scale: Scale<f64>,
|
||||||
alpha: f32,
|
alpha: f32,
|
||||||
target: RenderTarget,
|
target: RenderTarget,
|
||||||
) -> SplitElements<LayoutElementRenderElement<R>>;
|
push: &mut dyn FnMut(LayoutElementRenderElement<R>),
|
||||||
|
) {
|
||||||
|
self.render_popups(renderer, location, scale, alpha, target, push);
|
||||||
|
self.render_normal(renderer, location, scale, alpha, target, push);
|
||||||
|
}
|
||||||
|
|
||||||
/// Renders the non-popup parts of the element.
|
/// Renders the non-popup parts of the element.
|
||||||
fn render_normal<R: NiriRenderer>(
|
fn render_normal<R: NiriRenderer>(
|
||||||
@@ -169,8 +173,9 @@ pub trait LayoutElement {
|
|||||||
scale: Scale<f64>,
|
scale: Scale<f64>,
|
||||||
alpha: f32,
|
alpha: f32,
|
||||||
target: RenderTarget,
|
target: RenderTarget,
|
||||||
) -> Vec<LayoutElementRenderElement<R>> {
|
push: &mut dyn FnMut(LayoutElementRenderElement<R>),
|
||||||
self.render(renderer, location, scale, alpha, target).normal
|
) {
|
||||||
|
let _ = (renderer, location, scale, alpha, target, push);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Renders the popups of the element.
|
/// Renders the popups of the element.
|
||||||
@@ -181,8 +186,9 @@ pub trait LayoutElement {
|
|||||||
scale: Scale<f64>,
|
scale: Scale<f64>,
|
||||||
alpha: f32,
|
alpha: f32,
|
||||||
target: RenderTarget,
|
target: RenderTarget,
|
||||||
) -> Vec<LayoutElementRenderElement<R>> {
|
push: &mut dyn FnMut(LayoutElementRenderElement<R>),
|
||||||
self.render(renderer, location, scale, alpha, target).popups
|
) {
|
||||||
|
let _ = (renderer, location, scale, alpha, target, push);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Requests the element to change its size.
|
/// Requests the element to change its size.
|
||||||
@@ -4713,38 +4719,37 @@ impl<W: LayoutElement> Layout<W> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_interactive_move_for_output<'a, R: NiriRenderer + 'a>(
|
pub fn render_interactive_move_for_output<R: NiriRenderer>(
|
||||||
&'a self,
|
&self,
|
||||||
renderer: &mut R,
|
renderer: &mut R,
|
||||||
output: &Output,
|
output: &Output,
|
||||||
target: RenderTarget,
|
target: RenderTarget,
|
||||||
) -> impl Iterator<Item = RescaleRenderElement<TileRenderElement<R>>> + 'a {
|
push: &mut dyn FnMut(RescaleRenderElement<TileRenderElement<R>>),
|
||||||
|
) {
|
||||||
if self.update_render_elements_time != self.clock.now() {
|
if self.update_render_elements_time != self.clock.now() {
|
||||||
error!("clock moved between updating render elements and rendering");
|
error!("clock moved between updating render elements and rendering");
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut rv = None;
|
let Some(InteractiveMoveState::Moving(move_)) = &self.interactive_move else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if &move_.output != output {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(InteractiveMoveState::Moving(move_)) = &self.interactive_move {
|
|
||||||
if &move_.output == output {
|
|
||||||
let scale = Scale::from(move_.output.current_scale().fractional_scale());
|
let scale = Scale::from(move_.output.current_scale().fractional_scale());
|
||||||
let zoom = self.overview_zoom();
|
let zoom = self.overview_zoom();
|
||||||
let location = move_.tile_render_location(zoom);
|
let location = move_.tile_render_location(zoom);
|
||||||
let iter = move_
|
move_
|
||||||
.tile
|
.tile
|
||||||
.render(renderer, location, true, target)
|
.render(renderer, location, true, target, &mut |elem| {
|
||||||
.map(move |elem| {
|
push(RescaleRenderElement::from_element(
|
||||||
RescaleRenderElement::from_element(
|
|
||||||
elem,
|
elem,
|
||||||
location.to_physical_precise_round(scale),
|
location.to_physical_precise_round(scale),
|
||||||
zoom,
|
zoom,
|
||||||
)
|
));
|
||||||
});
|
});
|
||||||
rv = Some(iter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rv.into_iter().flatten()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn refresh(&mut self, is_active: bool) {
|
pub fn refresh(&mut self, is_active: bool) {
|
||||||
|
|||||||
+73
-95
@@ -1638,40 +1638,36 @@ impl<W: LayoutElement> Monitor<W> {
|
|||||||
pub fn render_insert_hint_between_workspaces<R: NiriRenderer>(
|
pub fn render_insert_hint_between_workspaces<R: NiriRenderer>(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut R,
|
renderer: &mut R,
|
||||||
) -> impl Iterator<Item = MonitorRenderElement<R>> {
|
push: &mut dyn FnMut(MonitorRenderElement<R>),
|
||||||
let mut rv = None;
|
) {
|
||||||
|
if self.options.layout.insert_hint.off {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let Some(render_loc) = self.insert_hint_render_loc else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let InsertWorkspace::NewAt(_) = render_loc.workspace else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
if !self.options.layout.insert_hint.off {
|
self.insert_hint_element
|
||||||
if let Some(render_loc) = self.insert_hint_render_loc {
|
.render(renderer, render_loc.location, &mut |elem| {
|
||||||
if let InsertWorkspace::NewAt(_) = render_loc.workspace {
|
let elem = MonitorInnerRenderElement::UncroppedInsertHint(elem);
|
||||||
let iter = self
|
|
||||||
.insert_hint_element
|
|
||||||
.render(renderer, render_loc.location)
|
|
||||||
.map(MonitorInnerRenderElement::UncroppedInsertHint);
|
|
||||||
rv = Some(iter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rv.into_iter().flatten().map(|elem| {
|
|
||||||
let elem = RescaleRenderElement::from_element(elem, Point::default(), 1.);
|
let elem = RescaleRenderElement::from_element(elem, Point::default(), 1.);
|
||||||
RelocateRenderElement::from_element(elem, Point::default(), Relocate::Relative)
|
let elem =
|
||||||
})
|
RelocateRenderElement::from_element(elem, Point::default(), Relocate::Relative);
|
||||||
|
push(elem);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_elements<'a, R: NiriRenderer>(
|
pub fn render_workspaces<R: NiriRenderer>(
|
||||||
&'a self,
|
&self,
|
||||||
renderer: &'a mut R,
|
renderer: &mut R,
|
||||||
target: RenderTarget,
|
target: RenderTarget,
|
||||||
focus_ring: bool,
|
focus_ring: bool,
|
||||||
) -> impl Iterator<
|
push: &mut dyn FnMut(MonitorRenderElement<R>),
|
||||||
Item = (
|
) {
|
||||||
Rectangle<f64, Logical>,
|
let _span = tracy_client::span!("Monitor::render_workspaces");
|
||||||
MonitorRenderElement<R>,
|
|
||||||
impl Iterator<Item = MonitorRenderElement<R>> + 'a,
|
|
||||||
),
|
|
||||||
> {
|
|
||||||
let _span = tracy_client::span!("Monitor::render_elements");
|
|
||||||
|
|
||||||
let scale = self.scale.fractional_scale();
|
let scale = self.scale.fractional_scale();
|
||||||
// Ceil the height in physical pixels.
|
// Ceil the height in physical pixels.
|
||||||
@@ -1701,51 +1697,15 @@ impl<W: LayoutElement> Monitor<W> {
|
|||||||
|
|
||||||
let zoom = self.overview_zoom();
|
let zoom = self.overview_zoom();
|
||||||
|
|
||||||
// Draw the insert hint.
|
let insert_hint_render_loc = self
|
||||||
let mut insert_hint = None;
|
.insert_hint_render_loc
|
||||||
if !self.options.layout.insert_hint.off {
|
.filter(|_| !self.options.layout.insert_hint.off);
|
||||||
if let Some(render_loc) = self.insert_hint_render_loc {
|
|
||||||
if let InsertWorkspace::Existing(workspace_id) = render_loc.workspace {
|
|
||||||
insert_hint = Some((
|
|
||||||
workspace_id,
|
|
||||||
self.insert_hint_element
|
|
||||||
.render(renderer, render_loc.location),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.workspaces_with_render_geo().map(move |(ws, geo)| {
|
let scale_relocate = move |geo: Rectangle<f64, Logical>, elem| {
|
||||||
let map_ws_contents = move |elem: WorkspaceRenderElement<R>| {
|
|
||||||
let elem = CropRenderElement::from_element(elem, scale, crop_bounds)?;
|
|
||||||
let elem = MonitorInnerRenderElement::Workspace(elem);
|
|
||||||
Some(elem)
|
|
||||||
};
|
|
||||||
|
|
||||||
let (floating, scrolling) = ws.render_elements(renderer, target, focus_ring);
|
|
||||||
let floating = floating.filter_map(map_ws_contents);
|
|
||||||
let scrolling = scrolling.filter_map(map_ws_contents);
|
|
||||||
|
|
||||||
let hint = if matches!(insert_hint, Some((hint_ws_id, _)) if hint_ws_id == ws.id()) {
|
|
||||||
let iter = insert_hint.take().unwrap().1;
|
|
||||||
let iter = iter.filter_map(move |elem| {
|
|
||||||
let elem = CropRenderElement::from_element(elem, scale, crop_bounds)?;
|
|
||||||
let elem = MonitorInnerRenderElement::InsertHint(elem);
|
|
||||||
Some(elem)
|
|
||||||
});
|
|
||||||
Some(iter)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
let hint = hint.into_iter().flatten();
|
|
||||||
|
|
||||||
let iter = floating.chain(hint).chain(scrolling);
|
|
||||||
|
|
||||||
let scale_relocate = move |elem| {
|
|
||||||
let elem = RescaleRenderElement::from_element(elem, Point::from((0, 0)), zoom);
|
let elem = RescaleRenderElement::from_element(elem, Point::from((0, 0)), zoom);
|
||||||
RelocateRenderElement::from_element(
|
RelocateRenderElement::from_element(
|
||||||
elem,
|
elem,
|
||||||
// The offset we get from workspaces_with_render_positions() is already
|
// The offset we get from workspaces_with_render_geo() is already
|
||||||
// rounded to physical pixels, but it's in the logical coordinate
|
// rounded to physical pixels, but it's in the logical coordinate
|
||||||
// space, so we need to convert it to physical.
|
// space, so we need to convert it to physical.
|
||||||
geo.loc.to_physical_precise_round(scale),
|
geo.loc.to_physical_precise_round(scale),
|
||||||
@@ -1753,43 +1713,61 @@ impl<W: LayoutElement> Monitor<W> {
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let iter = iter.map(scale_relocate);
|
for (ws, geo) in self.workspaces_with_render_geo() {
|
||||||
|
// Macro instead of closure because ws and insert hint have different elem types.
|
||||||
let background = ws.render_background();
|
macro_rules! push {
|
||||||
let background = scale_relocate(MonitorInnerRenderElement::SolidColor(background));
|
() => {{
|
||||||
|
&mut |elem| {
|
||||||
(geo, background, iter)
|
let elem = CropRenderElement::from_element(elem, scale, crop_bounds);
|
||||||
})
|
if let Some(elem) = elem {
|
||||||
|
let elem = MonitorInnerRenderElement::from(elem);
|
||||||
|
push(scale_relocate(geo, elem));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_workspace_shadows<'a, R: NiriRenderer>(
|
ws.render_floating(renderer, target, focus_ring, push!());
|
||||||
&'a self,
|
|
||||||
renderer: &'a mut R,
|
if let Some(loc) = insert_hint_render_loc {
|
||||||
) -> impl Iterator<Item = MonitorRenderElement<R>> + 'a {
|
if loc.workspace == InsertWorkspace::Existing(ws.id()) {
|
||||||
|
self.insert_hint_element
|
||||||
|
.render(renderer, loc.location, push!());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ws.render_scrolling(renderer, target, focus_ring, push!());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render_workspace_shadows<R: NiriRenderer>(
|
||||||
|
&self,
|
||||||
|
renderer: &mut R,
|
||||||
|
push: &mut dyn FnMut(MonitorRenderElement<R>),
|
||||||
|
) {
|
||||||
|
let Some(progress) = self.overview_progress.as_ref().map(|p| p.clamped_value()) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let alpha = progress.clamp(0., 1.) as f32;
|
||||||
|
|
||||||
let _span = tracy_client::span!("Monitor::render_workspace_shadows");
|
let _span = tracy_client::span!("Monitor::render_workspace_shadows");
|
||||||
|
|
||||||
let scale = self.scale.fractional_scale();
|
let scale = self.scale.fractional_scale();
|
||||||
let zoom = self.overview_zoom();
|
let zoom = self.overview_zoom();
|
||||||
let overview_clamped_progress = self.overview_progress.as_ref().map(|p| p.clamped_value());
|
|
||||||
|
|
||||||
self.workspaces_with_render_geo()
|
for (ws, geo) in self.workspaces_with_render_geo() {
|
||||||
.flat_map(move |(ws, geo)| {
|
ws.render_shadow(renderer, &mut |elem| {
|
||||||
let shadow = overview_clamped_progress.map(|value| {
|
let elem = elem.with_alpha(alpha);
|
||||||
ws.render_shadow(renderer)
|
let elem = MonitorInnerRenderElement::Shadow(elem);
|
||||||
.map(move |elem| elem.with_alpha(value.clamp(0., 1.) as f32))
|
|
||||||
.map(MonitorInnerRenderElement::Shadow)
|
|
||||||
});
|
|
||||||
let iter = shadow.into_iter().flatten();
|
|
||||||
|
|
||||||
iter.map(move |elem| {
|
|
||||||
let elem = RescaleRenderElement::from_element(elem, Point::from((0, 0)), zoom);
|
let elem = RescaleRenderElement::from_element(elem, Point::from((0, 0)), zoom);
|
||||||
RelocateRenderElement::from_element(
|
let elem = RelocateRenderElement::from_element(
|
||||||
elem,
|
elem,
|
||||||
geo.loc.to_physical_precise_round(scale),
|
geo.loc.to_physical_precise_round(scale),
|
||||||
Relocate::Relative,
|
Relocate::Relative,
|
||||||
)
|
);
|
||||||
})
|
push(elem);
|
||||||
})
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn workspace_switch_gesture_begin(&mut self, is_touchpad: bool) {
|
pub fn workspace_switch_gesture_begin(&mut self, is_touchpad: bool) {
|
||||||
|
|||||||
+10
-13
@@ -2897,25 +2897,24 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
|||||||
.is_fullscreen()
|
.is_fullscreen()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_elements<R: NiriRenderer>(
|
pub fn render<R: NiriRenderer>(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut R,
|
renderer: &mut R,
|
||||||
target: RenderTarget,
|
target: RenderTarget,
|
||||||
focus_ring: bool,
|
focus_ring: bool,
|
||||||
) -> Vec<ScrollingSpaceRenderElement<R>> {
|
push: &mut dyn FnMut(ScrollingSpaceRenderElement<R>),
|
||||||
let mut rv = vec![];
|
) {
|
||||||
|
|
||||||
let scale = Scale::from(self.scale);
|
let scale = Scale::from(self.scale);
|
||||||
|
|
||||||
// Draw the closing windows on top of the other windows.
|
// Draw the closing windows on top of the other windows.
|
||||||
let view_rect = Rectangle::new(Point::from((self.view_pos(), 0.)), self.view_size);
|
let view_rect = Rectangle::new(Point::from((self.view_pos(), 0.)), self.view_size);
|
||||||
for closing in self.closing_windows.iter().rev() {
|
for closing in self.closing_windows.iter().rev() {
|
||||||
let elem = closing.render(renderer.as_gles_renderer(), view_rect, scale, target);
|
let elem = closing.render(renderer.as_gles_renderer(), view_rect, scale, target);
|
||||||
rv.push(elem.into());
|
push(elem.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.columns.is_empty() {
|
if self.columns.is_empty() {
|
||||||
return rv;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
@@ -2930,7 +2929,8 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
|||||||
{
|
{
|
||||||
let pos = view_off + col_off + col_render_off;
|
let pos = view_off + col_off + col_render_off;
|
||||||
let pos = pos.to_physical_precise_round(scale).to_logical(scale);
|
let pos = pos.to_physical_precise_round(scale).to_logical(scale);
|
||||||
rv.extend(col.tab_indicator.render(renderer, pos).map(Into::into));
|
col.tab_indicator
|
||||||
|
.render(renderer, pos, &mut |elem| push(elem.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (tile, tile_off, visible) in col.tiles_in_render_order() {
|
for (tile, tile_off, visible) in col.tiles_in_render_order() {
|
||||||
@@ -2955,14 +2955,11 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
rv.extend(
|
tile.render(renderer, tile_pos, focus_ring, target, &mut |elem| {
|
||||||
tile.render(renderer, tile_pos, focus_ring, target)
|
push(elem.into())
|
||||||
.map(Into::into),
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rv
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn window_under(&self, pos: Point<f64, Logical>) -> Option<(&W, HitType)> {
|
pub fn window_under(&self, pos: Point<f64, Logical>) -> Option<(&W, HitType)> {
|
||||||
|
|||||||
@@ -166,19 +166,19 @@ impl Shadow {
|
|||||||
&self,
|
&self,
|
||||||
renderer: &mut impl NiriRenderer,
|
renderer: &mut impl NiriRenderer,
|
||||||
location: Point<f64, Logical>,
|
location: Point<f64, Logical>,
|
||||||
) -> impl Iterator<Item = ShadowRenderElement> + '_ {
|
push: &mut dyn FnMut(ShadowRenderElement),
|
||||||
|
) {
|
||||||
if !self.config.on {
|
if !self.config.on {
|
||||||
return None.into_iter().flatten();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let has_shadow_shader = ShadowRenderElement::has_shader(renderer);
|
let has_shadow_shader = ShadowRenderElement::has_shader(renderer);
|
||||||
if !has_shadow_shader {
|
if !has_shadow_shader {
|
||||||
return None.into_iter().flatten();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let rv = zip(&self.shaders, &self.shader_rects)
|
for (shader, rect) in zip(&self.shaders, &self.shader_rects) {
|
||||||
.map(move |(shader, rect)| shader.clone().with_location(location + rect.loc));
|
push(shader.clone().with_location(location + rect.loc));
|
||||||
|
}
|
||||||
Some(rv).into_iter().flatten()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -294,17 +294,17 @@ impl TabIndicator {
|
|||||||
&self,
|
&self,
|
||||||
renderer: &mut impl NiriRenderer,
|
renderer: &mut impl NiriRenderer,
|
||||||
pos: Point<f64, Logical>,
|
pos: Point<f64, Logical>,
|
||||||
) -> impl Iterator<Item = TabIndicatorRenderElement> + '_ {
|
push: &mut dyn FnMut(TabIndicatorRenderElement),
|
||||||
|
) {
|
||||||
let has_border_shader = BorderRenderElement::has_shader(renderer);
|
let has_border_shader = BorderRenderElement::has_shader(renderer);
|
||||||
if !has_border_shader {
|
if !has_border_shader {
|
||||||
return None.into_iter().flatten();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let rv = zip(&self.shaders, &self.shader_locs)
|
for (shader, loc) in zip(&self.shaders, &self.shader_locs) {
|
||||||
.map(move |(shader, loc)| shader.clone().with_location(pos + *loc))
|
let elem = shader.clone().with_location(pos + *loc);
|
||||||
.map(TabIndicatorRenderElement::from);
|
push(TabIndicatorRenderElement::from(elem));
|
||||||
|
}
|
||||||
Some(rv).into_iter().flatten()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extra size occupied by the tab indicator.
|
/// Extra size occupied by the tab indicator.
|
||||||
|
|||||||
@@ -166,17 +166,6 @@ impl LayoutElement for TestWindow {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render<R: NiriRenderer>(
|
|
||||||
&self,
|
|
||||||
_renderer: &mut R,
|
|
||||||
_location: Point<f64, Logical>,
|
|
||||||
_scale: Scale<f64>,
|
|
||||||
_alpha: f32,
|
|
||||||
_target: RenderTarget,
|
|
||||||
) -> SplitElements<LayoutElementRenderElement<R>> {
|
|
||||||
SplitElements::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn request_size(
|
fn request_size(
|
||||||
&mut self,
|
&mut self,
|
||||||
size: Size<i32, Logical>,
|
size: Size<i32, Logical>,
|
||||||
|
|||||||
+105
-92
@@ -1007,13 +1007,14 @@ impl<W: LayoutElement> Tile<W> {
|
|||||||
Point::from((0., y))
|
Point::from((0., y))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_inner<'a, R: NiriRenderer + 'a>(
|
fn render_inner<R: NiriRenderer>(
|
||||||
&'a self,
|
&self,
|
||||||
renderer: &mut R,
|
renderer: &mut R,
|
||||||
location: Point<f64, Logical>,
|
location: Point<f64, Logical>,
|
||||||
focus_ring: bool,
|
focus_ring: bool,
|
||||||
target: RenderTarget,
|
target: RenderTarget,
|
||||||
) -> impl Iterator<Item = TileRenderElement<R>> + 'a {
|
push: &mut dyn FnMut(TileRenderElement<R>),
|
||||||
|
) {
|
||||||
let _span = tracy_client::span!("Tile::render_inner");
|
let _span = tracy_client::span!("Tile::render_inner");
|
||||||
|
|
||||||
let scale = Scale::from(self.scale);
|
let scale = Scale::from(self.scale);
|
||||||
@@ -1056,29 +1057,31 @@ impl<W: LayoutElement> Tile<W> {
|
|||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.scaled_by(1. - expanded_progress as f32);
|
.scaled_by(1. - expanded_progress as f32);
|
||||||
|
|
||||||
// If we're resizing, try to render a shader, or a fallback.
|
// Popups go on top, whether it's resize or not.
|
||||||
let mut resize_shader = None;
|
self.window.render_popups(
|
||||||
let mut resize_popups = None;
|
renderer,
|
||||||
let mut resize_fallback = None;
|
window_render_loc,
|
||||||
|
scale,
|
||||||
if let Some(resize) = &self.resize_animation {
|
win_alpha,
|
||||||
resize_popups = Some(
|
target,
|
||||||
self.window
|
&mut |elem| push(elem.into()),
|
||||||
.render_popups(renderer, window_render_loc, scale, win_alpha, target)
|
|
||||||
.into_iter()
|
|
||||||
.map(Into::into),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// If we're resizing, try to render a shader, or a fallback.
|
||||||
|
let mut pushed_resize = false;
|
||||||
|
if let Some(resize) = &self.resize_animation {
|
||||||
if ResizeRenderElement::has_shader(renderer) {
|
if ResizeRenderElement::has_shader(renderer) {
|
||||||
let gles_renderer = renderer.as_gles_renderer();
|
let gles_renderer = renderer.as_gles_renderer();
|
||||||
|
|
||||||
if let Some(texture_from) = resize.snapshot.texture(gles_renderer, scale, target) {
|
if let Some(texture_from) = resize.snapshot.texture(gles_renderer, scale, target) {
|
||||||
let window_elements = self.window.render_normal(
|
let mut window_elements = Vec::new();
|
||||||
|
self.window.render_normal(
|
||||||
gles_renderer,
|
gles_renderer,
|
||||||
Point::from((0., 0.)),
|
Point::from((0., 0.)),
|
||||||
scale,
|
scale,
|
||||||
1.,
|
1.,
|
||||||
target,
|
target,
|
||||||
|
&mut |elem| window_elements.push(elem),
|
||||||
);
|
);
|
||||||
|
|
||||||
let current = resize
|
let current = resize
|
||||||
@@ -1125,46 +1128,33 @@ impl<W: LayoutElement> Tile<W> {
|
|||||||
// This is not a problem for split popups as the code will look for them by
|
// This is not a problem for split popups as the code will look for them by
|
||||||
// original id when it doesn't find them on the offscreen.
|
// original id when it doesn't find them on the offscreen.
|
||||||
self.window.set_offscreen_data(Some(data));
|
self.window.set_offscreen_data(Some(data));
|
||||||
resize_shader = Some(elem.into());
|
push(elem.into());
|
||||||
|
pushed_resize = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if resize_shader.is_none() {
|
if !pushed_resize {
|
||||||
let fallback_buffer = SolidColorBuffer::new(area.size, [1., 0., 0., 1.]);
|
let fallback_buffer = SolidColorBuffer::new(area.size, [1., 0., 0., 1.]);
|
||||||
resize_fallback = Some(
|
let elem = SolidColorRenderElement::from_buffer(
|
||||||
SolidColorRenderElement::from_buffer(
|
|
||||||
&fallback_buffer,
|
&fallback_buffer,
|
||||||
area.loc,
|
area.loc,
|
||||||
win_alpha,
|
win_alpha,
|
||||||
Kind::Unspecified,
|
Kind::Unspecified,
|
||||||
)
|
|
||||||
.into(),
|
|
||||||
);
|
);
|
||||||
|
push(elem.into());
|
||||||
|
pushed_resize = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're not resizing, render the window itself.
|
// If we're not resizing, render the window itself.
|
||||||
let mut window_surface = None;
|
|
||||||
let mut window_popups = None;
|
|
||||||
let mut rounded_corner_damage = None;
|
|
||||||
let has_border_shader = BorderRenderElement::has_shader(renderer);
|
let has_border_shader = BorderRenderElement::has_shader(renderer);
|
||||||
if resize_shader.is_none() && resize_fallback.is_none() {
|
if !pushed_resize {
|
||||||
let window = self
|
|
||||||
.window
|
|
||||||
.render(renderer, window_render_loc, scale, win_alpha, target);
|
|
||||||
|
|
||||||
let geo = Rectangle::new(window_render_loc, window_size);
|
let geo = Rectangle::new(window_render_loc, window_size);
|
||||||
let radius = radius.fit_to(window_size.w as f32, window_size.h as f32);
|
let radius = radius.fit_to(window_size.w as f32, window_size.h as f32);
|
||||||
|
|
||||||
let clip_shader = ClippedSurfaceRenderElement::shader(renderer).cloned();
|
let clip_shader = ClippedSurfaceRenderElement::shader(renderer).cloned();
|
||||||
|
let clip = |elem| match elem {
|
||||||
if clip_to_geometry && clip_shader.is_some() {
|
|
||||||
let damage = self.rounded_corner_damage.element();
|
|
||||||
rounded_corner_damage = Some(damage.with_location(window_render_loc).into());
|
|
||||||
}
|
|
||||||
|
|
||||||
window_surface = Some(window.normal.into_iter().map(move |elem| match elem {
|
|
||||||
LayoutElementRenderElement::Wayland(elem) => {
|
LayoutElementRenderElement::Wayland(elem) => {
|
||||||
// If we should clip to geometry, render a clipped window.
|
// If we should clip to geometry, render a clipped window.
|
||||||
if clip_to_geometry {
|
if clip_to_geometry {
|
||||||
@@ -1213,21 +1203,24 @@ impl<W: LayoutElement> Tile<W> {
|
|||||||
// Otherwise, render the solid color as is.
|
// Otherwise, render the solid color as is.
|
||||||
LayoutElementRenderElement::SolidColor(elem).into()
|
LayoutElementRenderElement::SolidColor(elem).into()
|
||||||
}
|
}
|
||||||
}));
|
};
|
||||||
|
|
||||||
window_popups = Some(window.popups.into_iter().map(Into::into));
|
if clip_to_geometry && clip_shader.is_some() {
|
||||||
|
let damage = self.rounded_corner_damage.element();
|
||||||
|
push(damage.with_location(window_render_loc).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let rv = resize_popups
|
self.window.render_normal(
|
||||||
.into_iter()
|
renderer,
|
||||||
.flatten()
|
window_render_loc,
|
||||||
.chain(resize_shader)
|
scale,
|
||||||
.chain(resize_fallback)
|
win_alpha,
|
||||||
.chain(window_popups.into_iter().flatten())
|
target,
|
||||||
.chain(rounded_corner_damage)
|
&mut |elem| push(clip(elem)),
|
||||||
.chain(window_surface.into_iter().flatten());
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let elem = (fullscreen_progress > 0.).then(|| {
|
if fullscreen_progress > 0. {
|
||||||
let alpha = fullscreen_progress as f32;
|
let alpha = fullscreen_progress as f32;
|
||||||
|
|
||||||
// During the un/fullscreen animation, render a border element in order to use the
|
// During the un/fullscreen animation, render a border element in order to use the
|
||||||
@@ -1243,7 +1236,7 @@ impl<W: LayoutElement> Tile<W> {
|
|||||||
|
|
||||||
let size = self.fullscreen_backdrop.size();
|
let size = self.fullscreen_backdrop.size();
|
||||||
let color = self.fullscreen_backdrop.color();
|
let color = self.fullscreen_backdrop.color();
|
||||||
BorderRenderElement::new(
|
let elem = BorderRenderElement::new(
|
||||||
size,
|
size,
|
||||||
Rectangle::from_size(size),
|
Rectangle::from_size(size),
|
||||||
GradientInterpolation::default(),
|
GradientInterpolation::default(),
|
||||||
@@ -1256,47 +1249,50 @@ impl<W: LayoutElement> Tile<W> {
|
|||||||
scale.x as f32,
|
scale.x as f32,
|
||||||
alpha,
|
alpha,
|
||||||
)
|
)
|
||||||
.with_location(location)
|
.with_location(location);
|
||||||
.into()
|
push(elem.into());
|
||||||
} else {
|
} else {
|
||||||
SolidColorRenderElement::from_buffer(
|
let elem = SolidColorRenderElement::from_buffer(
|
||||||
&self.fullscreen_backdrop,
|
&self.fullscreen_backdrop,
|
||||||
location,
|
location,
|
||||||
alpha,
|
alpha,
|
||||||
Kind::Unspecified,
|
Kind::Unspecified,
|
||||||
)
|
);
|
||||||
.into()
|
push(elem.into());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
let rv = rv.chain(elem);
|
|
||||||
|
|
||||||
let elem = self.visual_border_width().map(|width| {
|
if let Some(width) = self.visual_border_width() {
|
||||||
self.border
|
self.border.render(
|
||||||
.render(renderer, location + Point::from((width, width)))
|
renderer,
|
||||||
.map(Into::into)
|
location + Point::from((width, width)),
|
||||||
});
|
&mut |elem| push(elem.into()),
|
||||||
let rv = rv.chain(elem.into_iter().flatten());
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Hide the focus ring when maximized/fullscreened. It's not normally visible anyway due to
|
// Hide the focus ring when maximized/fullscreened. It's not normally visible anyway due to
|
||||||
// being outside the monitor or obscured by a solid colored bar, but it is visible under
|
// being outside the monitor or obscured by a solid colored bar, but it is visible under
|
||||||
// semitransparent bars in maximized state (which is a bit weird) and in the overview (also
|
// semitransparent bars in maximized state (which is a bit weird) and in the overview (also
|
||||||
// a bit weird).
|
// a bit weird).
|
||||||
let elem = (focus_ring && expanded_progress < 1.)
|
if focus_ring && expanded_progress < 1. {
|
||||||
.then(|| self.focus_ring.render(renderer, location).map(Into::into));
|
self.focus_ring
|
||||||
let rv = rv.chain(elem.into_iter().flatten());
|
.render(renderer, location, &mut |elem| push(elem.into()));
|
||||||
|
|
||||||
let elem = (expanded_progress < 1.)
|
|
||||||
.then(|| self.shadow.render(renderer, location).map(Into::into));
|
|
||||||
rv.chain(elem.into_iter().flatten())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render<'a, R: NiriRenderer + 'a>(
|
if expanded_progress < 1. {
|
||||||
&'a self,
|
self.shadow
|
||||||
|
.render(renderer, location, &mut |elem| push(elem.into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render<R: NiriRenderer>(
|
||||||
|
&self,
|
||||||
renderer: &mut R,
|
renderer: &mut R,
|
||||||
location: Point<f64, Logical>,
|
location: Point<f64, Logical>,
|
||||||
focus_ring: bool,
|
focus_ring: bool,
|
||||||
target: RenderTarget,
|
target: RenderTarget,
|
||||||
) -> impl Iterator<Item = TileRenderElement<R>> + 'a {
|
push: &mut dyn FnMut(TileRenderElement<R>),
|
||||||
|
) {
|
||||||
let _span = tracy_client::span!("Tile::render");
|
let _span = tracy_client::span!("Tile::render");
|
||||||
|
|
||||||
let scale = Scale::from(self.scale);
|
let scale = Scale::from(self.scale);
|
||||||
@@ -1306,16 +1302,19 @@ impl<W: LayoutElement> Tile<W> {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.map_or(1., |alpha| alpha.anim.clamped_value()) as f32;
|
.map_or(1., |alpha| alpha.anim.clamped_value()) as f32;
|
||||||
|
|
||||||
let mut open_anim_elem = None;
|
let mut pushed = false;
|
||||||
let mut alpha_anim_elem = None;
|
|
||||||
let mut window_elems = None;
|
|
||||||
|
|
||||||
self.window().set_offscreen_data(None);
|
self.window().set_offscreen_data(None);
|
||||||
|
|
||||||
if let Some(open) = &self.open_animation {
|
if let Some(open) = &self.open_animation {
|
||||||
let renderer = renderer.as_gles_renderer();
|
let renderer = renderer.as_gles_renderer();
|
||||||
let elements = self.render_inner(renderer, Point::from((0., 0.)), focus_ring, target);
|
let mut elements = Vec::new();
|
||||||
let elements = elements.collect::<Vec<TileRenderElement<_>>>();
|
self.render_inner(
|
||||||
|
renderer,
|
||||||
|
Point::from((0., 0.)),
|
||||||
|
focus_ring,
|
||||||
|
target,
|
||||||
|
&mut |elem| elements.push(elem),
|
||||||
|
);
|
||||||
match open.render(
|
match open.render(
|
||||||
renderer,
|
renderer,
|
||||||
&elements,
|
&elements,
|
||||||
@@ -1326,7 +1325,8 @@ impl<W: LayoutElement> Tile<W> {
|
|||||||
) {
|
) {
|
||||||
Ok((elem, data)) => {
|
Ok((elem, data)) => {
|
||||||
self.window().set_offscreen_data(Some(data));
|
self.window().set_offscreen_data(Some(data));
|
||||||
open_anim_elem = Some(elem.into());
|
push(elem.into());
|
||||||
|
pushed = true;
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!("error rendering window opening animation: {err:?}");
|
warn!("error rendering window opening animation: {err:?}");
|
||||||
@@ -1334,15 +1334,22 @@ impl<W: LayoutElement> Tile<W> {
|
|||||||
}
|
}
|
||||||
} else if let Some(alpha) = &self.alpha_animation {
|
} else if let Some(alpha) = &self.alpha_animation {
|
||||||
let renderer = renderer.as_gles_renderer();
|
let renderer = renderer.as_gles_renderer();
|
||||||
let elements = self.render_inner(renderer, Point::from((0., 0.)), focus_ring, target);
|
let mut elements = Vec::new();
|
||||||
let elements = elements.collect::<Vec<TileRenderElement<_>>>();
|
self.render_inner(
|
||||||
|
renderer,
|
||||||
|
Point::from((0., 0.)),
|
||||||
|
focus_ring,
|
||||||
|
target,
|
||||||
|
&mut |elem| elements.push(elem),
|
||||||
|
);
|
||||||
match alpha.offscreen.render(renderer, scale, &elements) {
|
match alpha.offscreen.render(renderer, scale, &elements) {
|
||||||
Ok((elem, _sync, data)) => {
|
Ok((elem, _sync, data)) => {
|
||||||
let offset = elem.offset();
|
let offset = elem.offset();
|
||||||
let elem = elem.with_alpha(tile_alpha).with_offset(location + offset);
|
let elem = elem.with_alpha(tile_alpha).with_offset(location + offset);
|
||||||
|
|
||||||
self.window().set_offscreen_data(Some(data));
|
self.window().set_offscreen_data(Some(data));
|
||||||
alpha_anim_elem = Some(elem.into());
|
push(elem.into());
|
||||||
|
pushed = true;
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!("error rendering tile to offscreen for alpha animation: {err:?}");
|
warn!("error rendering tile to offscreen for alpha animation: {err:?}");
|
||||||
@@ -1350,14 +1357,11 @@ impl<W: LayoutElement> Tile<W> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if open_anim_elem.is_none() && alpha_anim_elem.is_none() {
|
if !pushed {
|
||||||
window_elems = Some(self.render_inner(renderer, location, focus_ring, target));
|
self.render_inner(renderer, location, focus_ring, target, &mut |elem| {
|
||||||
|
push(elem)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
open_anim_elem
|
|
||||||
.into_iter()
|
|
||||||
.chain(alpha_anim_elem)
|
|
||||||
.chain(window_elems.into_iter().flatten())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn store_unmap_snapshot_if_empty(&mut self, renderer: &mut GlesRenderer) {
|
pub fn store_unmap_snapshot_if_empty(&mut self, renderer: &mut GlesRenderer) {
|
||||||
@@ -1371,19 +1375,28 @@ impl<W: LayoutElement> Tile<W> {
|
|||||||
fn render_snapshot(&self, renderer: &mut GlesRenderer) -> TileRenderSnapshot {
|
fn render_snapshot(&self, renderer: &mut GlesRenderer) -> TileRenderSnapshot {
|
||||||
let _span = tracy_client::span!("Tile::render_snapshot");
|
let _span = tracy_client::span!("Tile::render_snapshot");
|
||||||
|
|
||||||
let contents = self.render(renderer, Point::from((0., 0.)), false, RenderTarget::Output);
|
let mut contents = Vec::new();
|
||||||
|
self.render(
|
||||||
|
renderer,
|
||||||
|
Point::from((0., 0.)),
|
||||||
|
false,
|
||||||
|
RenderTarget::Output,
|
||||||
|
&mut |elem| contents.push(elem),
|
||||||
|
);
|
||||||
|
|
||||||
// A bit of a hack to render blocked out as for screencast, but I think it's fine here.
|
// A bit of a hack to render blocked out as for screencast, but I think it's fine here.
|
||||||
let blocked_out_contents = self.render(
|
let mut blocked_out_contents = Vec::new();
|
||||||
|
self.render(
|
||||||
renderer,
|
renderer,
|
||||||
Point::from((0., 0.)),
|
Point::from((0., 0.)),
|
||||||
false,
|
false,
|
||||||
RenderTarget::Screencast,
|
RenderTarget::Screencast,
|
||||||
|
&mut |elem| blocked_out_contents.push(elem),
|
||||||
);
|
);
|
||||||
|
|
||||||
RenderSnapshot {
|
RenderSnapshot {
|
||||||
contents: contents.collect(),
|
contents,
|
||||||
blocked_out_contents: blocked_out_contents.collect(),
|
blocked_out_contents,
|
||||||
block_out_from: self.window.rules().block_out_from,
|
block_out_from: self.window.rules().block_out_from,
|
||||||
size: self.animated_tile_size(),
|
size: self.animated_tile_size(),
|
||||||
texture: Default::default(),
|
texture: Default::default(),
|
||||||
|
|||||||
+29
-20
@@ -1624,39 +1624,48 @@ impl<W: LayoutElement> Workspace<W> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_elements<R: NiriRenderer>(
|
pub fn render_scrolling<R: NiriRenderer>(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut R,
|
renderer: &mut R,
|
||||||
target: RenderTarget,
|
target: RenderTarget,
|
||||||
focus_ring: bool,
|
focus_ring: bool,
|
||||||
) -> (
|
push: &mut dyn FnMut(WorkspaceRenderElement<R>),
|
||||||
impl Iterator<Item = WorkspaceRenderElement<R>>,
|
|
||||||
impl Iterator<Item = WorkspaceRenderElement<R>>,
|
|
||||||
) {
|
) {
|
||||||
let scrolling_focus_ring = focus_ring && !self.floating_is_active();
|
let scrolling_focus_ring = focus_ring && !self.floating_is_active();
|
||||||
let scrolling = self
|
self.scrolling
|
||||||
.scrolling
|
.render(renderer, target, scrolling_focus_ring, &mut |elem| {
|
||||||
.render_elements(renderer, target, scrolling_focus_ring);
|
push(elem.into())
|
||||||
let scrolling = scrolling.into_iter().map(WorkspaceRenderElement::from);
|
|
||||||
|
|
||||||
let floating_focus_ring = focus_ring && self.floating_is_active();
|
|
||||||
let floating = self.is_floating_visible().then(|| {
|
|
||||||
let view_rect = Rectangle::from_size(self.view_size);
|
|
||||||
let floating =
|
|
||||||
self.floating
|
|
||||||
.render_elements(renderer, view_rect, target, floating_focus_ring);
|
|
||||||
floating.into_iter().map(WorkspaceRenderElement::from)
|
|
||||||
});
|
});
|
||||||
let floating = floating.into_iter().flatten();
|
}
|
||||||
|
|
||||||
(floating, scrolling)
|
pub fn render_floating<R: NiriRenderer>(
|
||||||
|
&self,
|
||||||
|
renderer: &mut R,
|
||||||
|
target: RenderTarget,
|
||||||
|
focus_ring: bool,
|
||||||
|
push: &mut dyn FnMut(WorkspaceRenderElement<R>),
|
||||||
|
) {
|
||||||
|
if !self.is_floating_visible() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let view_rect = Rectangle::from_size(self.view_size);
|
||||||
|
let floating_focus_ring = focus_ring && self.floating_is_active();
|
||||||
|
self.floating.render(
|
||||||
|
renderer,
|
||||||
|
view_rect,
|
||||||
|
target,
|
||||||
|
floating_focus_ring,
|
||||||
|
&mut |elem| push(elem.into()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_shadow<R: NiriRenderer>(
|
pub fn render_shadow<R: NiriRenderer>(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut R,
|
renderer: &mut R,
|
||||||
) -> impl Iterator<Item = ShadowRenderElement> + '_ {
|
push: &mut dyn FnMut(ShadowRenderElement),
|
||||||
self.shadow.render(renderer, Point::from((0., 0.)))
|
) {
|
||||||
|
self.shadow.render(renderer, Point::from((0., 0.)), push);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_background(&self) -> SolidColorRenderElement {
|
pub fn render_background(&self) -> SolidColorRenderElement {
|
||||||
|
|||||||
+172
-165
@@ -22,9 +22,7 @@ use smithay::backend::allocator::Fourcc;
|
|||||||
use smithay::backend::input::Keycode;
|
use smithay::backend::input::Keycode;
|
||||||
use smithay::backend::renderer::damage::OutputDamageTracker;
|
use smithay::backend::renderer::damage::OutputDamageTracker;
|
||||||
use smithay::backend::renderer::element::memory::MemoryRenderBufferRenderElement;
|
use smithay::backend::renderer::element::memory::MemoryRenderBufferRenderElement;
|
||||||
use smithay::backend::renderer::element::surface::{
|
use smithay::backend::renderer::element::surface::WaylandSurfaceRenderElement;
|
||||||
render_elements_from_surface_tree, WaylandSurfaceRenderElement,
|
|
||||||
};
|
|
||||||
use smithay::backend::renderer::element::utils::{
|
use smithay::backend::renderer::element::utils::{
|
||||||
select_dmabuf_feedback, CropRenderElement, Relocate, RelocateRenderElement,
|
select_dmabuf_feedback, CropRenderElement, Relocate, RelocateRenderElement,
|
||||||
RescaleRenderElement,
|
RescaleRenderElement,
|
||||||
@@ -157,10 +155,11 @@ use crate::render_helpers::debug::draw_opaque_regions;
|
|||||||
use crate::render_helpers::primary_gpu_texture::PrimaryGpuTextureRenderElement;
|
use crate::render_helpers::primary_gpu_texture::PrimaryGpuTextureRenderElement;
|
||||||
use crate::render_helpers::renderer::NiriRenderer;
|
use crate::render_helpers::renderer::NiriRenderer;
|
||||||
use crate::render_helpers::solid_color::{SolidColorBuffer, SolidColorRenderElement};
|
use crate::render_helpers::solid_color::{SolidColorBuffer, SolidColorRenderElement};
|
||||||
|
use crate::render_helpers::surface::push_elements_from_surface_tree;
|
||||||
use crate::render_helpers::texture::TextureBuffer;
|
use crate::render_helpers::texture::TextureBuffer;
|
||||||
use crate::render_helpers::{
|
use crate::render_helpers::{
|
||||||
encompassing_geo, render_to_dmabuf, render_to_encompassing_texture, render_to_shm,
|
encompassing_geo, render_to_dmabuf, render_to_encompassing_texture, render_to_shm,
|
||||||
render_to_texture, render_to_vec, shaders, RenderTarget, SplitElements,
|
render_to_texture, render_to_vec, shaders, RenderTarget,
|
||||||
};
|
};
|
||||||
use crate::ui::config_error_notification::ConfigErrorNotification;
|
use crate::ui::config_error_notification::ConfigErrorNotification;
|
||||||
use crate::ui::exit_confirm_dialog::{ExitConfirmDialog, ExitConfirmDialogRenderElement};
|
use crate::ui::exit_confirm_dialog::{ExitConfirmDialog, ExitConfirmDialogRenderElement};
|
||||||
@@ -2075,9 +2074,8 @@ impl State {
|
|||||||
|
|
||||||
self.backend.with_primary_renderer(|renderer| {
|
self.backend.with_primary_renderer(|renderer| {
|
||||||
// FIXME: pointer.
|
// FIXME: pointer.
|
||||||
let elements = mapped
|
let mut elements = Vec::new();
|
||||||
.render_for_screen_cast(renderer, scale)
|
mapped.render_for_screen_cast(renderer, scale, &mut |elem| elements.push(elem));
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
if cast.dequeue_buffer_and_render(renderer, &elements, bbox.size, scale) {
|
if cast.dequeue_buffer_and_render(renderer, &elements, bbox.size, scale) {
|
||||||
cast.last_frame_time = get_monotonic_time();
|
cast.last_frame_time = get_monotonic_time();
|
||||||
@@ -3865,13 +3863,14 @@ impl Niri {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pointer_element<R: NiriRenderer>(
|
pub fn render_pointer<R: NiriRenderer>(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut R,
|
renderer: &mut R,
|
||||||
output: &Output,
|
output: &Output,
|
||||||
) -> Vec<OutputRenderElements<R>> {
|
push: &mut dyn FnMut(PointerRenderElements<R>),
|
||||||
|
) {
|
||||||
if !self.pointer_visibility.is_visible() {
|
if !self.pointer_visibility.is_visible() {
|
||||||
return vec![];
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let _span = tracy_client::span!("Niri::pointer_element");
|
let _span = tracy_client::span!("Niri::pointer_element");
|
||||||
@@ -3890,20 +3889,21 @@ impl Niri {
|
|||||||
|
|
||||||
let output_scale = Scale::from(output.current_scale().fractional_scale());
|
let output_scale = Scale::from(output.current_scale().fractional_scale());
|
||||||
|
|
||||||
let mut pointer_elements = match render_cursor {
|
match render_cursor {
|
||||||
RenderCursor::Hidden => vec![],
|
RenderCursor::Hidden => (),
|
||||||
RenderCursor::Surface { surface, hotspot } => {
|
RenderCursor::Surface { surface, hotspot } => {
|
||||||
let pointer_pos =
|
let pointer_pos =
|
||||||
(pointer_pos - hotspot.to_f64()).to_physical_precise_round(output_scale);
|
(pointer_pos - hotspot.to_f64()).to_physical_precise_round(output_scale);
|
||||||
|
|
||||||
render_elements_from_surface_tree(
|
push_elements_from_surface_tree(
|
||||||
renderer,
|
renderer,
|
||||||
&surface,
|
&surface,
|
||||||
pointer_pos,
|
pointer_pos,
|
||||||
output_scale,
|
output_scale,
|
||||||
1.,
|
1.,
|
||||||
Kind::Cursor,
|
Kind::Cursor,
|
||||||
)
|
&mut |elem| push(elem.into()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
RenderCursor::Named {
|
RenderCursor::Named {
|
||||||
icon,
|
icon,
|
||||||
@@ -3916,8 +3916,7 @@ impl Niri {
|
|||||||
(pointer_pos - hotspot.to_f64()).to_physical_precise_round(output_scale);
|
(pointer_pos - hotspot.to_f64()).to_physical_precise_round(output_scale);
|
||||||
|
|
||||||
let texture = self.cursor_texture_cache.get(icon, scale, &cursor, idx);
|
let texture = self.cursor_texture_cache.get(icon, scale, &cursor, idx);
|
||||||
let mut pointer_elements = vec![];
|
match MemoryRenderBufferRenderElement::from_buffer(
|
||||||
let pointer_element = match MemoryRenderBufferRenderElement::from_buffer(
|
|
||||||
renderer,
|
renderer,
|
||||||
pointer_pos,
|
pointer_pos,
|
||||||
&texture,
|
&texture,
|
||||||
@@ -3926,34 +3925,27 @@ impl Niri {
|
|||||||
None,
|
None,
|
||||||
Kind::Cursor,
|
Kind::Cursor,
|
||||||
) {
|
) {
|
||||||
Ok(element) => Some(element),
|
Ok(element) => push(element.into()),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!("error importing a cursor texture: {err:?}");
|
warn!("error importing a cursor texture: {err:?}");
|
||||||
None
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
if let Some(element) = pointer_element {
|
|
||||||
pointer_elements.push(OutputRenderElements::NamedPointer(element));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pointer_elements
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
if let Some(dnd_icon) = self.dnd_icon.as_ref() {
|
if let Some(dnd_icon) = self.dnd_icon.as_ref() {
|
||||||
let pointer_pos =
|
let pointer_pos =
|
||||||
(pointer_pos + dnd_icon.offset.to_f64()).to_physical_precise_round(output_scale);
|
(pointer_pos + dnd_icon.offset.to_f64()).to_physical_precise_round(output_scale);
|
||||||
pointer_elements.extend(render_elements_from_surface_tree(
|
push_elements_from_surface_tree(
|
||||||
renderer,
|
renderer,
|
||||||
&dnd_icon.surface,
|
&dnd_icon.surface,
|
||||||
pointer_pos,
|
pointer_pos,
|
||||||
output_scale,
|
output_scale,
|
||||||
1.,
|
1.,
|
||||||
Kind::ScanoutCandidate,
|
Kind::ScanoutCandidate,
|
||||||
));
|
&mut |elem| push(elem.into()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pointer_elements
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn refresh_pointer_outputs(&mut self) {
|
pub fn refresh_pointer_outputs(&mut self) {
|
||||||
@@ -4317,7 +4309,7 @@ impl Niri {
|
|||||||
// The pointer goes on the top.
|
// The pointer goes on the top.
|
||||||
let mut elements = vec![];
|
let mut elements = vec![];
|
||||||
if include_pointer {
|
if include_pointer {
|
||||||
elements = self.pointer_element(renderer, output);
|
self.render_pointer(renderer, output, &mut |elem| elements.push(elem.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next, the screen transition texture.
|
// Next, the screen transition texture.
|
||||||
@@ -4329,12 +4321,8 @@ impl Niri {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Next, the exit confirm dialog.
|
// Next, the exit confirm dialog.
|
||||||
elements.extend(
|
|
||||||
self.exit_confirm_dialog
|
self.exit_confirm_dialog
|
||||||
.render(renderer, output)
|
.render(renderer, output, &mut |elem| elements.push(elem.into()));
|
||||||
.into_iter()
|
|
||||||
.map(OutputRenderElements::from),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Next, the config error notification too.
|
// Next, the config error notification too.
|
||||||
if let Some(element) = self.config_error_notification.render(renderer, output) {
|
if let Some(element) = self.config_error_notification.render(renderer, output) {
|
||||||
@@ -4345,14 +4333,15 @@ impl Niri {
|
|||||||
if self.is_locked() {
|
if self.is_locked() {
|
||||||
let state = self.output_state.get(output).unwrap();
|
let state = self.output_state.get(output).unwrap();
|
||||||
if let Some(surface) = state.lock_surface.as_ref() {
|
if let Some(surface) = state.lock_surface.as_ref() {
|
||||||
elements.extend(render_elements_from_surface_tree(
|
push_elements_from_surface_tree(
|
||||||
renderer,
|
renderer,
|
||||||
surface.wl_surface(),
|
surface.wl_surface(),
|
||||||
(0, 0),
|
Point::new(0, 0),
|
||||||
output_scale,
|
output_scale,
|
||||||
1.,
|
1.,
|
||||||
Kind::ScanoutCandidate,
|
Kind::ScanoutCandidate,
|
||||||
));
|
&mut |elem| elements.push(elem.into()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw the solid color background.
|
// Draw the solid color background.
|
||||||
@@ -4384,12 +4373,8 @@ impl Niri {
|
|||||||
|
|
||||||
// If the screenshot UI is open, draw it.
|
// If the screenshot UI is open, draw it.
|
||||||
if self.screenshot_ui.is_open() {
|
if self.screenshot_ui.is_open() {
|
||||||
elements.extend(
|
|
||||||
self.screenshot_ui
|
self.screenshot_ui
|
||||||
.render_output(output, target)
|
.render_output(output, target, &mut |elem| elements.push(elem.into()));
|
||||||
.into_iter()
|
|
||||||
.map(OutputRenderElements::from),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Add the backdrop for outputs that were connected while the screenshot UI was open.
|
// Add the backdrop for outputs that were connected while the screenshot UI was open.
|
||||||
elements.push(backdrop);
|
elements.push(backdrop);
|
||||||
@@ -4406,13 +4391,10 @@ impl Niri {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Then, the Alt-Tab switcher.
|
// Then, the Alt-Tab switcher.
|
||||||
let mru_elements = self
|
self.window_mru_ui
|
||||||
.window_mru_ui
|
.render_output(self, output, renderer, target, &mut |elem| {
|
||||||
.render_output(self, output, renderer, target)
|
elements.push(elem.into())
|
||||||
.into_iter()
|
});
|
||||||
.flatten()
|
|
||||||
.map(OutputRenderElements::from);
|
|
||||||
elements.extend(mru_elements);
|
|
||||||
|
|
||||||
// Don't draw the focus ring on the workspaces while interactively moving above those
|
// Don't draw the focus ring on the workspaces while interactively moving above those
|
||||||
// workspaces, since the interactively-moved window already has a focus ring.
|
// workspaces, since the interactively-moved window already has a focus ring.
|
||||||
@@ -4421,129 +4403,119 @@ impl Niri {
|
|||||||
// Get monitor elements.
|
// Get monitor elements.
|
||||||
let mon = self.layout.monitor_for_output(output).unwrap();
|
let mon = self.layout.monitor_for_output(output).unwrap();
|
||||||
let zoom = mon.overview_zoom();
|
let zoom = mon.overview_zoom();
|
||||||
let monitor_elements = Vec::from_iter(
|
|
||||||
mon.render_elements(renderer, target, focus_ring)
|
|
||||||
.map(|(geo, bg, iter)| (geo, bg, Vec::from_iter(iter))),
|
|
||||||
);
|
|
||||||
let workspace_shadow_elements = Vec::from_iter(mon.render_workspace_shadows(renderer));
|
|
||||||
let insert_hint_elements = mon.render_insert_hint_between_workspaces(renderer);
|
|
||||||
let int_move_elements: Vec<_> = self
|
|
||||||
.layout
|
|
||||||
.render_interactive_move_for_output(renderer, output, target)
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
// Get layer-shell elements.
|
// Get layer-shell elements.
|
||||||
let layer_map = layer_map_for_output(output);
|
let layer_map = layer_map_for_output(output);
|
||||||
let mut extend_from_layer =
|
|
||||||
|elements: &mut SplitElements<LayerSurfaceRenderElement<R>>, layer, for_backdrop| {
|
// We use macros instead of closures to avoid borrowing issues (renderer and elements go
|
||||||
self.render_layer(renderer, target, &layer_map, layer, elements, for_backdrop);
|
// into different functions).
|
||||||
};
|
macro_rules! push_popups_from_layer {
|
||||||
|
($layer:expr, $backdrop:expr, $push:expr) => {{
|
||||||
|
self.render_layer_popups(renderer, target, &layer_map, $layer, $backdrop, $push);
|
||||||
|
}};
|
||||||
|
($layer:expr, true) => {{
|
||||||
|
push_popups_from_layer!($layer, true, &mut |elem| elements.push(elem.into()));
|
||||||
|
}};
|
||||||
|
($layer:expr, $push:expr) => {{
|
||||||
|
push_popups_from_layer!($layer, false, $push);
|
||||||
|
}};
|
||||||
|
($layer:expr) => {{
|
||||||
|
push_popups_from_layer!($layer, false, &mut |elem| elements.push(elem.into()));
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
macro_rules! push_normal_from_layer {
|
||||||
|
($layer:expr, $backdrop:expr, $push:expr) => {{
|
||||||
|
self.render_layer_normal(renderer, target, &layer_map, $layer, $backdrop, $push);
|
||||||
|
}};
|
||||||
|
($layer:expr, true) => {{
|
||||||
|
push_normal_from_layer!($layer, true, &mut |elem| elements.push(elem.into()));
|
||||||
|
}};
|
||||||
|
($layer:expr, $push:expr) => {{
|
||||||
|
push_normal_from_layer!($layer, false, $push);
|
||||||
|
}};
|
||||||
|
($layer:expr) => {{
|
||||||
|
push_normal_from_layer!($layer, false, &mut |elem| elements.push(elem.into()));
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
// The overlay layer elements go next.
|
// The overlay layer elements go next.
|
||||||
let mut layer_elems = SplitElements::default();
|
push_popups_from_layer!(Layer::Overlay);
|
||||||
extend_from_layer(&mut layer_elems, Layer::Overlay, false);
|
push_normal_from_layer!(Layer::Overlay);
|
||||||
elements.extend(layer_elems.into_iter().map(OutputRenderElements::from));
|
|
||||||
|
|
||||||
// Collect the top layer elements.
|
|
||||||
let mut layer_elems = SplitElements::default();
|
|
||||||
extend_from_layer(&mut layer_elems, Layer::Top, false);
|
|
||||||
let top_layer = layer_elems;
|
|
||||||
|
|
||||||
// When rendering above the top layer, we put the regular monitor elements first.
|
// When rendering above the top layer, we put the regular monitor elements first.
|
||||||
// Otherwise, we will render all layer-shell pop-ups and the top layer on top.
|
// Otherwise, we will render all layer-shell pop-ups and the top layer on top.
|
||||||
if mon.render_above_top_layer() {
|
if mon.render_above_top_layer() {
|
||||||
// Collect all other layer-shell elements.
|
self.layout
|
||||||
let mut layer_elems = SplitElements::default();
|
.render_interactive_move_for_output(renderer, output, target, &mut |elem| {
|
||||||
extend_from_layer(&mut layer_elems, Layer::Bottom, false);
|
elements.push(elem.into())
|
||||||
extend_from_layer(&mut layer_elems, Layer::Background, false);
|
});
|
||||||
|
|
||||||
elements.extend(
|
mon.render_insert_hint_between_workspaces(renderer, &mut |elem| {
|
||||||
int_move_elements
|
elements.push(elem.into())
|
||||||
.into_iter()
|
});
|
||||||
.map(OutputRenderElements::from),
|
|
||||||
);
|
|
||||||
elements.extend(
|
|
||||||
insert_hint_elements
|
|
||||||
.into_iter()
|
|
||||||
.map(OutputRenderElements::from),
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut ws_background = None;
|
mon.render_workspaces(renderer, target, focus_ring, &mut |elem| {
|
||||||
elements.extend(
|
elements.push(elem.into())
|
||||||
monitor_elements
|
});
|
||||||
.into_iter()
|
|
||||||
.flat_map(|(_ws_geo, ws_bg, iter)| {
|
|
||||||
ws_background = Some(ws_bg);
|
|
||||||
iter
|
|
||||||
})
|
|
||||||
.map(OutputRenderElements::from),
|
|
||||||
);
|
|
||||||
|
|
||||||
elements.extend(top_layer.into_iter().map(OutputRenderElements::from));
|
push_popups_from_layer!(Layer::Top);
|
||||||
elements.extend(layer_elems.into_iter().map(OutputRenderElements::from));
|
push_normal_from_layer!(Layer::Top);
|
||||||
|
|
||||||
if let Some(ws_background) = ws_background {
|
push_popups_from_layer!(Layer::Bottom);
|
||||||
elements.push(OutputRenderElements::from(ws_background));
|
push_popups_from_layer!(Layer::Background);
|
||||||
|
push_normal_from_layer!(Layer::Bottom);
|
||||||
|
push_normal_from_layer!(Layer::Background);
|
||||||
|
|
||||||
|
// We don't expect more than one workspace when render_above_top_layer().
|
||||||
|
if let Some((ws, _geo)) = mon.workspaces_with_render_geo().next() {
|
||||||
|
elements.push(ws.render_background().into());
|
||||||
}
|
}
|
||||||
|
|
||||||
elements.extend(
|
|
||||||
workspace_shadow_elements
|
|
||||||
.into_iter()
|
|
||||||
.map(OutputRenderElements::from),
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
elements.extend(top_layer.into_iter().map(OutputRenderElements::from));
|
push_popups_from_layer!(Layer::Top);
|
||||||
|
push_normal_from_layer!(Layer::Top);
|
||||||
|
|
||||||
elements.extend(
|
self.layout
|
||||||
int_move_elements
|
.render_interactive_move_for_output(renderer, output, target, &mut |elem| {
|
||||||
.into_iter()
|
elements.push(elem.into())
|
||||||
.map(OutputRenderElements::from),
|
});
|
||||||
);
|
|
||||||
|
|
||||||
elements.extend(
|
mon.render_insert_hint_between_workspaces(renderer, &mut |elem| {
|
||||||
insert_hint_elements
|
elements.push(elem.into())
|
||||||
.into_iter()
|
});
|
||||||
.map(OutputRenderElements::from),
|
|
||||||
);
|
|
||||||
|
|
||||||
for (ws_geo, ws_background, ws_elements) in monitor_elements {
|
// Macro instead of closure to avoid borrowing elements.
|
||||||
// Collect all other layer-shell elements.
|
macro_rules! process {
|
||||||
let mut layer_elems = SplitElements::default();
|
($geo:expr) => {{
|
||||||
extend_from_layer(&mut layer_elems, Layer::Bottom, false);
|
&mut |elem| {
|
||||||
extend_from_layer(&mut layer_elems, Layer::Background, false);
|
if let Some(elem) = scale_relocate_crop(elem, output_scale, zoom, $geo) {
|
||||||
|
elements.push(elem.into());
|
||||||
elements.extend(
|
}
|
||||||
layer_elems
|
}
|
||||||
.popups
|
}};
|
||||||
.into_iter()
|
|
||||||
.filter_map(|elem| scale_relocate_crop(elem, output_scale, zoom, ws_geo))
|
|
||||||
.map(OutputRenderElements::from),
|
|
||||||
);
|
|
||||||
|
|
||||||
elements.extend(ws_elements.into_iter().map(OutputRenderElements::from));
|
|
||||||
|
|
||||||
elements.extend(
|
|
||||||
layer_elems
|
|
||||||
.normal
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|elem| scale_relocate_crop(elem, output_scale, zoom, ws_geo))
|
|
||||||
.map(OutputRenderElements::from),
|
|
||||||
);
|
|
||||||
|
|
||||||
elements.push(OutputRenderElements::from(ws_background));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
elements.extend(
|
for (_ws, geo) in mon.workspaces_with_render_geo() {
|
||||||
workspace_shadow_elements
|
push_popups_from_layer!(Layer::Bottom, process!(geo));
|
||||||
.into_iter()
|
push_popups_from_layer!(Layer::Background, process!(geo));
|
||||||
.map(OutputRenderElements::from),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mon.render_workspaces(renderer, target, focus_ring, &mut |elem| {
|
||||||
|
elements.push(elem.into())
|
||||||
|
});
|
||||||
|
|
||||||
|
for (ws, geo) in mon.workspaces_with_render_geo() {
|
||||||
|
push_normal_from_layer!(Layer::Bottom, process!(geo));
|
||||||
|
push_normal_from_layer!(Layer::Background, process!(geo));
|
||||||
|
|
||||||
|
process!(geo)(ws.render_background());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mon.render_workspace_shadows(renderer, &mut |elem| elements.push(elem.into()));
|
||||||
|
|
||||||
// Then the backdrop.
|
// Then the backdrop.
|
||||||
let mut layer_elems = SplitElements::default();
|
push_popups_from_layer!(Layer::Background, true);
|
||||||
extend_from_layer(&mut layer_elems, Layer::Background, true);
|
push_normal_from_layer!(Layer::Background, true);
|
||||||
elements.extend(layer_elems.into_iter().map(OutputRenderElements::from));
|
|
||||||
|
|
||||||
elements.push(backdrop);
|
elements.push(backdrop);
|
||||||
|
|
||||||
@@ -4554,18 +4526,14 @@ impl Niri {
|
|||||||
elements
|
elements
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
fn layers_in_render_order<'a>(
|
||||||
fn render_layer<R: NiriRenderer>(
|
&'a self,
|
||||||
&self,
|
layer_map: &'a LayerMap,
|
||||||
renderer: &mut R,
|
|
||||||
target: RenderTarget,
|
|
||||||
layer_map: &LayerMap,
|
|
||||||
layer: Layer,
|
layer: Layer,
|
||||||
elements: &mut SplitElements<LayerSurfaceRenderElement<R>>,
|
|
||||||
for_backdrop: bool,
|
for_backdrop: bool,
|
||||||
) {
|
) -> impl Iterator<Item = (&'a MappedLayer, Rectangle<i32, Logical>)> {
|
||||||
// LayerMap returns layers in reverse stacking order.
|
// LayerMap returns layers in reverse stacking order.
|
||||||
let iter = layer_map.layers_on(layer).rev().filter_map(|surface| {
|
layer_map.layers_on(layer).rev().filter_map(move |surface| {
|
||||||
let mapped = self.mapped_layer_surfaces.get(surface)?;
|
let mapped = self.mapped_layer_surfaces.get(surface)?;
|
||||||
|
|
||||||
if for_backdrop != mapped.place_within_backdrop() {
|
if for_backdrop != mapped.place_within_backdrop() {
|
||||||
@@ -4574,9 +4542,34 @@ impl Niri {
|
|||||||
|
|
||||||
let geo = layer_map.layer_geometry(surface)?;
|
let geo = layer_map.layer_geometry(surface)?;
|
||||||
Some((mapped, geo))
|
Some((mapped, geo))
|
||||||
});
|
})
|
||||||
for (mapped, geo) in iter {
|
}
|
||||||
elements.extend(mapped.render(renderer, geo.loc.to_f64(), target));
|
|
||||||
|
fn render_layer_normal<R: NiriRenderer>(
|
||||||
|
&self,
|
||||||
|
renderer: &mut R,
|
||||||
|
target: RenderTarget,
|
||||||
|
layer_map: &LayerMap,
|
||||||
|
layer: Layer,
|
||||||
|
for_backdrop: bool,
|
||||||
|
push: &mut dyn FnMut(LayerSurfaceRenderElement<R>),
|
||||||
|
) {
|
||||||
|
for (mapped, geo) in self.layers_in_render_order(layer_map, layer, for_backdrop) {
|
||||||
|
mapped.render_normal(renderer, geo.loc.to_f64(), target, push);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_layer_popups<R: NiriRenderer>(
|
||||||
|
&self,
|
||||||
|
renderer: &mut R,
|
||||||
|
target: RenderTarget,
|
||||||
|
layer_map: &LayerMap,
|
||||||
|
layer: Layer,
|
||||||
|
for_backdrop: bool,
|
||||||
|
push: &mut dyn FnMut(LayerSurfaceRenderElement<R>),
|
||||||
|
) {
|
||||||
|
for (mapped, geo) in self.layers_in_render_order(layer_map, layer, for_backdrop) {
|
||||||
|
mapped.render_popups(renderer, geo.loc.to_f64(), target, push);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5291,7 +5284,8 @@ impl Niri {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: pointer.
|
// FIXME: pointer.
|
||||||
let elements: Vec<_> = mapped.render_for_screen_cast(renderer, scale).collect();
|
let mut elements = Vec::new();
|
||||||
|
mapped.render_for_screen_cast(renderer, scale, &mut |elem| elements.push(elem));
|
||||||
|
|
||||||
if cast.dequeue_buffer_and_render(renderer, &elements, bbox.size, scale) {
|
if cast.dequeue_buffer_and_render(renderer, &elements, bbox.size, scale) {
|
||||||
cast.last_frame_time = target_presentation_time;
|
cast.last_frame_time = target_presentation_time;
|
||||||
@@ -5594,7 +5588,8 @@ impl Niri {
|
|||||||
}
|
}
|
||||||
let res_output = res.ok();
|
let res_output = res.ok();
|
||||||
|
|
||||||
let pointer = self.pointer_element(renderer, &output);
|
let mut pointer = Vec::new();
|
||||||
|
self.render_pointer(renderer, &output, &mut |elem| pointer.push(elem));
|
||||||
let res_pointer = if pointer.is_empty() {
|
let res_pointer = if pointer.is_empty() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
@@ -5685,12 +5680,14 @@ impl Niri {
|
|||||||
mapped.rules().opacity.unwrap_or(1.).clamp(0., 1.)
|
mapped.rules().opacity.unwrap_or(1.).clamp(0., 1.)
|
||||||
};
|
};
|
||||||
// FIXME: pointer.
|
// FIXME: pointer.
|
||||||
let elements = mapped.render(
|
let mut elements = Vec::new();
|
||||||
|
mapped.render(
|
||||||
renderer,
|
renderer,
|
||||||
mapped.window.geometry().loc.to_f64(),
|
mapped.window.geometry().loc.to_f64(),
|
||||||
scale,
|
scale,
|
||||||
alpha,
|
alpha,
|
||||||
RenderTarget::ScreenCapture,
|
RenderTarget::ScreenCapture,
|
||||||
|
&mut |elem| elements.push(elem),
|
||||||
);
|
);
|
||||||
let geo = encompassing_geo(scale, elements.iter());
|
let geo = encompassing_geo(scale, elements.iter());
|
||||||
let elements = elements.iter().rev().map(|elem| {
|
let elements = elements.iter().rev().map(|elem| {
|
||||||
@@ -6556,6 +6553,13 @@ fn scale_relocate_crop<E: Element>(
|
|||||||
CropRenderElement::from_element(elem, output_scale, ws_geo)
|
CropRenderElement::from_element(elem, output_scale, ws_geo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
niri_render_elements! {
|
||||||
|
PointerRenderElements<R> => {
|
||||||
|
Wayland = WaylandSurfaceRenderElement<R>,
|
||||||
|
NamedPointer = MemoryRenderBufferRenderElement<R>,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
niri_render_elements! {
|
niri_render_elements! {
|
||||||
OutputRenderElements<R> => {
|
OutputRenderElements<R> => {
|
||||||
Monitor = MonitorRenderElement<R>,
|
Monitor = MonitorRenderElement<R>,
|
||||||
@@ -6564,8 +6568,11 @@ niri_render_elements! {
|
|||||||
RelocatedLayerSurface = CropRenderElement<RelocateRenderElement<RescaleRenderElement<
|
RelocatedLayerSurface = CropRenderElement<RelocateRenderElement<RescaleRenderElement<
|
||||||
LayerSurfaceRenderElement<R>
|
LayerSurfaceRenderElement<R>
|
||||||
>>>,
|
>>>,
|
||||||
|
RelocatedColor = CropRenderElement<RelocateRenderElement<RescaleRenderElement<
|
||||||
|
SolidColorRenderElement
|
||||||
|
>>>,
|
||||||
|
Pointer = PointerRenderElements<R>,
|
||||||
Wayland = WaylandSurfaceRenderElement<R>,
|
Wayland = WaylandSurfaceRenderElement<R>,
|
||||||
NamedPointer = MemoryRenderBufferRenderElement<R>,
|
|
||||||
SolidColor = SolidColorRenderElement,
|
SolidColor = SolidColorRenderElement,
|
||||||
ScreenshotUi = ScreenshotUiRenderElement,
|
ScreenshotUi = ScreenshotUiRenderElement,
|
||||||
WindowMruUi = WindowMruUiRenderElement<R>,
|
WindowMruUi = WindowMruUiRenderElement<R>,
|
||||||
|
|||||||
@@ -58,13 +58,6 @@ pub struct BakedBuffer<B> {
|
|||||||
pub dst: Option<Size<i32, Logical>>,
|
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 {
|
pub trait ToRenderElement {
|
||||||
type RenderElement;
|
type RenderElement;
|
||||||
|
|
||||||
@@ -87,41 +80,6 @@ impl RenderTarget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn extend(&mut self, other: SplitElements<E>) {
|
|
||||||
self.popups.extend(other.popups);
|
|
||||||
self.normal.extend(other.normal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToRenderElement for BakedBuffer<TextureBuffer<GlesTexture>> {
|
impl ToRenderElement for BakedBuffer<TextureBuffer<GlesTexture>> {
|
||||||
type RenderElement = PrimaryGpuTextureRenderElement;
|
type RenderElement = PrimaryGpuTextureRenderElement;
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
|
use smithay::backend::renderer::element::surface::WaylandSurfaceRenderElement;
|
||||||
|
use smithay::backend::renderer::element::Kind;
|
||||||
use smithay::backend::renderer::gles::{GlesRenderer, GlesTexture};
|
use smithay::backend::renderer::gles::{GlesRenderer, GlesTexture};
|
||||||
use smithay::backend::renderer::utils::{import_surface, RendererSurfaceStateUserData};
|
use smithay::backend::renderer::utils::{import_surface, RendererSurfaceStateUserData};
|
||||||
use smithay::backend::renderer::Renderer as _;
|
use smithay::backend::renderer::{ImportAll, Renderer};
|
||||||
use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;
|
use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;
|
||||||
use smithay::utils::{Logical, Point};
|
use smithay::utils::{Logical, Physical, Point, Scale};
|
||||||
use smithay::wayland::compositor::{with_surface_tree_downward, TraversalAction};
|
use smithay::wayland::compositor::{with_surface_tree_downward, TraversalAction};
|
||||||
|
|
||||||
use super::texture::TextureBuffer;
|
use super::texture::TextureBuffer;
|
||||||
@@ -78,3 +80,67 @@ pub fn render_snapshot_from_surface_tree(
|
|||||||
|_, _, _| true,
|
|_, _, _| true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn push_elements_from_surface_tree<R>(
|
||||||
|
renderer: &mut R,
|
||||||
|
surface: &WlSurface,
|
||||||
|
// Fractional scale expects surface buffers to be aligned to physical pixels.
|
||||||
|
location: Point<i32, Physical>,
|
||||||
|
scale: Scale<f64>,
|
||||||
|
alpha: f32,
|
||||||
|
kind: Kind,
|
||||||
|
push: &mut dyn FnMut(WaylandSurfaceRenderElement<R>),
|
||||||
|
) where
|
||||||
|
R: Renderer + ImportAll,
|
||||||
|
R::TextureId: Clone + 'static,
|
||||||
|
{
|
||||||
|
let _span = tracy_client::span!("push_elements_from_surface_tree");
|
||||||
|
|
||||||
|
let location = location.to_f64();
|
||||||
|
|
||||||
|
with_surface_tree_downward(
|
||||||
|
surface,
|
||||||
|
location,
|
||||||
|
|_, states, location| {
|
||||||
|
let mut location = *location;
|
||||||
|
let data = states.data_map.get::<RendererSurfaceStateUserData>();
|
||||||
|
|
||||||
|
if let Some(data) = data {
|
||||||
|
if let Some(view) = data.lock().unwrap().view() {
|
||||||
|
location += view.offset.to_f64().to_physical(scale);
|
||||||
|
TraversalAction::DoChildren(location)
|
||||||
|
} else {
|
||||||
|
TraversalAction::SkipChildren
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
TraversalAction::SkipChildren
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|surface, states, location| {
|
||||||
|
let mut location = *location;
|
||||||
|
let data = states.data_map.get::<RendererSurfaceStateUserData>();
|
||||||
|
|
||||||
|
if let Some(data) = data {
|
||||||
|
let has_view = if let Some(view) = data.lock().unwrap().view() {
|
||||||
|
location += view.offset.to_f64().to_physical(scale);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
if has_view {
|
||||||
|
match WaylandSurfaceRenderElement::from_surface(
|
||||||
|
renderer, surface, states, location, alpha, kind,
|
||||||
|
) {
|
||||||
|
Ok(Some(surface)) => push(surface),
|
||||||
|
Ok(None) => {} // surface is not mapped
|
||||||
|
Err(err) => {
|
||||||
|
warn!("failed to import surface: {}", err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|_, _, _| true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ use std::collections::HashMap;
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
use arrayvec::ArrayVec;
|
|
||||||
use niri_config::Config;
|
use niri_config::Config;
|
||||||
use ordered_float::NotNan;
|
use ordered_float::NotNan;
|
||||||
use pangocairo::cairo::{self, ImageSurface};
|
use pangocairo::cairo::{self, ImageSurface};
|
||||||
@@ -151,14 +150,15 @@ impl ExitConfirmDialog {
|
|||||||
&self,
|
&self,
|
||||||
renderer: &mut R,
|
renderer: &mut R,
|
||||||
output: &Output,
|
output: &Output,
|
||||||
) -> ArrayVec<ExitConfirmDialogRenderElement, 2> {
|
push: &mut dyn FnMut(ExitConfirmDialogRenderElement),
|
||||||
let mut rv = ArrayVec::new();
|
) {
|
||||||
|
|
||||||
let (value, clamped_value) = match &self.state {
|
let (value, clamped_value) = match &self.state {
|
||||||
State::Hidden => return rv,
|
State::Hidden => return,
|
||||||
State::Showing(anim) | State::Hiding(anim) => (anim.value(), anim.clamped_value()),
|
State::Showing(anim) | State::Hiding(anim) => (anim.value(), anim.clamped_value()),
|
||||||
State::Visible => (1., 1.),
|
State::Visible => (1., 1.),
|
||||||
};
|
};
|
||||||
|
let _span = tracy_client::span!("ExitConfirmDialog::render");
|
||||||
|
|
||||||
// Can be out of range when starting from past 0. or 1. from a spring bounce.
|
// Can be out of range when starting from past 0. or 1. from a spring bounce.
|
||||||
let clamped_value = clamped_value.clamp(0., 1.);
|
let clamped_value = clamped_value.clamp(0., 1.);
|
||||||
|
|
||||||
@@ -168,7 +168,7 @@ impl ExitConfirmDialog {
|
|||||||
let mut buffers = self.buffers.borrow_mut();
|
let mut buffers = self.buffers.borrow_mut();
|
||||||
let Some(fallback) = buffers[&NotNan::new(1.).unwrap()].clone() else {
|
let Some(fallback) = buffers[&NotNan::new(1.).unwrap()].clone() else {
|
||||||
error!("exit confirm dialog opened without fallback buffer");
|
error!("exit confirm dialog opened without fallback buffer");
|
||||||
return rv;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let buffer = buffers
|
let buffer = buffers
|
||||||
@@ -179,7 +179,7 @@ impl ExitConfirmDialog {
|
|||||||
let size = buffer.logical_size();
|
let size = buffer.logical_size();
|
||||||
let Ok(buffer) = TextureBuffer::from_memory_buffer(renderer.as_gles_renderer(), buffer)
|
let Ok(buffer) = TextureBuffer::from_memory_buffer(renderer.as_gles_renderer(), buffer)
|
||||||
else {
|
else {
|
||||||
return rv;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let location = (output_size.to_point() - size.to_point()).downscale(2.);
|
let location = (output_size.to_point() - size.to_point()).downscale(2.);
|
||||||
@@ -201,7 +201,7 @@ impl ExitConfirmDialog {
|
|||||||
(location + size.downscale(2.)).to_physical_precise_round(scale),
|
(location + size.downscale(2.)).to_physical_precise_round(scale),
|
||||||
value.max(0.) * 0.2 + 0.8,
|
value.max(0.) * 0.2 + 0.8,
|
||||||
);
|
);
|
||||||
rv.push(ExitConfirmDialogRenderElement::Texture(elem));
|
push(ExitConfirmDialogRenderElement::Texture(elem));
|
||||||
|
|
||||||
// Backdrop.
|
// Backdrop.
|
||||||
let data = output.user_data().get_or_insert(|| {
|
let data = output.user_data().get_or_insert(|| {
|
||||||
@@ -218,9 +218,7 @@ impl ExitConfirmDialog {
|
|||||||
clamped_value as f32,
|
clamped_value as f32,
|
||||||
Kind::Unspecified,
|
Kind::Unspecified,
|
||||||
);
|
);
|
||||||
rv.push(ExitConfirmDialogRenderElement::SolidColor(elem));
|
push(ExitConfirmDialogRenderElement::SolidColor(elem));
|
||||||
|
|
||||||
rv
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+68
-77
@@ -346,7 +346,8 @@ impl Thumbnail {
|
|||||||
is_active: bool,
|
is_active: bool,
|
||||||
bob_y: f64,
|
bob_y: f64,
|
||||||
target: RenderTarget,
|
target: RenderTarget,
|
||||||
) -> impl Iterator<Item = WindowMruUiRenderElement<R>> {
|
push: &mut dyn FnMut(WindowMruUiRenderElement<R>),
|
||||||
|
) {
|
||||||
let _span = tracy_client::span!("Thumbnail::render");
|
let _span = tracy_client::span!("Thumbnail::render");
|
||||||
|
|
||||||
let round = move |logical: f64| round_logical_in_physical(scale, logical);
|
let round = move |logical: f64| round_logical_in_physical(scale, logical);
|
||||||
@@ -368,11 +369,6 @@ impl Thumbnail {
|
|||||||
};
|
};
|
||||||
let bob_offset = Point::new(0., bob_y);
|
let bob_offset = Point::new(0., bob_y);
|
||||||
|
|
||||||
// FIXME: this could use mipmaps, for that it should be rendered through an offscreen.
|
|
||||||
let elems = mapped
|
|
||||||
.render_normal(renderer, Point::new(0., 0.), s, preview_alpha, target)
|
|
||||||
.into_iter();
|
|
||||||
|
|
||||||
// Clip thumbnails to their geometry.
|
// Clip thumbnails to their geometry.
|
||||||
let radius = if mapped.sizing_mode().is_normal() {
|
let radius = if mapped.sizing_mode().is_normal() {
|
||||||
mapped.rules().geometry_corner_radius
|
mapped.rules().geometry_corner_radius
|
||||||
@@ -385,7 +381,7 @@ impl Thumbnail {
|
|||||||
let clip_shader = ClippedSurfaceRenderElement::shader(renderer).cloned();
|
let clip_shader = ClippedSurfaceRenderElement::shader(renderer).cloned();
|
||||||
let geo = Rectangle::from_size(self.size.to_f64());
|
let geo = Rectangle::from_size(self.size.to_f64());
|
||||||
// FIXME: deduplicate code with Tile::render_inner()
|
// FIXME: deduplicate code with Tile::render_inner()
|
||||||
let elems = elems.map(move |elem| match elem {
|
let clip = move |elem| match elem {
|
||||||
LayoutElementRenderElement::Wayland(elem) => {
|
LayoutElementRenderElement::Wayland(elem) => {
|
||||||
if let Some(shader) = clip_shader.clone() {
|
if let Some(shader) = clip_shader.clone() {
|
||||||
if ClippedSurfaceRenderElement::will_clip(&elem, s, geo, radius) {
|
if ClippedSurfaceRenderElement::will_clip(&elem, s, geo, radius) {
|
||||||
@@ -426,9 +422,9 @@ impl Thumbnail {
|
|||||||
// Otherwise, render the solid color as is.
|
// Otherwise, render the solid color as is.
|
||||||
LayoutElementRenderElement::SolidColor(elem).into()
|
LayoutElementRenderElement::SolidColor(elem).into()
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
let elems = elems.map(move |elem| {
|
let downscale = move |elem| {
|
||||||
let thumb_scale = Scale {
|
let thumb_scale = Scale {
|
||||||
x: preview_geo.size.w / geo.size.w,
|
x: preview_geo.size.w / geo.size.w,
|
||||||
y: preview_geo.size.h / geo.size.h,
|
y: preview_geo.size.h / geo.size.h,
|
||||||
@@ -445,7 +441,21 @@ impl Thumbnail {
|
|||||||
Relocate::Relative,
|
Relocate::Relative,
|
||||||
);
|
);
|
||||||
WindowMruUiRenderElement::Thumbnail(elem)
|
WindowMruUiRenderElement::Thumbnail(elem)
|
||||||
});
|
};
|
||||||
|
|
||||||
|
// FIXME: this could use mipmaps, for that it should be rendered through an offscreen.
|
||||||
|
mapped.render_normal(
|
||||||
|
renderer,
|
||||||
|
Point::new(0., 0.),
|
||||||
|
s,
|
||||||
|
preview_alpha,
|
||||||
|
target,
|
||||||
|
&mut |elem| {
|
||||||
|
let elem = clip(elem);
|
||||||
|
let elem = downscale(elem);
|
||||||
|
push(elem)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
let mut title_size = None;
|
let mut title_size = None;
|
||||||
let title_texture = self.title_texture(renderer.as_gles_renderer(), mapped, scale);
|
let title_texture = self.title_texture(renderer.as_gles_renderer(), mapped, scale);
|
||||||
@@ -462,7 +472,7 @@ impl Thumbnail {
|
|||||||
let should_block_out = target.should_block_out(mapped.rules().block_out_from);
|
let should_block_out = target.should_block_out(mapped.rules().block_out_from);
|
||||||
let title_texture = title_texture.filter(|_| !should_block_out);
|
let title_texture = title_texture.filter(|_| !should_block_out);
|
||||||
|
|
||||||
let title_elems = title_texture.map(|(texture, size)| {
|
if let Some((texture, size)) = title_texture {
|
||||||
// Clip from the right if it doesn't fit.
|
// Clip from the right if it doesn't fit.
|
||||||
let src = Rectangle::from_size(size);
|
let src = Rectangle::from_size(size);
|
||||||
|
|
||||||
@@ -484,15 +494,15 @@ impl Thumbnail {
|
|||||||
let renderer = renderer.as_gles_renderer();
|
let renderer = renderer.as_gles_renderer();
|
||||||
if let Some(program) = GradientFadeTextureRenderElement::shader(renderer) {
|
if let Some(program) = GradientFadeTextureRenderElement::shader(renderer) {
|
||||||
let elem = GradientFadeTextureRenderElement::new(texture, program);
|
let elem = GradientFadeTextureRenderElement::new(texture, program);
|
||||||
WindowMruUiRenderElement::GradientFadeElem(elem)
|
push(WindowMruUiRenderElement::GradientFadeElem(elem));
|
||||||
} else {
|
} else {
|
||||||
let elem = PrimaryGpuTextureRenderElement(texture);
|
let elem = PrimaryGpuTextureRenderElement(texture);
|
||||||
WindowMruUiRenderElement::TextureElement(elem)
|
push(WindowMruUiRenderElement::TextureElement(elem));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
let is_urgent = mapped.is_urgent();
|
let is_urgent = mapped.is_urgent();
|
||||||
let background_elems = (is_active || is_urgent).then(|| {
|
if is_active || is_urgent {
|
||||||
let padding = Point::new(padding, padding);
|
let padding = Point::new(padding, padding);
|
||||||
|
|
||||||
let mut size = preview_geo.size;
|
let mut size = preview_geo.size;
|
||||||
@@ -532,9 +542,9 @@ impl Thumbnail {
|
|||||||
scale,
|
scale,
|
||||||
0.5,
|
0.5,
|
||||||
);
|
);
|
||||||
let bg_elems = background
|
background.render(renderer, loc, &mut |elem| {
|
||||||
.render(renderer, loc)
|
push(WindowMruUiRenderElement::FocusRing(elem))
|
||||||
.map(WindowMruUiRenderElement::FocusRing);
|
});
|
||||||
|
|
||||||
let mut border = self.border.borrow_mut();
|
let mut border = self.border.borrow_mut();
|
||||||
let mut config = *border.config();
|
let mut config = *border.config();
|
||||||
@@ -554,15 +564,10 @@ impl Thumbnail {
|
|||||||
1.,
|
1.,
|
||||||
);
|
);
|
||||||
|
|
||||||
let border_elems = border
|
border.render(renderer, loc, &mut |elem| {
|
||||||
.render(renderer, loc)
|
push(WindowMruUiRenderElement::FocusRing(elem))
|
||||||
.map(WindowMruUiRenderElement::FocusRing);
|
|
||||||
|
|
||||||
bg_elems.chain(border_elems)
|
|
||||||
});
|
});
|
||||||
let background_elems = background_elems.into_iter().flatten();
|
}
|
||||||
|
|
||||||
elems.chain(title_elems).chain(background_elems)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1091,26 +1096,27 @@ impl WindowMruUi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_output<'a, R: NiriRenderer>(
|
pub fn render_output<R: NiriRenderer>(
|
||||||
&'a self,
|
&self,
|
||||||
niri: &'a Niri,
|
niri: &Niri,
|
||||||
output: &Output,
|
output: &Output,
|
||||||
renderer: &'a mut R,
|
renderer: &mut R,
|
||||||
target: RenderTarget,
|
target: RenderTarget,
|
||||||
) -> Option<impl Iterator<Item = WindowMruUiRenderElement<R>> + 'a> {
|
push: &mut dyn FnMut(WindowMruUiRenderElement<R>),
|
||||||
|
) {
|
||||||
let (inner, progress) = match &self.state {
|
let (inner, progress) = match &self.state {
|
||||||
UiState::Closed { .. } => return None,
|
UiState::Closed { .. } => return,
|
||||||
UiState::Closing { inner, anim } => (inner, anim.clamped_value()),
|
UiState::Closing { inner, anim } => (inner, anim.clamped_value()),
|
||||||
UiState::Open(inner) => {
|
UiState::Open(inner) => {
|
||||||
if inner.is_fully_open() {
|
if inner.is_fully_open() {
|
||||||
(inner, 1.)
|
(inner, 1.)
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let span = tracy_client::span!("mru render");
|
let _span = tracy_client::span!("WindowMruUi::render_output");
|
||||||
|
|
||||||
let alpha = progress.clamp(0., 1.) as f32;
|
let alpha = progress.clamp(0., 1.) as f32;
|
||||||
|
|
||||||
@@ -1131,9 +1137,12 @@ impl WindowMruUi {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// During the closing fade, use an offscreen to avoid transparent compositing artifacts.
|
// During the closing fade, use an offscreen to avoid transparent compositing artifacts.
|
||||||
let offscreen_elem = if *output == inner.output && alpha < 1. {
|
let mut pushed_offscreen = false;
|
||||||
|
if *output == inner.output && alpha < 1. {
|
||||||
let renderer = renderer.as_gles_renderer();
|
let renderer = renderer.as_gles_renderer();
|
||||||
let mut elems = Vec::from_iter(inner.render(niri, renderer, target));
|
|
||||||
|
let mut elems = Vec::new();
|
||||||
|
inner.render(niri, renderer, target, &mut |elem| elems.push(elem));
|
||||||
elems.push(WindowMruUiRenderElement::SolidColor(render_backdrop(1.)));
|
elems.push(WindowMruUiRenderElement::SolidColor(render_backdrop(1.)));
|
||||||
|
|
||||||
let scale = output.current_scale().fractional_scale();
|
let scale = output.current_scale().fractional_scale();
|
||||||
@@ -1149,39 +1158,27 @@ impl WindowMruUi {
|
|||||||
// itself).
|
// itself).
|
||||||
//
|
//
|
||||||
// Anyhow, this is not very noticeable since Alt-Tab closing happens quickly.
|
// Anyhow, this is not very noticeable since Alt-Tab closing happens quickly.
|
||||||
Some(WindowMruUiRenderElement::Offscreen(elem.with_alpha(alpha)))
|
push(WindowMruUiRenderElement::Offscreen(elem.with_alpha(alpha)));
|
||||||
|
pushed_offscreen = true;
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!("error rendering MRU to offscreen for fade-out: {err:?}");
|
warn!("error rendering MRU to offscreen for fade-out: {err:?}");
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
// When alpha is 1., render everything directly, without an offscreen.
|
// When alpha is 1., render everything directly, without an offscreen.
|
||||||
//
|
//
|
||||||
// This is not used as fallback when offscreen fails to render because it looks better to
|
// This is not used as fallback when offscreen fails to render because it looks better to
|
||||||
// hide the previews immediately than to render them with alpha = 1. during a fade-out.
|
// hide the previews immediately than to render them with alpha = 1. during a fade-out.
|
||||||
let normal_elems =
|
if *output == inner.output && alpha == 1. {
|
||||||
(*output == inner.output && alpha == 1.).then(|| inner.render(niri, renderer, target));
|
inner.render(niri, renderer, target, &mut |elem| push(elem));
|
||||||
let normal_elems = normal_elems.into_iter().flatten();
|
}
|
||||||
|
|
||||||
// This is used for both normal elems and for other outputs.
|
// This is used for both normal elems and for other outputs.
|
||||||
let backdrop_elem = (offscreen_elem.is_none())
|
if !pushed_offscreen {
|
||||||
.then(|| WindowMruUiRenderElement::SolidColor(render_backdrop(alpha)));
|
push(WindowMruUiRenderElement::SolidColor(render_backdrop(alpha)));
|
||||||
|
}
|
||||||
// Make sure the span includes consuming the iterator.
|
|
||||||
let drop_span = std::iter::once(span).filter_map(|_| None);
|
|
||||||
|
|
||||||
Some(
|
|
||||||
offscreen_elem
|
|
||||||
.into_iter()
|
|
||||||
.chain(normal_elems)
|
|
||||||
.chain(backdrop_elem)
|
|
||||||
.chain(drop_span),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn are_animations_ongoing(&self) -> bool {
|
pub fn are_animations_ongoing(&self) -> bool {
|
||||||
@@ -1554,12 +1551,13 @@ impl Inner {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render<'a, R: NiriRenderer>(
|
fn render<R: NiriRenderer>(
|
||||||
&'a self,
|
&self,
|
||||||
niri: &'a Niri,
|
niri: &Niri,
|
||||||
renderer: &'a mut R,
|
renderer: &mut R,
|
||||||
target: RenderTarget,
|
target: RenderTarget,
|
||||||
) -> impl Iterator<Item = WindowMruUiRenderElement<R>> + 'a {
|
push: &mut dyn FnMut(WindowMruUiRenderElement<R>),
|
||||||
|
) {
|
||||||
let output_size = output_size(&self.output);
|
let output_size = output_size(&self.output);
|
||||||
let scale = self.output.current_scale().fractional_scale();
|
let scale = self.output.current_scale().fractional_scale();
|
||||||
|
|
||||||
@@ -1567,7 +1565,7 @@ impl Inner {
|
|||||||
self.scope_panel
|
self.scope_panel
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.get(renderer.as_gles_renderer(), scale, self.wmru.scope);
|
.get(renderer.as_gles_renderer(), scale, self.wmru.scope);
|
||||||
let panel = panel_texture.map(move |texture| {
|
if let Some(texture) = panel_texture {
|
||||||
let padding = round_logical_in_physical(scale, f64::from(PANEL_PADDING));
|
let padding = round_logical_in_physical(scale, f64::from(PANEL_PADDING));
|
||||||
|
|
||||||
let size = texture.logical_size();
|
let size = texture.logical_size();
|
||||||
@@ -1580,9 +1578,8 @@ impl Inner {
|
|||||||
None,
|
None,
|
||||||
Kind::Unspecified,
|
Kind::Unspecified,
|
||||||
));
|
));
|
||||||
WindowMruUiRenderElement::TextureElement(elem)
|
push(WindowMruUiRenderElement::TextureElement(elem));
|
||||||
});
|
}
|
||||||
let panel = panel.into_iter();
|
|
||||||
|
|
||||||
let current_id = self.wmru.current_id;
|
let current_id = self.wmru.current_id;
|
||||||
|
|
||||||
@@ -1591,26 +1588,20 @@ impl Inner {
|
|||||||
|
|
||||||
let config = self.config.borrow();
|
let config = self.config.borrow();
|
||||||
|
|
||||||
let thumbnails = self
|
for (thumbnail, geo) in self.thumbnails_in_view_render() {
|
||||||
.thumbnails_in_view_render()
|
|
||||||
.filter_map(move |(thumbnail, geo)| {
|
|
||||||
let id = thumbnail.id;
|
let id = thumbnail.id;
|
||||||
let Some((_, mapped)) = niri.layout.windows().find(|(_, m)| m.id() == id) else {
|
let Some((_, mapped)) = niri.layout.windows().find(|(_, m)| m.id() == id) else {
|
||||||
error!("window in the MRU must be present in the layout");
|
error!("window in the MRU must be present in the layout");
|
||||||
return None;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
let config = &config.recent_windows;
|
let config = &config.recent_windows;
|
||||||
|
|
||||||
let is_active = Some(id) == current_id;
|
let is_active = Some(id) == current_id;
|
||||||
let elems = thumbnail.render(
|
thumbnail.render(
|
||||||
renderer, config, mapped, geo, scale, is_active, bob_y, target,
|
renderer, config, mapped, geo, scale, is_active, bob_y, target, push,
|
||||||
);
|
);
|
||||||
Some(elems)
|
}
|
||||||
});
|
|
||||||
let thumbnails = thumbnails.flatten();
|
|
||||||
|
|
||||||
panel.chain(thumbnails)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn thumbnail_under(&self, pos: Point<f64, Logical>) -> Option<MappedId> {
|
fn thumbnail_under(&self, pos: Point<f64, Logical>) -> Option<MappedId> {
|
||||||
|
|||||||
+11
-15
@@ -623,7 +623,8 @@ impl ScreenshotUi {
|
|||||||
&self,
|
&self,
|
||||||
output: &Output,
|
output: &Output,
|
||||||
target: RenderTarget,
|
target: RenderTarget,
|
||||||
) -> ArrayVec<ScreenshotUiRenderElement, 11> {
|
push: &mut dyn FnMut(ScreenshotUiRenderElement),
|
||||||
|
) {
|
||||||
let _span = tracy_client::span!("ScreenshotUi::render_output");
|
let _span = tracy_client::span!("ScreenshotUi::render_output");
|
||||||
|
|
||||||
let Self::Open {
|
let Self::Open {
|
||||||
@@ -637,10 +638,8 @@ impl ScreenshotUi {
|
|||||||
panic!("screenshot UI must be open to render it");
|
panic!("screenshot UI must be open to render it");
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut elements = ArrayVec::new();
|
|
||||||
|
|
||||||
let Some(output_data) = output_data.get(output) else {
|
let Some(output_data) = output_data.get(output) else {
|
||||||
return elements;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let scale = output_data.scale;
|
let scale = output_data.scale;
|
||||||
@@ -666,19 +665,18 @@ impl ScreenshotUi {
|
|||||||
None,
|
None,
|
||||||
Kind::Unspecified,
|
Kind::Unspecified,
|
||||||
));
|
));
|
||||||
elements.push(elem.into());
|
push(elem.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let buf_loc = zip(&output_data.buffers, &output_data.locations);
|
for (buffer, loc) in zip(&output_data.buffers, &output_data.locations) {
|
||||||
elements.extend(buf_loc.map(|(buffer, loc)| {
|
let elem = SolidColorRenderElement::from_buffer(
|
||||||
SolidColorRenderElement::from_buffer(
|
|
||||||
buffer,
|
buffer,
|
||||||
loc.to_f64().to_logical(scale),
|
loc.to_f64().to_logical(scale),
|
||||||
progress,
|
progress,
|
||||||
Kind::Unspecified,
|
Kind::Unspecified,
|
||||||
)
|
);
|
||||||
.into()
|
push(elem.into());
|
||||||
}));
|
}
|
||||||
|
|
||||||
// The screenshot itself goes last.
|
// The screenshot itself goes last.
|
||||||
let index = match target {
|
let index = match target {
|
||||||
@@ -690,12 +688,10 @@ impl ScreenshotUi {
|
|||||||
|
|
||||||
if *show_pointer {
|
if *show_pointer {
|
||||||
if let Some(pointer) = screenshot.pointer.clone() {
|
if let Some(pointer) = screenshot.pointer.clone() {
|
||||||
elements.push(pointer.into());
|
push(pointer.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elements.push(screenshot.buffer.clone().into());
|
push(screenshot.buffer.clone().into());
|
||||||
|
|
||||||
elements
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn capture(
|
pub fn capture(
|
||||||
|
|||||||
+32
-66
@@ -2,7 +2,7 @@ use std::cell::{Cell, Ref, RefCell};
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use niri_config::{Color, CornerRadius, GradientInterpolation, WindowRule};
|
use niri_config::{Color, CornerRadius, GradientInterpolation, WindowRule};
|
||||||
use smithay::backend::renderer::element::surface::render_elements_from_surface_tree;
|
use smithay::backend::renderer::element::surface::WaylandSurfaceRenderElement;
|
||||||
use smithay::backend::renderer::element::Kind;
|
use smithay::backend::renderer::element::Kind;
|
||||||
use smithay::backend::renderer::gles::GlesRenderer;
|
use smithay::backend::renderer::gles::GlesRenderer;
|
||||||
use smithay::desktop::space::SpaceElement as _;
|
use smithay::desktop::space::SpaceElement as _;
|
||||||
@@ -33,8 +33,10 @@ use crate::render_helpers::offscreen::OffscreenData;
|
|||||||
use crate::render_helpers::renderer::NiriRenderer;
|
use crate::render_helpers::renderer::NiriRenderer;
|
||||||
use crate::render_helpers::snapshot::RenderSnapshot;
|
use crate::render_helpers::snapshot::RenderSnapshot;
|
||||||
use crate::render_helpers::solid_color::{SolidColorBuffer, SolidColorRenderElement};
|
use crate::render_helpers::solid_color::{SolidColorBuffer, SolidColorRenderElement};
|
||||||
use crate::render_helpers::surface::render_snapshot_from_surface_tree;
|
use crate::render_helpers::surface::{
|
||||||
use crate::render_helpers::{BakedBuffer, RenderTarget, SplitElements};
|
push_elements_from_surface_tree, render_snapshot_from_surface_tree,
|
||||||
|
};
|
||||||
|
use crate::render_helpers::{BakedBuffer, RenderTarget};
|
||||||
use crate::utils::id::IdCounter;
|
use crate::utils::id::IdCounter;
|
||||||
use crate::utils::transaction::Transaction;
|
use crate::utils::transaction::Transaction;
|
||||||
use crate::utils::{
|
use crate::utils::{
|
||||||
@@ -472,7 +474,8 @@ impl Mapped {
|
|||||||
&self,
|
&self,
|
||||||
renderer: &mut R,
|
renderer: &mut R,
|
||||||
scale: Scale<f64>,
|
scale: Scale<f64>,
|
||||||
) -> impl DoubleEndedIterator<Item = WindowCastRenderElements<R>> {
|
push: &mut dyn FnMut(WindowCastRenderElements<R>),
|
||||||
|
) {
|
||||||
let bbox = self.window.bbox_with_popups().to_physical_precise_up(scale);
|
let bbox = self.window.bbox_with_popups().to_physical_precise_up(scale);
|
||||||
|
|
||||||
let has_border_shader = BorderRenderElement::has_shader(renderer);
|
let has_border_shader = BorderRenderElement::has_shader(renderer);
|
||||||
@@ -484,11 +487,9 @@ impl Mapped {
|
|||||||
.to_physical_precise_round(scale)
|
.to_physical_precise_round(scale)
|
||||||
.to_logical(scale);
|
.to_logical(scale);
|
||||||
let radius = radius.fit_to(window_size.w as f32, window_size.h as f32);
|
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 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| {
|
let use_border = |elem| {
|
||||||
if let LayoutElementRenderElement::SolidColor(elem) = &elem {
|
if let LayoutElementRenderElement::SolidColor(elem) = &elem {
|
||||||
// In this branch we're rendering a blocked-out window with a solid color. We need
|
// 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,
|
// to render it with a rounded corner shader even if clip_to_geometry is false,
|
||||||
@@ -516,7 +517,16 @@ impl Mapped {
|
|||||||
}
|
}
|
||||||
|
|
||||||
WindowCastRenderElements::from(elem)
|
WindowCastRenderElements::from(elem)
|
||||||
})
|
};
|
||||||
|
|
||||||
|
self.render(
|
||||||
|
renderer,
|
||||||
|
location,
|
||||||
|
scale,
|
||||||
|
1.,
|
||||||
|
RenderTarget::Screencast,
|
||||||
|
&mut |elem| push(use_border(elem)),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_focus_timestamp(&self) -> Option<Duration> {
|
pub fn get_focus_timestamp(&self) -> Option<Duration> {
|
||||||
@@ -601,52 +611,6 @@ impl LayoutElement for Mapped {
|
|||||||
self.window.is_in_input_region(&surface_local)
|
self.window.is_in_input_region(&surface_local)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render<R: NiriRenderer>(
|
|
||||||
&self,
|
|
||||||
renderer: &mut R,
|
|
||||||
location: Point<f64, Logical>,
|
|
||||||
scale: Scale<f64>,
|
|
||||||
alpha: f32,
|
|
||||||
target: RenderTarget,
|
|
||||||
) -> SplitElements<LayoutElementRenderElement<R>> {
|
|
||||||
let mut rv = SplitElements::default();
|
|
||||||
|
|
||||||
if target.should_block_out(self.rules.block_out_from) {
|
|
||||||
let mut buffer = self.block_out_buffer.borrow_mut();
|
|
||||||
buffer.resize(self.window.geometry().size.to_f64());
|
|
||||||
let elem =
|
|
||||||
SolidColorRenderElement::from_buffer(&buffer, location, alpha, Kind::Unspecified);
|
|
||||||
rv.normal.push(elem.into());
|
|
||||||
} else {
|
|
||||||
let buf_pos = location - self.window.geometry().loc.to_f64();
|
|
||||||
|
|
||||||
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_f64()).to_physical_precise_round(scale),
|
|
||||||
scale,
|
|
||||||
alpha,
|
|
||||||
Kind::ScanoutCandidate,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
rv.normal = render_elements_from_surface_tree(
|
|
||||||
renderer,
|
|
||||||
surface,
|
|
||||||
buf_pos.to_physical_precise_round(scale),
|
|
||||||
scale,
|
|
||||||
alpha,
|
|
||||||
Kind::ScanoutCandidate,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
rv
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_normal<R: NiriRenderer>(
|
fn render_normal<R: NiriRenderer>(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut R,
|
renderer: &mut R,
|
||||||
@@ -654,23 +618,26 @@ impl LayoutElement for Mapped {
|
|||||||
scale: Scale<f64>,
|
scale: Scale<f64>,
|
||||||
alpha: f32,
|
alpha: f32,
|
||||||
target: RenderTarget,
|
target: RenderTarget,
|
||||||
) -> Vec<LayoutElementRenderElement<R>> {
|
push: &mut dyn FnMut(LayoutElementRenderElement<R>),
|
||||||
|
) {
|
||||||
if target.should_block_out(self.rules.block_out_from) {
|
if target.should_block_out(self.rules.block_out_from) {
|
||||||
let mut buffer = self.block_out_buffer.borrow_mut();
|
let mut buffer = self.block_out_buffer.borrow_mut();
|
||||||
buffer.resize(self.window.geometry().size.to_f64());
|
buffer.resize(self.window.geometry().size.to_f64());
|
||||||
let elem =
|
let elem =
|
||||||
SolidColorRenderElement::from_buffer(&buffer, location, alpha, Kind::Unspecified);
|
SolidColorRenderElement::from_buffer(&buffer, location, alpha, Kind::Unspecified);
|
||||||
vec![elem.into()]
|
push(elem.into());
|
||||||
} else {
|
} else {
|
||||||
let buf_pos = location - self.window.geometry().loc.to_f64();
|
let buf_pos = location - self.window.geometry().loc.to_f64();
|
||||||
let surface = self.toplevel().wl_surface();
|
let surface = self.toplevel().wl_surface();
|
||||||
render_elements_from_surface_tree(
|
let mut push = |elem: WaylandSurfaceRenderElement<R>| push(elem.into());
|
||||||
|
push_elements_from_surface_tree(
|
||||||
renderer,
|
renderer,
|
||||||
surface,
|
surface,
|
||||||
buf_pos.to_physical_precise_round(scale),
|
buf_pos.to_physical_precise_round(scale),
|
||||||
scale,
|
scale,
|
||||||
alpha,
|
alpha,
|
||||||
Kind::ScanoutCandidate,
|
Kind::ScanoutCandidate,
|
||||||
|
&mut push,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -682,28 +649,27 @@ impl LayoutElement for Mapped {
|
|||||||
scale: Scale<f64>,
|
scale: Scale<f64>,
|
||||||
alpha: f32,
|
alpha: f32,
|
||||||
target: RenderTarget,
|
target: RenderTarget,
|
||||||
) -> Vec<LayoutElementRenderElement<R>> {
|
push: &mut dyn FnMut(LayoutElementRenderElement<R>),
|
||||||
|
) {
|
||||||
if target.should_block_out(self.rules.block_out_from) {
|
if target.should_block_out(self.rules.block_out_from) {
|
||||||
vec![]
|
return;
|
||||||
} else {
|
}
|
||||||
let mut rv = vec![];
|
|
||||||
|
|
||||||
let buf_pos = location - self.window.geometry().loc.to_f64();
|
let buf_pos = location - self.window.geometry().loc.to_f64();
|
||||||
let surface = self.toplevel().wl_surface();
|
let surface = self.toplevel().wl_surface();
|
||||||
|
let mut push = |elem: WaylandSurfaceRenderElement<R>| push(elem.into());
|
||||||
for (popup, popup_offset) in PopupManager::popups_for_surface(surface) {
|
for (popup, popup_offset) in PopupManager::popups_for_surface(surface) {
|
||||||
let offset = self.window.geometry().loc + popup_offset - popup.geometry().loc;
|
let offset = self.window.geometry().loc + popup_offset - popup.geometry().loc;
|
||||||
|
|
||||||
rv.extend(render_elements_from_surface_tree(
|
push_elements_from_surface_tree(
|
||||||
renderer,
|
renderer,
|
||||||
popup.wl_surface(),
|
popup.wl_surface(),
|
||||||
(buf_pos + offset.to_f64()).to_physical_precise_round(scale),
|
(buf_pos + offset.to_f64()).to_physical_precise_round(scale),
|
||||||
scale,
|
scale,
|
||||||
alpha,
|
alpha,
|
||||||
Kind::ScanoutCandidate,
|
Kind::ScanoutCandidate,
|
||||||
));
|
&mut push,
|
||||||
}
|
);
|
||||||
|
|
||||||
rv
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user