Merge pull request #463 from Smithay/fix/popup_damage

This commit is contained in:
Victoria Brekenfeld 2022-01-16 17:00:14 +01:00 committed by GitHub
commit c9a2eb7ed2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 146 additions and 12 deletions

View File

@ -24,6 +24,7 @@ use wayland_server::protocol::wl_surface::WlSurface;
mod element; mod element;
mod layer; mod layer;
mod output; mod output;
mod popup;
mod window; mod window;
pub use self::element::*; pub use self::element::*;
@ -486,6 +487,16 @@ impl Space {
let output_geo = Rectangle::from_loc_and_size(state.location, output_size); let output_geo = Rectangle::from_loc_and_size(state.location, output_size);
let layer_map = layer_map_for_output(output); let layer_map = layer_map_for_output(output);
let window_popups = self
.windows
.iter()
.flat_map(|w| w.popup_elements::<R>(self.id))
.collect::<Vec<_>>();
let layer_popups = layer_map
.layers()
.flat_map(|l| l.popup_elements::<R>(self.id))
.collect::<Vec<_>>();
// This will hold all the damage we need for this rendering step // This will hold all the damage we need for this rendering step
let mut damage = Vec::<Rectangle<i32, Logical>>::new(); let mut damage = Vec::<Rectangle<i32, Logical>>::new();
// First add damage for windows gone // First add damage for windows gone
@ -497,7 +508,9 @@ impl Space {
.windows .windows
.iter() .iter()
.map(|w| w as &SpaceElem<R>) .map(|w| w as &SpaceElem<R>)
.chain(window_popups.iter().map(|p| p as &SpaceElem<R>))
.chain(layer_map.layers().map(|l| l as &SpaceElem<R>)) .chain(layer_map.layers().map(|l| l as &SpaceElem<R>))
.chain(layer_popups.iter().map(|p| p as &SpaceElem<R>))
.chain(custom_elements.iter().map(|c| c as &SpaceElem<R>)) .chain(custom_elements.iter().map(|c| c as &SpaceElem<R>))
.any(|e| ToplevelId::from(e) == *id) .any(|e| ToplevelId::from(e) == *id)
{ {
@ -517,7 +530,9 @@ impl Space {
.windows .windows
.iter() .iter()
.map(|w| w as &SpaceElem<R>) .map(|w| w as &SpaceElem<R>)
.chain(window_popups.iter().map(|p| p as &SpaceElem<R>))
.chain(layer_map.layers().map(|l| l as &SpaceElem<R>)) .chain(layer_map.layers().map(|l| l as &SpaceElem<R>))
.chain(layer_popups.iter().map(|p| p as &SpaceElem<R>))
.chain(custom_elements.iter().map(|c| c as &SpaceElem<R>)) .chain(custom_elements.iter().map(|c| c as &SpaceElem<R>))
{ {
let geo = element.geometry(self.id); let geo = element.geometry(self.id);
@ -647,7 +662,9 @@ impl Space {
.windows .windows
.iter() .iter()
.map(|w| w as &SpaceElem<R>) .map(|w| w as &SpaceElem<R>)
.chain(window_popups.iter().map(|p| p as &SpaceElem<R>))
.chain(layer_map.layers().map(|l| l as &SpaceElem<R>)) .chain(layer_map.layers().map(|l| l as &SpaceElem<R>))
.chain(layer_popups.iter().map(|p| p as &SpaceElem<R>))
.chain(custom_elements.iter().map(|c| c as &SpaceElem<R>)) .chain(custom_elements.iter().map(|c| c as &SpaceElem<R>))
.map(|elem| { .map(|elem| {
let geo = elem.geometry(self.id); let geo = elem.geometry(self.id);

129
src/desktop/space/popup.rs Normal file
View File

@ -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<i32, Logical>,
popup: PopupKind,
}
impl Window {
pub(super) fn popup_elements<R>(&self, space_id: usize) -> impl Iterator<Item = RenderPopup>
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<R>(&self, space_id: usize) -> impl Iterator<Item = RenderPopup>
where
R: Renderer + ImportAll + 'static,
R::TextureId: 'static,
R::Error: 'static,
R::Frame: 'static,
{
type SpaceElem<R> =
dyn SpaceElement<R, <R as Renderer>::Frame, <R as Renderer>::Error, <R as Renderer>::TextureId>;
let loc = (self as &SpaceElem<R>).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<R, F, E, T> SpaceElement<R, F, E, T> for RenderPopup
where
R: Renderer<Error = E, TextureId = T, Frame = F> + ImportAll,
F: Frame<Error = E, TextureId = T>,
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::<RenderPopup>()
}
fn geometry(&self, _space_id: usize) -> Rectangle<i32, Logical> {
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<Rectangle<i32, Logical>> {
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<i32, Logical>,
_damage: &[Rectangle<i32, Logical>],
_log: &slog::Logger,
) -> Result<(), R::Error> {
// popups are special, we track them, but they render with their parents
Ok(())
}
}

View File

@ -258,18 +258,6 @@ impl Window {
.into_iter() .into_iter()
.flat_map(|rect| rect.intersection(self.bbox())), .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 damage
} }