🔒 Repository is read-only – file editing is disabled.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
use smithay::{
backend::renderer::{
damage::{Error as OutputDamageTrackerError, OutputDamageTracker, RenderOutputResult},
element::{
surface::WaylandSurfaceRenderElement,
utils::{
ConstrainAlign, ConstrainScaleBehavior, CropRenderElement, RelocateRenderElement,
RescaleRenderElement,
},
AsRenderElements, RenderElement, Wrap,
},
Color32F, ImportAll, ImportMem, Renderer,
},
desktop::space::{
constrain_space_element, ConstrainBehavior, ConstrainReference, Space, SpaceRenderElements,
},
output::Output,
utils::{Point, Rectangle, Size},
};
#[cfg(feature = "debug")]
use crate::drawing::FpsElement;
use crate::{
drawing::{PointerRenderElement, CLEAR_COLOR, CLEAR_COLOR_FULLSCREEN},
shell::{FullscreenSurface, WindowElement, WindowRenderElement},
};
smithay::backend::renderer::element::render_elements! {
pub CustomRenderElements<R> where
R: ImportAll + ImportMem;
Pointer=PointerRenderElement<R>,
Surface=WaylandSurfaceRenderElement<R>,
#[cfg(feature = "debug")]
// Note: We would like to borrow this element instead, but that would introduce
// a feature-dependent lifetime, which introduces a lot more feature bounds
// as the whole type changes and we can't have an unused lifetime (for when "debug" is disabled)
// in the declaration.
Fps=FpsElement<R::TextureId>,
}
impl<R: Renderer> std::fmt::Debug for CustomRenderElements<R> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Pointer(arg0) => f.debug_tuple("Pointer").field(arg0).finish(),
Self::Surface(arg0) => f.debug_tuple("Surface").field(arg0).finish(),
#[cfg(feature = "debug")]
Self::Fps(arg0) => f.debug_tuple("Fps").field(arg0).finish(),
Self::_GenericCatcher(arg0) => f.debug_tuple("_GenericCatcher").field(arg0).finish(),
}
}
}
smithay::backend::renderer::element::render_elements! {
pub OutputRenderElements<R, E> where R: ImportAll + ImportMem;
Space=SpaceRenderElements<R, E>,
Window=Wrap<E>,
Custom=CustomRenderElements<R>,
Preview=CropRenderElement<RelocateRenderElement<RescaleRenderElement<WindowRenderElement<R>>>>,
}
impl<R: Renderer + ImportAll + ImportMem, E: RenderElement<R> + std::fmt::Debug> std::fmt::Debug
for OutputRenderElements<R, E>
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Space(arg0) => f.debug_tuple("Space").field(arg0).finish(),
Self::Window(arg0) => f.debug_tuple("Window").field(arg0).finish(),
Self::Custom(arg0) => f.debug_tuple("Custom").field(arg0).finish(),
Self::Preview(arg0) => f.debug_tuple("Preview").field(arg0).finish(),
Self::_GenericCatcher(arg0) => f.debug_tuple("_GenericCatcher").field(arg0).finish(),
}
}
}
pub fn space_preview_elements<'a, R, C>(
renderer: &'a mut R,
space: &'a Space<WindowElement>,
output: &'a Output,
) -> impl Iterator<Item = C> + 'a
where
R: Renderer + ImportAll + ImportMem,
R::TextureId: Clone + 'static,
C: From<CropRenderElement<RelocateRenderElement<RescaleRenderElement<WindowRenderElement<R>>>>> + 'a,
{
let constrain_behavior = ConstrainBehavior {
reference: ConstrainReference::BoundingBox,
behavior: ConstrainScaleBehavior::Fit,
align: ConstrainAlign::CENTER,
};
let preview_padding = 10;
let elements_on_space = space.elements_for_output(output).count();
let output_scale = output.current_scale().fractional_scale();
let output_transform = output.current_transform();
let output_size = output
.current_mode()
.map(|mode| {
output_transform
.transform_size(mode.size)
.to_f64()
.to_logical(output_scale)
})
.unwrap_or_default();
let max_elements_per_row = 4;
let elements_per_row = usize::min(elements_on_space, max_elements_per_row);
let rows = f64::ceil(elements_on_space as f64 / elements_per_row as f64);
let preview_size = Size::from((
f64::round(output_size.w / elements_per_row as f64) as i32 - preview_padding * 2,
f64::round(output_size.h / rows) as i32 - preview_padding * 2,
));
space
.elements_for_output(output)
.enumerate()
.flat_map(move |(element_index, window)| {
let column = element_index % elements_per_row;
let row = element_index / elements_per_row;
let preview_location = Point::from((
preview_padding + (preview_padding + preview_size.w) * column as i32,
preview_padding + (preview_padding + preview_size.h) * row as i32,
));
let constrain = Rectangle::new(preview_location, preview_size);
constrain_space_element(
renderer,
window,
preview_location,
1.0,
output_scale,
constrain,
constrain_behavior,
)
})
}
#[profiling::function]
pub fn output_elements<R>(
output: &Output,
space: &Space<WindowElement>,
custom_elements: impl IntoIterator<Item = CustomRenderElements<R>>,
renderer: &mut R,
show_window_preview: bool,
) -> (Vec<OutputRenderElements<R, WindowRenderElement<R>>>, Color32F)
where
R: Renderer + ImportAll + ImportMem,
R::TextureId: Clone + 'static,
{
if let Some(window) = output
.user_data()
.get::<FullscreenSurface>()
.and_then(|f| f.get())
{
let scale = output.current_scale().fractional_scale().into();
let window_render_elements: Vec<WindowRenderElement<R>> =
AsRenderElements::<R>::render_elements(&window, renderer, (0, 0).into(), scale, 1.0);
let elements = custom_elements
.into_iter()
.map(OutputRenderElements::from)
.chain(
window_render_elements
.into_iter()
.map(|e| OutputRenderElements::Window(Wrap::from(e))),
)
.collect::<Vec<_>>();
(elements, CLEAR_COLOR_FULLSCREEN)
} else {
let mut output_render_elements = custom_elements
.into_iter()
.map(OutputRenderElements::from)
.collect::<Vec<_>>();
if show_window_preview && space.elements_for_output(output).count() > 0 {
output_render_elements.extend(space_preview_elements(renderer, space, output));
}
let space_elements = smithay::desktop::space::space_render_elements::<_, WindowElement, _>(
renderer,
[space],
output,
1.0,
)
.expect("output without mode?");
output_render_elements.extend(space_elements.into_iter().map(OutputRenderElements::Space));
(output_render_elements, CLEAR_COLOR)
}
}
#[allow(clippy::too_many_arguments)]
pub fn render_output<'a, 'd, R>(
output: &'a Output,
space: &'a Space<WindowElement>,
custom_elements: impl IntoIterator<Item = CustomRenderElements<R>>,
renderer: &'a mut R,
framebuffer: &'a mut R::Framebuffer<'_>,
damage_tracker: &'d mut OutputDamageTracker,
age: usize,
show_window_preview: bool,
) -> Result<RenderOutputResult<'d>, OutputDamageTrackerError<R::Error>>
where
R: Renderer + ImportAll + ImportMem,
R::TextureId: Clone + 'static,
{
let (elements, clear_color) =
output_elements(output, space, custom_elements, renderer, show_window_preview);
damage_tracker.render_output(renderer, framebuffer, age, &elements, clear_color)
}