use crate::shell::{CosmicMappedRenderElement, WorkspaceRenderElement}; #[cfg(feature = "debug")] use smithay::backend::renderer::element::texture::TextureRenderElement; use smithay::{ backend::{ allocator::dmabuf::Dmabuf, renderer::{ Bind, Blit, ExportMem, ImportAll, ImportMem, Offscreen, Renderer, element::{ Element, Id, Kind, RenderElement, UnderlyingStorage, memory::MemoryRenderBufferRenderElement, surface::WaylandSurfaceRenderElement, utils::{CropRenderElement, Relocate, RelocateRenderElement, RescaleRenderElement}, }, gles::{GlesError, GlesRenderbuffer, GlesTexture, element::TextureShaderElement}, glow::{GlowFrame, GlowRenderer}, utils::{CommitCounter, DamageSet, OpaqueRegions}, }, }, utils::{ Buffer as BufferCoords, Logical, Physical, Point, Rectangle, Scale, user_data::UserDataMap, }, }; use super::{GlMultiRenderer, cursor::CursorRenderElement}; pub enum CosmicElement where R: AsGlowRenderer, R::TextureId: 'static, CosmicMappedRenderElement: RenderElement, { Workspace( RelocateRenderElement>>>, ), Cursor(RescaleRenderElement>>), Dnd(WaylandSurfaceRenderElement), MoveGrab(RescaleRenderElement>), Postprocess( CropRenderElement>>, ), Zoom(MemoryRenderBufferRenderElement), #[cfg(feature = "debug")] Egui(TextureRenderElement), } impl Element for CosmicElement where R: AsGlowRenderer, R::TextureId: 'static, CosmicMappedRenderElement: RenderElement, { fn id(&self) -> &Id { match self { CosmicElement::Workspace(elem) => elem.id(), CosmicElement::Cursor(elem) => elem.id(), CosmicElement::Dnd(elem) => elem.id(), CosmicElement::MoveGrab(elem) => elem.id(), CosmicElement::Postprocess(elem) => elem.id(), CosmicElement::Zoom(elem) => elem.id(), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => elem.id(), } } fn current_commit(&self) -> CommitCounter { match self { CosmicElement::Workspace(elem) => elem.current_commit(), CosmicElement::Cursor(elem) => elem.current_commit(), CosmicElement::Dnd(elem) => elem.current_commit(), CosmicElement::MoveGrab(elem) => elem.current_commit(), CosmicElement::Postprocess(elem) => elem.current_commit(), CosmicElement::Zoom(elem) => elem.current_commit(), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => elem.current_commit(), } } fn src(&self) -> Rectangle { match self { CosmicElement::Workspace(elem) => elem.src(), CosmicElement::Cursor(elem) => elem.src(), CosmicElement::Dnd(elem) => elem.src(), CosmicElement::MoveGrab(elem) => elem.src(), CosmicElement::Postprocess(elem) => elem.src(), CosmicElement::Zoom(elem) => elem.src(), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => elem.src(), } } fn geometry(&self, scale: Scale) -> Rectangle { match self { CosmicElement::Workspace(elem) => elem.geometry(scale), CosmicElement::Cursor(elem) => elem.geometry(scale), CosmicElement::Dnd(elem) => elem.geometry(scale), CosmicElement::MoveGrab(elem) => elem.geometry(scale), CosmicElement::Postprocess(elem) => elem.geometry(scale), CosmicElement::Zoom(elem) => elem.geometry(scale), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => elem.geometry(scale), } } fn location(&self, scale: Scale) -> Point { match self { CosmicElement::Workspace(elem) => elem.location(scale), CosmicElement::Cursor(elem) => elem.location(scale), CosmicElement::Dnd(elem) => elem.location(scale), CosmicElement::MoveGrab(elem) => elem.location(scale), CosmicElement::Postprocess(elem) => elem.location(scale), CosmicElement::Zoom(elem) => elem.location(scale), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => elem.location(scale), } } fn transform(&self) -> smithay::utils::Transform { match self { CosmicElement::Workspace(elem) => elem.transform(), CosmicElement::Cursor(elem) => elem.transform(), CosmicElement::Dnd(elem) => elem.transform(), CosmicElement::MoveGrab(elem) => elem.transform(), CosmicElement::Postprocess(elem) => elem.transform(), CosmicElement::Zoom(elem) => elem.transform(), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => elem.transform(), } } fn damage_since( &self, scale: Scale, commit: Option, ) -> DamageSet { match self { CosmicElement::Workspace(elem) => elem.damage_since(scale, commit), CosmicElement::Cursor(elem) => elem.damage_since(scale, commit), CosmicElement::Dnd(elem) => elem.damage_since(scale, commit), CosmicElement::MoveGrab(elem) => elem.damage_since(scale, commit), CosmicElement::Postprocess(elem) => elem.damage_since(scale, commit), CosmicElement::Zoom(elem) => elem.damage_since(scale, commit), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => elem.damage_since(scale, commit), } } fn opaque_regions(&self, scale: Scale) -> OpaqueRegions { match self { CosmicElement::Workspace(elem) => elem.opaque_regions(scale), CosmicElement::Cursor(elem) => elem.opaque_regions(scale), CosmicElement::Dnd(elem) => elem.opaque_regions(scale), CosmicElement::MoveGrab(elem) => elem.opaque_regions(scale), CosmicElement::Postprocess(elem) => elem.opaque_regions(scale), CosmicElement::Zoom(elem) => elem.opaque_regions(scale), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => elem.opaque_regions(scale), } } fn alpha(&self) -> f32 { match self { CosmicElement::Workspace(elem) => elem.alpha(), CosmicElement::Cursor(elem) => elem.alpha(), CosmicElement::Dnd(elem) => elem.alpha(), CosmicElement::MoveGrab(elem) => elem.alpha(), CosmicElement::Postprocess(elem) => elem.alpha(), CosmicElement::Zoom(elem) => elem.alpha(), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => elem.alpha(), } } fn kind(&self) -> Kind { match self { CosmicElement::Workspace(elem) => elem.kind(), CosmicElement::Cursor(elem) => elem.kind(), CosmicElement::Dnd(elem) => elem.kind(), CosmicElement::MoveGrab(elem) => elem.kind(), CosmicElement::Postprocess(elem) => elem.kind(), CosmicElement::Zoom(elem) => elem.kind(), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => elem.kind(), } } fn is_framebuffer_effect(&self) -> bool { match self { CosmicElement::Workspace(elem) => elem.is_framebuffer_effect(), CosmicElement::Cursor(elem) => elem.is_framebuffer_effect(), CosmicElement::Dnd(elem) => elem.is_framebuffer_effect(), CosmicElement::MoveGrab(elem) => elem.is_framebuffer_effect(), CosmicElement::Postprocess(elem) => elem.is_framebuffer_effect(), CosmicElement::Zoom(elem) => elem.is_framebuffer_effect(), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => elem.is_framebuffer_effect(), } } } impl RenderElement for CosmicElement where R: AsGlowRenderer, R::TextureId: 'static, R::Error: FromGlesError, CosmicMappedRenderElement: RenderElement, { fn draw( &self, frame: &mut R::Frame<'_, '_>, src: Rectangle, dst: Rectangle, damage: &[Rectangle], opaque_regions: &[Rectangle], cache: Option<&UserDataMap>, ) -> Result<(), R::Error> { match self { CosmicElement::Workspace(elem) => { elem.draw(frame, src, dst, damage, opaque_regions, cache) } CosmicElement::Cursor(elem) => { elem.draw(frame, src, dst, damage, opaque_regions, cache) } CosmicElement::Dnd(elem) => elem.draw(frame, src, dst, damage, opaque_regions, cache), CosmicElement::MoveGrab(elem) => { elem.draw(frame, src, dst, damage, opaque_regions, cache) } CosmicElement::Postprocess(elem) => { let glow_frame = R::glow_frame_mut(frame); RenderElement::::draw( elem, glow_frame, src, dst, damage, opaque_regions, cache, ) .map_err(FromGlesError::from_gles_error) } CosmicElement::Zoom(elem) => elem.draw(frame, src, dst, damage, opaque_regions, cache), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => { let glow_frame = R::glow_frame_mut(frame); RenderElement::::draw( elem, glow_frame, src, dst, damage, opaque_regions, cache, ) .map_err(FromGlesError::from_gles_error) } } } fn underlying_storage(&self, renderer: &mut R) -> Option> { match self { CosmicElement::Workspace(elem) => elem.underlying_storage(renderer), CosmicElement::Cursor(elem) => elem.underlying_storage(renderer), CosmicElement::Dnd(elem) => elem.underlying_storage(renderer), CosmicElement::MoveGrab(elem) => elem.underlying_storage(renderer), CosmicElement::Postprocess(elem) => { let glow_renderer = renderer.glow_renderer_mut(); elem.underlying_storage(glow_renderer) } CosmicElement::Zoom(elem) => elem.underlying_storage(renderer), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => { let glow_renderer = renderer.glow_renderer_mut(); elem.underlying_storage(glow_renderer) } } } fn capture_framebuffer( &self, frame: &mut ::Frame<'_, '_>, src: Rectangle, dst: Rectangle, cache: &UserDataMap, ) -> Result<(), ::Error> { match self { CosmicElement::Workspace(elem) => elem.capture_framebuffer(frame, src, dst, cache), CosmicElement::Cursor(elem) => elem.capture_framebuffer(frame, src, dst, cache), CosmicElement::Dnd(elem) => elem.capture_framebuffer(frame, src, dst, cache), CosmicElement::MoveGrab(elem) => elem.capture_framebuffer(frame, src, dst, cache), CosmicElement::Postprocess(elem) => { let glow_frame = R::glow_frame_mut(frame); RenderElement::::capture_framebuffer( elem, glow_frame, src, dst, cache, ) .map_err(FromGlesError::from_gles_error) } CosmicElement::Zoom(elem) => elem.capture_framebuffer(frame, src, dst, cache), #[cfg(feature = "debug")] CosmicElement::Egui(elem) => { let glow_frame = R::glow_frame_mut(frame); RenderElement::::capture_framebuffer( elem, glow_frame, src, dst, cache, ) .map_err(FromGlesError::from_gles_error) } } } } impl From>>> for CosmicElement where R: AsGlowRenderer, R::TextureId: 'static, CosmicMappedRenderElement: RenderElement, { fn from(elem: CropRenderElement>>) -> Self { Self::Workspace(RelocateRenderElement::from_element( elem, (0, 0), Relocate::Relative, )) } } impl From> for CosmicElement where R: AsGlowRenderer, R::TextureId: 'static, CosmicMappedRenderElement: RenderElement, { fn from(value: MemoryRenderBufferRenderElement) -> Self { Self::Zoom(value) } } #[cfg(feature = "debug")] impl From> for CosmicElement where R: AsGlowRenderer, R::TextureId: 'static, CosmicMappedRenderElement: RenderElement, { fn from(elem: TextureRenderElement) -> Self { Self::Egui(elem) } } pub trait AsGlowRenderer: Renderer + Offscreen + Offscreen + ImportAll + ImportMem + ExportMem + Bind + Blit { fn glow_renderer(&self) -> &GlowRenderer; fn glow_renderer_mut(&mut self) -> &mut GlowRenderer; fn glow_frame<'a, 'frame, 'buffer>( frame: &'a Self::Frame<'frame, 'buffer>, ) -> &'a GlowFrame<'frame, 'buffer>; fn glow_frame_mut<'a, 'frame, 'buffer>( frame: &'a mut Self::Frame<'frame, 'buffer>, ) -> &'a mut GlowFrame<'frame, 'buffer>; } impl AsGlowRenderer for GlowRenderer { fn glow_renderer(&self) -> &GlowRenderer { self } fn glow_renderer_mut(&mut self) -> &mut GlowRenderer { self } fn glow_frame<'a, 'frame, 'buffer>( frame: &'a Self::Frame<'frame, 'buffer>, ) -> &'a GlowFrame<'frame, 'buffer> { frame } fn glow_frame_mut<'a, 'frame, 'buffer>( frame: &'a mut Self::Frame<'frame, 'buffer>, ) -> &'a mut GlowFrame<'frame, 'buffer> { frame } } impl AsGlowRenderer for GlMultiRenderer<'_> { fn glow_renderer(&self) -> &GlowRenderer { self.as_ref() } fn glow_renderer_mut(&mut self) -> &mut GlowRenderer { self.as_mut() } fn glow_frame<'b, 'frame, 'buffer>( frame: &'b Self::Frame<'frame, 'buffer>, ) -> &'b GlowFrame<'frame, 'buffer> { frame.as_ref() } fn glow_frame_mut<'b, 'frame, 'buffer>( frame: &'b mut Self::Frame<'frame, 'buffer>, ) -> &'b mut GlowFrame<'frame, 'buffer> { frame.as_mut() } } pub struct DamageElement { id: Id, geometry: Rectangle, } impl DamageElement { pub fn new(geometry: Rectangle) -> DamageElement { DamageElement { id: Id::new(), geometry, } } } impl Element for DamageElement { fn id(&self) -> &Id { &self.id } fn current_commit(&self) -> CommitCounter { CommitCounter::default() } fn src(&self) -> Rectangle { Rectangle::from_size((1.0, 1.0).into()) } fn geometry(&self, scale: Scale) -> Rectangle { self.geometry.to_f64().to_physical(scale).to_i32_round() } fn damage_since( &self, scale: Scale, _commit: Option, ) -> DamageSet { DamageSet::from_slice(&[Rectangle::from_size(self.geometry(scale).size)]) } } impl RenderElement for DamageElement { fn draw( &self, _frame: &mut R::Frame<'_, '_>, _src: Rectangle, _dst: Rectangle, _damage: &[Rectangle], _opaque_regions: &[Rectangle], _cache: Option<&UserDataMap>, ) -> Result<(), R::Error> { Ok(()) } } pub trait FromGlesError { fn from_gles_error(err: GlesError) -> Self; } impl FromGlesError for GlesError { fn from_gles_error(err: GlesError) -> Self { err } }