#![allow(clippy::too_many_arguments)] use smithay::{ backend::renderer::{ element::{ memory::{MemoryRenderBuffer, MemoryRenderBufferRenderElement}, surface::WaylandSurfaceRenderElement, AsRenderElements, Kind, }, Color32F, ImportAll, ImportMem, Renderer, Texture, }, input::pointer::CursorImageStatus, render_elements, utils::{Physical, Point, Scale}, }; #[cfg(feature = "debug")] use smithay::{ backend::renderer::{ element::{Element, Id, RenderElement}, utils::CommitCounter, Frame, }, utils::{Buffer, Logical, Rectangle, Size, Transform}, }; pub static CLEAR_COLOR: Color32F = Color32F::new(0.8, 0.8, 0.9, 1.0); pub static CLEAR_COLOR_FULLSCREEN: Color32F = Color32F::new(0.0, 0.0, 0.0, 0.0); pub struct PointerElement { buffer: Option, status: CursorImageStatus, } impl Default for PointerElement { fn default() -> Self { Self { buffer: Default::default(), status: CursorImageStatus::default_named(), } } } impl PointerElement { pub fn set_status(&mut self, status: CursorImageStatus) { self.status = status; } pub fn set_buffer(&mut self, buffer: MemoryRenderBuffer) { self.buffer = Some(buffer); } } render_elements! { pub PointerRenderElement where R: ImportAll + ImportMem; Surface=WaylandSurfaceRenderElement, Memory=MemoryRenderBufferRenderElement, } impl std::fmt::Debug for PointerRenderElement { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Surface(arg0) => f.debug_tuple("Surface").field(arg0).finish(), Self::Memory(arg0) => f.debug_tuple("Memory").field(arg0).finish(), Self::_GenericCatcher(arg0) => f.debug_tuple("_GenericCatcher").field(arg0).finish(), } } } impl AsRenderElements for PointerElement where R: Renderer + ImportAll + ImportMem, { type RenderElement = PointerRenderElement; fn render_elements( &self, renderer: &mut R, location: Point, scale: Scale, alpha: f32, ) -> Vec where E: From>, { match &self.status { CursorImageStatus::Hidden => vec![], // Always render `Default` for a named shape. CursorImageStatus::Named(_) => { if let Some(buffer) = self.buffer.as_ref() { vec![PointerRenderElement::::from( MemoryRenderBufferRenderElement::from_buffer( renderer, location.to_f64(), buffer, None, None, None, Kind::Cursor, ) .expect("Lost system pointer buffer"), ) .into()] } else { vec![] } } CursorImageStatus::Surface(surface) => { let elements: Vec> = smithay::backend::renderer::element::surface::render_elements_from_surface_tree( renderer, surface, location, scale, alpha, Kind::Cursor, ); elements.into_iter().map(E::from).collect() } } } } #[cfg(feature = "debug")] pub static FPS_NUMBERS_PNG: &[u8] = include_bytes!("../resources/numbers.png"); #[cfg(feature = "debug")] #[derive(Debug, Clone)] pub struct FpsElement { id: Id, value: u32, texture: T, commit_counter: CommitCounter, } #[cfg(feature = "debug")] impl FpsElement { pub fn new(texture: T) -> Self { FpsElement { id: Id::new(), texture, value: 0, commit_counter: CommitCounter::default(), } } pub fn update_fps(&mut self, fps: u32) { if self.value != fps { self.value = fps; self.commit_counter.increment(); } } } #[cfg(feature = "debug")] impl Element for FpsElement where T: Texture + 'static, { fn id(&self) -> &Id { &self.id } fn location(&self, _scale: Scale) -> Point { (0, 0).into() } fn src(&self) -> Rectangle { let digits = if self.value < 10 { 1 } else if self.value < 100 { 2 } else { 3 }; Rectangle::from_size((24 * digits, 35).into()).to_f64() } fn geometry(&self, scale: Scale) -> Rectangle { let digits = if self.value < 10 { 1 } else if self.value < 100 { 2 } else { 3 }; Rectangle::from_size((24 * digits, 35).into()).to_physical_precise_round(scale) } fn current_commit(&self) -> CommitCounter { self.commit_counter } } #[cfg(feature = "debug")] impl RenderElement for FpsElement where R: Renderer + ImportAll, R::TextureId: 'static, { fn draw( &self, frame: &mut R::Frame<'_, '_>, _src: Rectangle, dst: Rectangle, damage: &[Rectangle], _opaque_regions: &[Rectangle], ) -> Result<(), R::Error> { // FIXME: respect the src for cropping let scale = dst.size.to_f64() / self.src().size; let value_str = std::cmp::min(self.value, 999).to_string(); let mut offset: Point = Point::from((0.0, 0.0)); for digit in value_str.chars().map(|d| d.to_digit(10).unwrap()) { let digit_location = dst.loc.to_f64() + offset; let digit_size = Size::::from((22, 35)).to_f64().to_physical(scale); let dst = Rectangle::new( digit_location.to_i32_round(), ((digit_size.to_point() + digit_location).to_i32_round() - digit_location.to_i32_round()) .to_size(), ); let damage = damage .iter() .cloned() .flat_map(|x| x.intersection(dst)) .map(|mut x| { x.loc -= dst.loc; x }) .collect::>(); let texture_src: Rectangle = match digit { 9 => Rectangle::from_size((22, 35).into()), 6 => Rectangle::new((22, 0).into(), (22, 35).into()), 3 => Rectangle::new((44, 0).into(), (22, 35).into()), 1 => Rectangle::new((66, 0).into(), (22, 35).into()), 8 => Rectangle::new((0, 35).into(), (22, 35).into()), 0 => Rectangle::new((22, 35).into(), (22, 35).into()), 2 => Rectangle::new((44, 35).into(), (22, 35).into()), 7 => Rectangle::new((0, 70).into(), (22, 35).into()), 4 => Rectangle::new((22, 70).into(), (22, 35).into()), 5 => Rectangle::new((44, 70).into(), (22, 35).into()), _ => unreachable!(), }; frame.render_texture_from_to( &self.texture, texture_src.to_f64(), dst, &damage, &[], Transform::Normal, 1.0, )?; offset += Point::from((24.0, 0.0)).to_physical(scale); } Ok(()) } }