diff --git a/src/backend/renderer/mod.rs b/src/backend/renderer/mod.rs index 1b70e85..95cdb2d 100644 --- a/src/backend/renderer/mod.rs +++ b/src/backend/renderer/mod.rs @@ -32,6 +32,7 @@ use crate::backend::egl::{ Error as EglError, }; +#[cfg(feature = "wayland_frontend")] pub mod utils; #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] diff --git a/src/backend/renderer/utils/mod.rs b/src/backend/renderer/utils.rs similarity index 99% rename from src/backend/renderer/utils/mod.rs rename to src/backend/renderer/utils.rs index 9ac79e3..31eb4bb 100644 --- a/src/backend/renderer/utils/mod.rs +++ b/src/backend/renderer/utils.rs @@ -15,7 +15,7 @@ pub(crate) struct SurfaceState { pub(crate) buffer_scale: i32, pub(crate) buffer: Option, pub(crate) texture: Option>, - pub(crate) damage_seen: HashSet<(usize, *const ())>, + pub(crate) damage_seen: HashSet, } impl SurfaceState { @@ -69,7 +69,6 @@ pub fn on_commit_buffer_handler(surface: &WlSurface) { } } -/// TODO pub fn draw_surface_tree( renderer: &mut R, frame: &mut F, diff --git a/src/desktop/layer.rs b/src/desktop/layer.rs index 8a99374..4f72e0d 100644 --- a/src/desktop/layer.rs +++ b/src/desktop/layer.rs @@ -84,11 +84,14 @@ impl LayerMap { self.zone } - pub fn layer_geometry(&self, layer: &LayerSurface) -> Rectangle { + pub fn layer_geometry(&self, layer: &LayerSurface) -> Option> { + if !self.layers.contains(layer) { + return None; + } let mut bbox = layer.bbox_with_popups(); let state = layer_state(layer); bbox.loc += state.location; - bbox + Some(bbox) } pub fn layer_under>>( @@ -98,7 +101,7 @@ impl LayerMap { ) -> Option<&LayerSurface> { let point = point.into(); self.layers_on(layer).rev().find(|l| { - let bbox = self.layer_geometry(l); + let bbox = self.layer_geometry(l).unwrap(); bbox.to_f64().contains(point) }) } diff --git a/src/desktop/space/element.rs b/src/desktop/space/element.rs index a719310..3fe3cfc 100644 --- a/src/desktop/space/element.rs +++ b/src/desktop/space/element.rs @@ -4,7 +4,10 @@ use crate::{ utils::{Logical, Point, Rectangle}, wayland::output::Output, }; -use std::any::{Any, TypeId}; +use std::{ + any::{Any, TypeId}, + hash::{Hash, Hasher}, +}; use wayland_server::protocol::wl_surface::WlSurface; pub trait RenderElement @@ -21,13 +24,15 @@ where std::any::Any::type_id(self) } fn geometry(&self) -> Rectangle; - fn accumulated_damage(&self, for_values: Option<(&Space, &Output)>) -> Vec>; + fn accumulated_damage( + &self, + for_values: Option>, + ) -> Vec>; fn draw( &self, renderer: &mut R, frame: &mut F, scale: f64, - location: Point, damage: &[Rectangle], log: &slog::Logger, ) -> Result<(), R::Error>; @@ -77,7 +82,7 @@ where (&**self as &dyn RenderElement).geometry() } fn accumulated_damage(&self, for_values: Option<(&Space, &Output)>) -> Vec> { - (&**self as &dyn RenderElement).accumulated_damage(for_values) + (&**self as &dyn RenderElement).accumulated_damage(for_values.map(SpaceOutputTuple::from)) } fn draw( &self, @@ -85,11 +90,11 @@ where renderer: &mut R, frame: &mut F, scale: f64, - location: Point, + _location: Point, damage: &[Rectangle], log: &slog::Logger, ) -> Result<(), R::Error> { - (&**self as &dyn RenderElement).draw(renderer, frame, scale, location, damage, log) + (&**self as &dyn RenderElement).draw(renderer, frame, scale, damage, log) } } @@ -116,8 +121,11 @@ where bbox } - fn accumulated_damage(&self, for_values: Option<(&Space, &Output)>) -> Vec> { - damage_from_surface_tree(&self.surface, (0, 0), for_values) + fn accumulated_damage( + &self, + for_values: Option>, + ) -> Vec> { + damage_from_surface_tree(&self.surface, (0, 0), for_values.map(|x| (x.0, x.1))) } fn draw( @@ -125,7 +133,6 @@ where renderer: &mut R, frame: &mut F, scale: f64, - location: Point, damage: &[Rectangle], log: &slog::Logger, ) -> Result<(), R::Error> { @@ -134,9 +141,40 @@ where frame, &self.surface, scale, - location, + self.position, damage, log, ) } } + +/// Newtype for (&Space, &Output) to provide a `Hash` implementation for damage tracking +#[derive(Debug, PartialEq)] +pub struct SpaceOutputTuple<'a, 'b>(pub &'a Space, pub &'b Output); + +impl<'a, 'b> Hash for SpaceOutputTuple<'a, 'b> { + fn hash(&self, state: &mut H) { + self.0.id.hash(state); + (std::sync::Arc::as_ptr(&self.1.inner) as *const () as usize).hash(state); + } +} + +impl<'a, 'b> SpaceOutputTuple<'a, 'b> { + /// Returns an owned version that produces and equivalent hash + pub fn owned_hash(&self) -> SpaceOutputHash { + SpaceOutputHash( + self.0.id, + std::sync::Arc::as_ptr(&self.1.inner) as *const () as usize, + ) + } +} + +impl<'a, 'b> From<(&'a Space, &'b Output)> for SpaceOutputTuple<'a, 'b> { + fn from((space, output): (&'a Space, &'b Output)) -> SpaceOutputTuple<'a, 'b> { + SpaceOutputTuple(space, output) + } +} + +/// Type to use as an owned hashable value equal to [`SpaceOutputTuple`] +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +pub struct SpaceOutputHash(usize, usize); diff --git a/src/desktop/space/mod.rs b/src/desktop/space/mod.rs index d92a6de..0c65e30 100644 --- a/src/desktop/space/mod.rs +++ b/src/desktop/space/mod.rs @@ -30,12 +30,7 @@ use self::window::*; crate::utils::ids::id_gen!(next_space_id, SPACE_ID, SPACE_IDS); -#[derive(Debug, thiserror::Error)] -pub enum SpaceError { - #[error("Window is not mapped to this space")] - UnknownWindow, -} - +/// Represents two dimensional plane to map windows and outputs upon. #[derive(Debug)] pub struct Space { pub(super) id: usize, @@ -48,6 +43,12 @@ pub struct Space { pub type DynamicRenderElements = Box::Frame, ::Error, ::TextureId>>; +impl PartialEq for Space { + fn eq(&self, other: &Space) -> bool { + self.id == other.id + } +} + impl Drop for Space { fn drop(&mut self) { SPACE_IDS.lock().unwrap().remove(&self.id); @@ -390,6 +391,10 @@ impl Space { R::Error: 'static, R::Frame: 'static, { + if !self.outputs.contains(output) { + return Err(RenderError::UnmappedOutput); + } + type SpaceElem = dyn SpaceElement::Frame, ::Error, ::TextureId>; @@ -474,14 +479,7 @@ impl Space { damage.dedup(); damage.retain(|rect| rect.overlaps(output_geo)); damage.retain(|rect| rect.size.h > 0 && rect.size.w > 0); - for rect in damage.clone().iter() { - // if this rect was already removed, because it was smaller as another one, - // there is no reason to evaluate this. - if damage.contains(rect) { - // remove every rectangle that is contained in this rectangle - damage.retain(|other| !rect.contains_rect(*other)); - } - } + // merge overlapping rectangles damage = damage.into_iter().fold(Vec::new(), |mut new_damage, rect| { if let Some(existing) = new_damage.iter_mut().find(|other| rect.overlaps(**other)) { *existing = existing.merge(rect); @@ -614,4 +612,6 @@ pub enum RenderError { Rendering(R::Error), #[error("Output has no active mode")] OutputNoMode, + #[error("Output was not mapped to this space")] + UnmappedOutput, } diff --git a/src/desktop/utils.rs b/src/desktop/utils.rs index 79b27f6..0031c76 100644 --- a/src/desktop/utils.rs +++ b/src/desktop/utils.rs @@ -12,7 +12,7 @@ use crate::{ }; use wayland_server::protocol::wl_surface; -use std::{cell::RefCell, sync::Arc}; +use std::cell::RefCell; impl SurfaceState { /// Returns the size of the surface. @@ -96,8 +96,10 @@ pub fn damage_from_surface_tree

( where P: Into>, { + use super::space::SpaceOutputTuple; + let mut damage = Vec::new(); - let key = key.map(|(space, output)| (space.id, Arc::as_ptr(&output.inner) as *const ())); + let key = key.map(|x| SpaceOutputTuple::from(x).owned_hash()); with_surface_tree_upward( surface, location.into(),