diff --git a/src/desktop/space/mod.rs b/src/desktop/space/mod.rs index 47116b4..11bd6e8 100644 --- a/src/desktop/space/mod.rs +++ b/src/desktop/space/mod.rs @@ -24,6 +24,7 @@ use wayland_server::protocol::wl_surface::WlSurface; mod element; mod layer; mod output; +mod popup; mod window; pub use self::element::*; @@ -486,6 +487,16 @@ impl Space { let output_geo = Rectangle::from_loc_and_size(state.location, output_size); let layer_map = layer_map_for_output(output); + let window_popups = self + .windows + .iter() + .flat_map(|w| w.popup_elements::(self.id)) + .collect::>(); + let layer_popups = layer_map + .layers() + .flat_map(|l| l.popup_elements::(self.id)) + .collect::>(); + // This will hold all the damage we need for this rendering step let mut damage = Vec::>::new(); // First add damage for windows gone @@ -497,7 +508,9 @@ impl Space { .windows .iter() .map(|w| w as &SpaceElem) + .chain(window_popups.iter().map(|p| p as &SpaceElem)) .chain(layer_map.layers().map(|l| l as &SpaceElem)) + .chain(layer_popups.iter().map(|p| p as &SpaceElem)) .chain(custom_elements.iter().map(|c| c as &SpaceElem)) .any(|e| ToplevelId::from(e) == *id) { @@ -517,7 +530,9 @@ impl Space { .windows .iter() .map(|w| w as &SpaceElem) + .chain(window_popups.iter().map(|p| p as &SpaceElem)) .chain(layer_map.layers().map(|l| l as &SpaceElem)) + .chain(layer_popups.iter().map(|p| p as &SpaceElem)) .chain(custom_elements.iter().map(|c| c as &SpaceElem)) { let geo = element.geometry(self.id); @@ -647,7 +662,9 @@ impl Space { .windows .iter() .map(|w| w as &SpaceElem) + .chain(window_popups.iter().map(|p| p as &SpaceElem)) .chain(layer_map.layers().map(|l| l as &SpaceElem)) + .chain(layer_popups.iter().map(|p| p as &SpaceElem)) .chain(custom_elements.iter().map(|c| c as &SpaceElem)) .map(|elem| { let geo = elem.geometry(self.id); diff --git a/src/desktop/space/popup.rs b/src/desktop/space/popup.rs new file mode 100644 index 0000000..dbef156 --- /dev/null +++ b/src/desktop/space/popup.rs @@ -0,0 +1,129 @@ +use crate::{ + backend::renderer::{Frame, ImportAll, Renderer, Texture}, + desktop::{ + layer::LayerSurface, + popup::{PopupKind, PopupManager}, + space::{window_loc, Space, SpaceElement}, + utils::{bbox_from_surface_tree, damage_from_surface_tree}, + window::Window, + }, + utils::{Logical, Point, Rectangle}, + wayland::output::Output, +}; +use std::any::TypeId; + +#[derive(Debug)] +pub struct RenderPopup { + location: Point, + popup: PopupKind, +} + +impl Window { + pub(super) fn popup_elements(&self, space_id: usize) -> impl Iterator + where + R: Renderer + ImportAll + 'static, + R::TextureId: 'static, + R::Error: 'static, + R::Frame: 'static, + { + let loc = window_loc(self, &space_id) + self.geometry().loc; + self.toplevel() + .get_surface() + .map(move |surface| { + PopupManager::popups_for_surface(surface) + .ok() + .into_iter() + .flatten() + .map(move |(popup, location)| { + let offset = loc + location - popup.geometry().loc; + RenderPopup { + location: offset, + popup, + } + }) + }) + .into_iter() + .flatten() + } +} + +impl LayerSurface { + pub(super) fn popup_elements(&self, space_id: usize) -> impl Iterator + where + R: Renderer + ImportAll + 'static, + R::TextureId: 'static, + R::Error: 'static, + R::Frame: 'static, + { + type SpaceElem = + dyn SpaceElement::Frame, ::Error, ::TextureId>; + + let loc = (self as &SpaceElem).geometry(space_id).loc; + self.get_surface() + .map(move |surface| { + PopupManager::popups_for_surface(surface) + .ok() + .into_iter() + .flatten() + .map(move |(popup, location)| { + let offset = loc + location - popup.geometry().loc; + RenderPopup { + location: offset, + popup, + } + }) + }) + .into_iter() + .flatten() + } +} + +impl SpaceElement for RenderPopup +where + R: Renderer + ImportAll, + F: Frame, + E: std::error::Error, + T: Texture + 'static, +{ + fn id(&self) -> usize { + self.popup + .get_surface() + .map(|s| s.as_ref().id() as usize) + .unwrap_or(0) + } + + fn type_of(&self) -> TypeId { + TypeId::of::() + } + + fn geometry(&self, _space_id: usize) -> Rectangle { + if let Some(surface) = self.popup.get_surface() { + bbox_from_surface_tree(surface, self.location) + } else { + Rectangle::from_loc_and_size((0, 0), (0, 0)) + } + } + + fn accumulated_damage(&self, for_values: Option<(&Space, &Output)>) -> Vec> { + if let Some(surface) = self.popup.get_surface() { + damage_from_surface_tree(surface, (0, 0), for_values) + } else { + Vec::new() + } + } + + #[allow(clippy::too_many_arguments)] + fn draw( + &self, + _space_id: usize, + _renderer: &mut R, + _frame: &mut F, + _scale: f64, + _location: Point, + _damage: &[Rectangle], + _log: &slog::Logger, + ) -> Result<(), R::Error> { + // popups are special, we track them, but they render with their parents + Ok(()) + } +} diff --git a/src/desktop/window.rs b/src/desktop/window.rs index a45d65d..1c57b1a 100644 --- a/src/desktop/window.rs +++ b/src/desktop/window.rs @@ -258,18 +258,6 @@ impl Window { .into_iter() .flat_map(|rect| rect.intersection(self.bbox())), ); - for (popup, location) in PopupManager::popups_for_surface(surface) - .ok() - .into_iter() - .flatten() - { - if let Some(surface) = popup.get_surface() { - let offset = self.geometry().loc + location - popup.geometry().loc; - let bbox = bbox_from_surface_tree(surface, offset); - let popup_damage = damage_from_surface_tree(surface, offset, for_values); - damage.extend(popup_damage.into_iter().flat_map(|rect| rect.intersection(bbox))); - } - } } damage }