cosmic-comp/src/backend/render/wayland/mod.rs
2026-07-09 18:08:01 +02:00

111 lines
3.7 KiB
Rust

use smithay::{
backend::renderer::{
ImportAll, Renderer,
element::surface::{KindEvaluation, WaylandSurfaceRenderElement},
utils::RendererSurfaceStateUserData,
},
reexports::wayland_server::protocol::wl_surface,
render_elements,
utils::{Logical, Physical, Point, Rectangle, Scale},
wayland::compositor::{self, TraversalAction},
};
use tracing::warn;
use crate::backend::render::{
element::AsGlowRenderer, wayland::clipped_surface::ClippedSurfaceRenderElement,
};
pub mod clipped_surface;
render_elements! {
pub SurfaceRenderElement<R> where R: AsGlowRenderer + ImportAll;
Clipped=ClippedSurfaceRenderElement<R>,
Wayland=WaylandSurfaceRenderElement<R>,
}
pub fn render_elements_from_surface_tree<R, E>(
renderer: &mut R,
main_surface: &wl_surface::WlSurface,
location: impl Into<Point<i32, Physical>>,
geometry: impl Into<Rectangle<f64, Logical>>,
scale: impl Into<Scale<f64>>,
alpha: f32,
should_clip: bool,
radii: [u8; 4],
kind: impl Into<KindEvaluation>,
) -> Vec<E>
where
R: Renderer + ImportAll + AsGlowRenderer,
R::TextureId: Clone + 'static,
E: From<SurfaceRenderElement<R>>,
{
let location = location.into().to_f64();
let geometry = geometry.into().to_f64();
let scale = scale.into();
let kind = kind.into();
let mut surfaces: Vec<E> = Vec::new();
compositor::with_surface_tree_downward(
main_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 kind = kind.eval(states);
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)) => {
let elem: SurfaceRenderElement<R> = if radii.iter().any(|r| *r != 0)
&& should_clip
&& ClippedSurfaceRenderElement::will_clip(
&surface, scale, geometry, radii,
) {
ClippedSurfaceRenderElement::new(
renderer, surface, scale, geometry, radii,
)
.into()
} else {
surface.into()
};
surfaces.push(elem.into());
}
Ok(None) => {} // surface is not mapped
Err(err) => {
warn!("Failed to import surface: {}", err);
}
};
}
}
},
|_, _, _| true,
);
surfaces
}