From 8536fa90a10445dbb293448aadeb659d6f600fce Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Mon, 27 Dec 2021 00:03:42 +0100 Subject: [PATCH] desktop: streamline custom elements logic --- src/desktop/layer.rs | 8 +- src/desktop/mod.rs | 9 +- src/desktop/space/element.rs | 141 +++++++++ src/desktop/space/layer.rs | 72 +++++ src/desktop/{space.rs => space/mod.rs} | 393 +++++-------------------- src/desktop/{ => space}/output.rs | 47 ++- src/desktop/space/window.rs | 106 +++++++ 7 files changed, 422 insertions(+), 354 deletions(-) create mode 100644 src/desktop/space/element.rs create mode 100644 src/desktop/space/layer.rs rename src/desktop/{space.rs => space/mod.rs} (63%) rename src/desktop/{ => space}/output.rs (53%) create mode 100644 src/desktop/space/window.rs diff --git a/src/desktop/layer.rs b/src/desktop/layer.rs index 2d0f16f..4fa52aa 100644 --- a/src/desktop/layer.rs +++ b/src/desktop/layer.rs @@ -1,6 +1,6 @@ use crate::{ backend::renderer::{utils::draw_surface_tree, Frame, ImportAll, Renderer, Texture}, - desktop::{utils::*, PopupManager, Space}, + desktop::{space::RenderElement, utils::*, PopupManager, Space}, utils::{user_data::UserDataMap, Logical, Point, Rectangle}, wayland::{ compositor::with_states, @@ -267,12 +267,12 @@ impl LayerMap { } #[derive(Debug, Default)] -pub(super) struct LayerState { - location: Point, +pub struct LayerState { + pub location: Point, } type LayerUserdata = RefCell>; -fn layer_state(layer: &LayerSurface) -> RefMut<'_, LayerState> { +pub fn layer_state(layer: &LayerSurface) -> RefMut<'_, LayerState> { let userdata = layer.user_data(); userdata.insert_if_missing(LayerUserdata::default); RefMut::map(userdata.get::().unwrap().borrow_mut(), |opt| { diff --git a/src/desktop/mod.rs b/src/desktop/mod.rs index e5bcbbb..aad577a 100644 --- a/src/desktop/mod.rs +++ b/src/desktop/mod.rs @@ -1,13 +1,12 @@ // TODO: Remove - but for now, this makes sure these files are not completely highlighted with warnings #![allow(missing_docs, clippy::all)] -mod layer; -mod output; +pub(crate) mod layer; mod popup; -mod space; +pub mod space; pub mod utils; mod window; -pub use self::layer::*; +pub use self::layer::{draw_layer, layer_map_for_output, LayerMap, LayerSurface}; pub use self::popup::*; -pub use self::space::*; +pub use self::space::Space; pub use self::window::*; diff --git a/src/desktop/space/element.rs b/src/desktop/space/element.rs new file mode 100644 index 0000000..b62dc49 --- /dev/null +++ b/src/desktop/space/element.rs @@ -0,0 +1,141 @@ +use crate::{ + backend::renderer::{Frame, ImportAll, Renderer, Texture}, + desktop::{space::*, utils::*}, + utils::{Logical, Point, Rectangle}, + wayland::output::Output, +}; +use std::any::{Any, TypeId}; +use wayland_server::protocol::wl_surface::WlSurface; + +pub trait RenderElement +where + R: Renderer + ImportAll, + F: Frame, + E: std::error::Error, + T: Texture + 'static, + Self: Any + 'static, +{ + fn id(&self) -> usize; + #[doc(hidden)] + 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>; +} + +pub(crate) trait SpaceElement +where + R: Renderer + ImportAll, + F: Frame, + E: std::error::Error, + T: Texture, +{ + fn id(&self) -> usize; + fn type_of(&self) -> TypeId; + fn location(&self, space_id: usize) -> Point { + self.geometry(space_id).loc + } + fn geometry(&self, space_id: usize) -> Rectangle; + fn accumulated_damage(&self, for_values: Option<(&Space, &Output)>) -> Vec>; + fn draw( + &self, + space_id: usize, + renderer: &mut R, + frame: &mut F, + scale: f64, + location: Point, + damage: &[Rectangle], + log: &slog::Logger, + ) -> Result<(), R::Error>; +} + +impl SpaceElement for Box> +where + R: Renderer + ImportAll + 'static, + F: Frame + 'static, + E: std::error::Error + 'static, + T: Texture + 'static, +{ + fn id(&self) -> usize { + (&**self as &dyn RenderElement).id() + } + fn type_of(&self) -> TypeId { + (&**self as &dyn RenderElement).type_of() + } + fn geometry(&self, _space_id: usize) -> Rectangle { + (&**self as &dyn RenderElement).geometry() + } + fn accumulated_damage(&self, for_values: Option<(&Space, &Output)>) -> Vec> { + (&**self as &dyn RenderElement).accumulated_damage(for_values) + } + fn draw( + &self, + _space_id: usize, + renderer: &mut R, + frame: &mut F, + scale: f64, + location: Point, + damage: &[Rectangle], + log: &slog::Logger, + ) -> Result<(), R::Error> { + (&**self as &dyn RenderElement).draw(renderer, frame, scale, location, damage, log) + } +} + +#[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 = bbox_from_surface_tree(&self.surface, (0, 0)); + bbox.loc += self.position; + bbox + } + + fn accumulated_damage(&self, for_values: Option<(&Space, &Output)>) -> Vec> { + 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, + ) + } +} diff --git a/src/desktop/space/layer.rs b/src/desktop/space/layer.rs new file mode 100644 index 0000000..d9157e8 --- /dev/null +++ b/src/desktop/space/layer.rs @@ -0,0 +1,72 @@ +use crate::{ + backend::renderer::{Frame, ImportAll, Renderer, Texture}, + desktop::{ + layer::{layer_state as output_layer_state, *}, + space::{Space, SpaceElement}, + }, + utils::{Logical, Point, Rectangle}, + wayland::output::Output, +}; +use std::{ + any::TypeId, + cell::{RefCell, RefMut}, + collections::HashMap, +}; + +#[derive(Default)] +pub struct LayerState { + pub drawn: bool, +} + +type LayerUserdata = RefCell>; +pub fn layer_state(space: usize, l: &LayerSurface) -> RefMut<'_, LayerState> { + let userdata = l.user_data(); + userdata.insert_if_missing(LayerUserdata::default); + RefMut::map(userdata.get::().unwrap().borrow_mut(), |m| { + m.entry(space).or_default() + }) +} + +impl SpaceElement for LayerSurface +where + R: Renderer + ImportAll, + F: Frame, + E: std::error::Error, + T: Texture + 'static, +{ + fn id(&self) -> usize { + self.0.id + } + + fn type_of(&self) -> TypeId { + TypeId::of::() + } + + fn geometry(&self, space_id: usize) -> Rectangle { + let mut bbox = self.bbox_with_popups(); + let state = output_layer_state(self); + bbox.loc += state.location; + bbox + } + + fn accumulated_damage(&self, for_values: Option<(&Space, &Output)>) -> Vec> { + self.accumulated_damage(for_values) + } + + fn draw( + &self, + space_id: usize, + renderer: &mut R, + frame: &mut F, + scale: f64, + location: Point, + damage: &[Rectangle], + log: &slog::Logger, + ) -> Result<(), R::Error> { + let res = draw_layer(renderer, frame, self, scale, location, damage, log); + if res.is_ok() { + layer_state(space_id, self).drawn = true; + } + res + } +} diff --git a/src/desktop/space.rs b/src/desktop/space/mod.rs similarity index 63% rename from src/desktop/space.rs rename to src/desktop/space/mod.rs index 3a2cfa4..4734d14 100644 --- a/src/desktop/space.rs +++ b/src/desktop/space/mod.rs @@ -1,7 +1,9 @@ -use super::{draw_window, Window}; use crate::{ - backend::renderer::{utils::SurfaceState, Frame, ImportAll, Renderer, Texture, Transform}, - desktop::{layer::*, output::*}, + backend::renderer::{utils::SurfaceState, Frame, ImportAll, Renderer, Transform}, + desktop::{ + layer::{layer_map_for_output, LayerSurface}, + window::Window, + }, utils::{Logical, Point, Rectangle}, wayland::{ compositor::{ @@ -14,9 +16,8 @@ use crate::{ }; use indexmap::{IndexMap, IndexSet}; use std::{ - any::{Any, TypeId}, - cell::{RefCell, RefMut}, - collections::{HashMap, HashSet, VecDeque}, + cell::RefCell, + collections::{HashSet, VecDeque}, sync::{ atomic::{AtomicUsize, Ordering}, Mutex, @@ -24,6 +25,16 @@ use std::{ }; use wayland_server::protocol::wl_surface::WlSurface; +mod element; +mod layer; +mod output; +mod window; + +pub use self::element::*; +use self::layer::*; +use self::output::*; +use self::window::*; + static SPACE_ID: AtomicUsize = AtomicUsize::new(0); lazy_static::lazy_static! { static ref SPACE_IDS: Mutex> = Mutex::new(HashSet::new()); @@ -46,35 +57,6 @@ fn next_space_id() -> usize { id } -#[derive(Default)] -struct WindowState { - location: Point, - drawn: bool, -} - -type WindowUserdata = RefCell>; -fn window_state(space: usize, w: &Window) -> RefMut<'_, WindowState> { - let userdata = w.user_data(); - userdata.insert_if_missing(WindowUserdata::default); - RefMut::map(userdata.get::().unwrap().borrow_mut(), |m| { - m.entry(space).or_default() - }) -} - -#[derive(Default)] -struct LayerState { - drawn: bool, -} - -type LayerUserdata = RefCell>; -fn layer_state(space: usize, l: &LayerSurface) -> RefMut<'_, LayerState> { - let userdata = l.user_data(); - userdata.insert_if_missing(LayerUserdata::default); - RefMut::map(userdata.get::().unwrap().borrow_mut(), |m| { - m.entry(space).or_default() - }) -} - // TODO: Maybe replace UnmanagedResource if nothing else comes up? #[derive(Debug, thiserror::Error)] pub enum SpaceError { @@ -421,12 +403,9 @@ impl Space { output: &Output, age: usize, clear_color: [f32; 4], - custom_elements: &[&(dyn RenderElement< - R, - ::Frame, - ::Error, - ::TextureId, - >)], + custom_elements: &[Box< + dyn RenderElement::Frame, ::Error, ::TextureId>, + >], ) -> Result> where R: Renderer + ImportAll + 'static, @@ -434,6 +413,9 @@ impl Space { R::Error: 'static, R::Frame: 'static, { + type SpaceElem = + dyn SpaceElement::Frame, ::Error, ::TextureId>; + let mut state = output_state(self.id, output); let output_size = output .current_mode() @@ -451,14 +433,16 @@ impl Space { 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) + .filter_map(|(id, geo)| { + if !self + .windows + .iter() + .map(|w| w as &SpaceElem) + .chain(layer_map.layers().map(|l| l as &SpaceElem)) + .chain(custom_elements.iter().map(|c| c as &SpaceElem)) + .any(|e| ToplevelId::from(e) == *id) { - Some(*w) + Some(*geo) } else { None } @@ -470,9 +454,15 @@ impl Space { } // lets iterate front to back and figure out, what new windows or unmoved windows we have - for window in self.windows.iter() { - let geo = window_rect_with_popups(window, &self.id); - let old_geo = state.last_state.get(&ToplevelId::Xdg(window.0.id)).cloned(); + for element in self + .windows + .iter() + .map(|w| w as &SpaceElem) + .chain(layer_map.layers().map(|l| l as &SpaceElem)) + .chain(custom_elements.iter().map(|c| c as &SpaceElem)) + { + let geo = element.geometry(self.id); + let old_geo = state.last_state.get(&ToplevelId::from(element)).cloned(); // window was moved or resized if old_geo.map(|old_geo| old_geo != geo).unwrap_or(false) { @@ -481,62 +471,13 @@ impl Space { damage.push(geo); } else { // window stayed at its place - let loc = window_loc(window, &self.id); - damage.extend( - window - .accumulated_damage(Some((self, output))) - .into_iter() - .map(|mut rect| { - rect.loc += loc; - rect - }), - ); - } - } - for layer in layer_map.layers() { - let geo = layer_map.layer_geometry(layer); - let old_geo = state.last_state.get(&ToplevelId::Layer(layer.0.id)).cloned(); - - // layer moved or 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( - layer - .accumulated_damage(Some((self, output))) - .into_iter() - .map(|mut rect| { - rect.loc += location; - rect - }), - ); - } - } - 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 - }), - ); + let loc = element.location(self.id); + damage.extend(element.accumulated_damage(Some((self, output))).into_iter().map( + |mut rect| { + rect.loc += loc; + rect + }, + )); } } @@ -598,115 +539,40 @@ impl Space { // Then re-draw all windows & layers overlapping with a damage rect. - for layer in layer_map + for element in layer_map .layers_on(WlrLayer::Background) .chain(layer_map.layers_on(WlrLayer::Bottom)) + .map(|l| l as &SpaceElem) + .chain(self.windows.iter().map(|w| w as &SpaceElem)) + .chain( + layer_map + .layers_on(WlrLayer::Top) + .chain(layer_map.layers_on(WlrLayer::Overlay)) + .map(|l| l as &SpaceElem), + ) + .chain(custom_elements.iter().map(|c| c as &SpaceElem)) { - let lgeo = layer_map.layer_geometry(layer); - if damage.iter().any(|geo| lgeo.overlaps(*geo)) { - let layer_damage = damage + let geo = element.geometry(self.id); + if damage.iter().any(|d| d.overlaps(geo)) { + let loc = element.location(self.id) - output_geo.loc; + let damage = damage .iter() - .flat_map(|geo| geo.intersection(lgeo)) - .map(|geo| Rectangle::from_loc_and_size(geo.loc - lgeo.loc, geo.size)) - .collect::>(); - slog::trace!( - self.logger, - "Rendering layer at {:?} with damage {:#?}", - lgeo, - layer_damage - ); - draw_layer( - renderer, - frame, - layer, - state.render_scale, - lgeo.loc, - &layer_damage, - &self.logger, - )?; - layer_state(self.id, layer).drawn = true; - } - } - - for window in self.windows.iter() { - let wgeo = window_rect_with_popups(window, &self.id); - let mut loc = window_loc(window, &self.id); - if damage.iter().any(|geo| wgeo.overlaps(*geo)) { - loc -= output_geo.loc; - let win_damage = damage - .iter() - .flat_map(|geo| geo.intersection(wgeo)) + .flat_map(|d| d.intersection(geo)) .map(|geo| Rectangle::from_loc_and_size(geo.loc - loc, geo.size)) .collect::>(); slog::trace!( self.logger, - "Rendering window at {:?} with damage {:#?}", - wgeo, - win_damage + "Rendering toplevel at {:?} with damage {:#?}", + geo, + damage ); - draw_window( + element.draw( + self.id, renderer, frame, - window, state.render_scale, loc, - &win_damage, - &self.logger, - )?; - window_state(self.id, window).drawn = true; - } - } - - for layer in layer_map - .layers_on(WlrLayer::Top) - .chain(layer_map.layers_on(WlrLayer::Overlay)) - { - let lgeo = layer_map.layer_geometry(layer); - if damage.iter().any(|geo| lgeo.overlaps(*geo)) { - let layer_damage = damage - .iter() - .flat_map(|geo| geo.intersection(lgeo)) - .map(|geo| Rectangle::from_loc_and_size(geo.loc - lgeo.loc, geo.size)) - .collect::>(); - slog::trace!( - self.logger, - "Rendering layer at {:?} with damage {:#?}", - lgeo, - layer_damage - ); - draw_layer( - renderer, - frame, - layer, - state.render_scale, - lgeo.loc, - &layer_damage, - &self.logger, - )?; - layer_state(self.id, layer).drawn = true; - } - } - - 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, + &damage, &self.logger, )?; } @@ -726,18 +592,13 @@ impl Space { state.last_state = self .windows .iter() - .map(|window| { - let wgeo = window_rect_with_popups(window, &self.id); - (ToplevelId::Xdg(window.0.id), wgeo) + .map(|w| w as &SpaceElem) + .chain(layer_map.layers().map(|l| l as &SpaceElem)) + .chain(custom_elements.iter().map(|c| c as &SpaceElem)) + .map(|elem| { + let geo = elem.geometry(self.id); + (ToplevelId::from(elem), geo) }) - .chain(layer_map.layers().map(|layer| { - 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); @@ -768,78 +629,6 @@ 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)] @@ -847,35 +636,3 @@ pub enum RenderError { #[error("Output has no active mode")] OutputNoMode, } - -fn window_geo(window: &Window, space_id: &usize) -> Rectangle { - let loc = window_loc(window, space_id); - let mut wgeo = window.geometry(); - wgeo.loc = loc; - wgeo -} - -fn window_rect(window: &Window, space_id: &usize) -> Rectangle { - let loc = window_loc(window, space_id); - let mut wgeo = window.bbox(); - wgeo.loc += loc; - wgeo -} - -fn window_rect_with_popups(window: &Window, space_id: &usize) -> Rectangle { - let loc = window_loc(window, space_id); - let mut wgeo = window.bbox_with_popups(); - wgeo.loc += loc; - wgeo -} - -fn window_loc(window: &Window, space_id: &usize) -> Point { - window - .user_data() - .get::>>() - .unwrap() - .borrow() - .get(space_id) - .unwrap() - .location -} diff --git a/src/desktop/output.rs b/src/desktop/space/output.rs similarity index 53% rename from src/desktop/output.rs rename to src/desktop/space/output.rs index 445f46f..2b0b3fa 100644 --- a/src/desktop/output.rs +++ b/src/desktop/space/output.rs @@ -1,4 +1,6 @@ use crate::{ + backend::renderer::{Frame, ImportAll, Renderer, Texture}, + desktop::{space::SpaceElement, LayerSurface, Window}, utils::{Logical, Point, Rectangle}, wayland::output::Output, }; @@ -6,43 +8,34 @@ use indexmap::IndexMap; use wayland_server::protocol::wl_surface::WlSurface; use std::{ - any::TypeId, + any::{Any, TypeId}, cell::{RefCell, RefMut}, collections::{HashMap, VecDeque}, }; #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] -pub(super) enum ToplevelId { - Xdg(usize), - Layer(usize), - Custom(TypeId, usize), +pub struct ToplevelId { + t_id: TypeId, + id: usize, } -impl ToplevelId { - pub fn is_xdg(&self) -> bool { - match self { - ToplevelId::Xdg(_) => true, - _ => false, - } - } - - pub fn is_layer(&self) -> bool { - match self { - ToplevelId::Layer(_) => true, - _ => false, - } - } - - pub fn is_custom(&self) -> bool { - match self { - ToplevelId::Custom(_, _) => true, - _ => false, +impl From<&dyn SpaceElement> for ToplevelId +where + R: Renderer + ImportAll + 'static, + F: Frame + 'static, + E: std::error::Error + 'static, + T: Texture + 'static, +{ + fn from(elem: &dyn SpaceElement) -> ToplevelId { + ToplevelId { + t_id: elem.type_of(), + id: elem.id(), } } } #[derive(Clone, Default)] -pub(super) struct OutputState { +pub struct OutputState { pub location: Point, pub render_scale: f64, @@ -54,8 +47,8 @@ pub(super) struct OutputState { pub surfaces: Vec, } -pub(super) type OutputUserdata = RefCell>; -pub(super) fn output_state(space: usize, o: &Output) -> RefMut<'_, OutputState> { +pub type OutputUserdata = RefCell>; +pub fn output_state(space: usize, o: &Output) -> RefMut<'_, OutputState> { let userdata = o.user_data(); userdata.insert_if_missing(OutputUserdata::default); RefMut::map(userdata.get::().unwrap().borrow_mut(), |m| { diff --git a/src/desktop/space/window.rs b/src/desktop/space/window.rs new file mode 100644 index 0000000..31dc021 --- /dev/null +++ b/src/desktop/space/window.rs @@ -0,0 +1,106 @@ +use crate::{ + backend::renderer::{Frame, ImportAll, Renderer, Texture}, + desktop::{ + space::{Space, SpaceElement}, + window::{draw_window, Window}, + }, + utils::{Logical, Point, Rectangle}, + wayland::output::Output, +}; +use std::{ + any::TypeId, + cell::{RefCell, RefMut}, + collections::HashMap, +}; + +#[derive(Default)] +pub struct WindowState { + pub location: Point, + pub drawn: bool, +} + +pub type WindowUserdata = RefCell>; +pub fn window_state(space: usize, w: &Window) -> RefMut<'_, WindowState> { + let userdata = w.user_data(); + userdata.insert_if_missing(WindowUserdata::default); + RefMut::map(userdata.get::().unwrap().borrow_mut(), |m| { + m.entry(space).or_default() + }) +} + +pub fn window_geo(window: &Window, space_id: &usize) -> Rectangle { + let loc = window_loc(window, space_id); + let mut wgeo = window.geometry(); + wgeo.loc = loc; + wgeo +} + +pub fn window_rect(window: &Window, space_id: &usize) -> Rectangle { + let loc = window_loc(window, space_id); + let mut wgeo = window.bbox(); + wgeo.loc += loc; + wgeo +} + +pub fn window_rect_with_popups(window: &Window, space_id: &usize) -> Rectangle { + let loc = window_loc(window, space_id); + let mut wgeo = window.bbox_with_popups(); + wgeo.loc += loc; + wgeo +} + +pub fn window_loc(window: &Window, space_id: &usize) -> Point { + window + .user_data() + .get::>>() + .unwrap() + .borrow() + .get(space_id) + .unwrap() + .location +} + +impl SpaceElement for Window +where + R: Renderer + ImportAll, + F: Frame, + E: std::error::Error, + T: Texture + 'static, +{ + fn id(&self) -> usize { + self.0.id + } + + fn type_of(&self) -> TypeId { + TypeId::of::() + } + + fn location(&self, space_id: usize) -> Point { + window_loc(self, &space_id) + } + + fn geometry(&self, space_id: usize) -> Rectangle { + window_rect_with_popups(self, &space_id) + } + + fn accumulated_damage(&self, for_values: Option<(&Space, &Output)>) -> Vec> { + self.accumulated_damage(for_values) + } + + fn draw( + &self, + space_id: usize, + renderer: &mut R, + frame: &mut F, + scale: f64, + location: Point, + damage: &[Rectangle], + log: &slog::Logger, + ) -> Result<(), R::Error> { + let res = draw_window(renderer, frame, &self, scale, location, damage, log); + if res.is_ok() { + window_state(space_id, self).drawn = true; + } + res + } +}