From bb1e68c9167d1f198dbcaf23e9f38a8ce77fee83 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Mon, 20 Dec 2021 19:13:55 +0100 Subject: [PATCH] space: Add support for drawing custom elements --- src/desktop/output.rs | 9 +++ src/desktop/space.rs | 153 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 154 insertions(+), 8 deletions(-) diff --git a/src/desktop/output.rs b/src/desktop/output.rs index 88a1d43..445f46f 100644 --- a/src/desktop/output.rs +++ b/src/desktop/output.rs @@ -6,6 +6,7 @@ use indexmap::IndexMap; use wayland_server::protocol::wl_surface::WlSurface; use std::{ + any::TypeId, cell::{RefCell, RefMut}, collections::{HashMap, VecDeque}, }; @@ -14,6 +15,7 @@ use std::{ pub(super) enum ToplevelId { Xdg(usize), Layer(usize), + Custom(TypeId, usize), } impl ToplevelId { @@ -30,6 +32,13 @@ impl ToplevelId { _ => false, } } + + pub fn is_custom(&self) -> bool { + match self { + ToplevelId::Custom(_, _) => true, + _ => false, + } + } } #[derive(Clone, Default)] diff --git a/src/desktop/space.rs b/src/desktop/space.rs index 63e4bea..3a2cfa4 100644 --- a/src/desktop/space.rs +++ b/src/desktop/space.rs @@ -1,6 +1,6 @@ use super::{draw_window, Window}; use crate::{ - backend::renderer::{utils::SurfaceState, Frame, ImportAll, Renderer, Transform}, + backend::renderer::{utils::SurfaceState, Frame, ImportAll, Renderer, Texture, Transform}, desktop::{layer::*, output::*}, utils::{Logical, Point, Rectangle}, wayland::{ @@ -14,6 +14,7 @@ use crate::{ }; use indexmap::{IndexMap, IndexSet}; use std::{ + any::{Any, TypeId}, cell::{RefCell, RefMut}, collections::{HashMap, HashSet, VecDeque}, sync::{ @@ -420,10 +421,18 @@ impl Space { output: &Output, age: usize, clear_color: [f32; 4], + custom_elements: &[&(dyn RenderElement< + R, + ::Frame, + ::Error, + ::TextureId, + >)], ) -> Result> where - R: Renderer + ImportAll, + R: Renderer + ImportAll + 'static, R::TextureId: 'static, + R::Error: 'static, + R::Frame: 'static, { let mut state = output_state(self.id, output); let output_size = output @@ -439,12 +448,15 @@ impl Space { // This will hold all the damage we need for this rendering step let mut damage = Vec::>::new(); // First add damage for windows gone - for old_window in state + for old_toplevel in state .last_state .iter() .filter_map(|(id, w)| { if !self.windows.iter().any(|w| ToplevelId::Xdg(w.0.id) == *id) && !layer_map.layers().any(|l| ToplevelId::Layer(l.0.id) == *id) + && !custom_elements + .iter() + .any(|c| ToplevelId::Custom(c.type_of(), c.id()) == *id) { Some(*w) } else { @@ -453,8 +465,8 @@ impl Space { }) .collect::>>() { - slog::trace!(self.logger, "Removing toplevel at: {:?}", old_window); - damage.push(old_window); + slog::trace!(self.logger, "Removing toplevel at: {:?}", old_toplevel); + damage.push(old_toplevel); } // lets iterate front to back and figure out, what new windows or unmoved windows we have @@ -503,6 +515,30 @@ impl Space { ); } } + for elem in custom_elements { + let geo = elem.geometry(); + let old_geo = state + .last_state + .get(&ToplevelId::Custom(elem.type_of(), elem.id())) + .cloned(); + + // moved of resized + if old_geo.map(|old_geo| old_geo != geo).unwrap_or(false) { + // Add damage for the old position of the layer + damage.push(old_geo.unwrap()); + damage.push(geo); + } else { + let location = geo.loc; + damage.extend( + elem.accumulated_damage(Some((self, output))) + .into_iter() + .map(|mut rect| { + rect.loc += location; + rect + }), + ); + } + } // That is all completely new damage, which we need to store for subsequent renders let new_damage = damage.clone(); @@ -577,7 +613,7 @@ impl Space { self.logger, "Rendering layer at {:?} with damage {:#?}", lgeo, - damage + layer_damage ); draw_layer( renderer, @@ -606,7 +642,7 @@ impl Space { self.logger, "Rendering window at {:?} with damage {:#?}", wgeo, - damage + win_damage ); draw_window( renderer, @@ -636,7 +672,7 @@ impl Space { self.logger, "Rendering layer at {:?} with damage {:#?}", lgeo, - damage + layer_damage ); draw_layer( renderer, @@ -651,6 +687,31 @@ impl Space { } } + for elem in custom_elements { + let egeo = elem.geometry(); + if damage.iter().any(|geo| egeo.overlaps(*geo)) { + let elem_damage = damage + .iter() + .flat_map(|geo| geo.intersection(egeo)) + .map(|geo| Rectangle::from_loc_and_size(geo.loc - egeo.loc, geo.size)) + .collect::>(); + slog::trace!( + self.logger, + "Rendering custom element at {:?} with damage {:#?}", + egeo, + elem_damage + ); + elem.draw( + renderer, + frame, + state.render_scale, + egeo.loc, + &elem_damage, + &self.logger, + )?; + } + } + Result::<(), R::Error>::Ok(()) }, ) { @@ -673,6 +734,10 @@ impl Space { let lgeo = layer_map.layer_geometry(layer); (ToplevelId::Layer(layer.0.id), lgeo) })) + .chain(custom_elements.iter().map(|custom| { + let egeo = custom.geometry(); + (ToplevelId::Custom(custom.type_of(), custom.id()), egeo) + })) .collect(); state.old_damage.push_front(new_damage); @@ -703,6 +768,78 @@ impl Space { } } +pub trait RenderElement +where + R: Renderer + ImportAll, + F: Frame, + E: std::error::Error, + T: Texture + 'static, + Self: Any + 'static, +{ + fn id(&self) -> usize; + fn type_of(&self) -> TypeId { + std::any::Any::type_id(self) + } + fn geometry(&self) -> Rectangle; + fn accumulated_damage(&self, for_values: Option<(&Space, &Output)>) -> Vec>; + fn draw( + &self, + renderer: &mut R, + frame: &mut F, + scale: f64, + location: Point, + damage: &[Rectangle], + log: &slog::Logger, + ) -> Result<(), R::Error>; +} + +#[derive(Debug)] +pub struct SurfaceTree { + pub surface: WlSurface, + pub position: Point, +} + +impl RenderElement for SurfaceTree +where + R: Renderer + ImportAll, + F: Frame, + E: std::error::Error, + T: Texture + 'static, +{ + fn id(&self) -> usize { + self.surface.as_ref().id() as usize + } + fn geometry(&self) -> Rectangle { + let mut bbox = super::utils::bbox_from_surface_tree(&self.surface, (0, 0)); + bbox.loc += self.position; + bbox + } + + fn accumulated_damage(&self, for_values: Option<(&Space, &Output)>) -> Vec> { + super::utils::damage_from_surface_tree(&self.surface, (0, 0), for_values) + } + + fn draw( + &self, + renderer: &mut R, + frame: &mut F, + scale: f64, + location: Point, + damage: &[Rectangle], + log: &slog::Logger, + ) -> Result<(), R::Error> { + crate::backend::renderer::utils::draw_surface_tree( + renderer, + frame, + &self.surface, + scale, + location, + damage, + log, + ) + } +} + #[derive(Debug, thiserror::Error)] pub enum RenderError { #[error(transparent)]