space: Add support for drawing custom elements
This commit is contained in:
parent
5b85333eaf
commit
bb1e68c916
|
@ -6,6 +6,7 @@ use indexmap::IndexMap;
|
||||||
use wayland_server::protocol::wl_surface::WlSurface;
|
use wayland_server::protocol::wl_surface::WlSurface;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
|
any::TypeId,
|
||||||
cell::{RefCell, RefMut},
|
cell::{RefCell, RefMut},
|
||||||
collections::{HashMap, VecDeque},
|
collections::{HashMap, VecDeque},
|
||||||
};
|
};
|
||||||
|
@ -14,6 +15,7 @@ use std::{
|
||||||
pub(super) enum ToplevelId {
|
pub(super) enum ToplevelId {
|
||||||
Xdg(usize),
|
Xdg(usize),
|
||||||
Layer(usize),
|
Layer(usize),
|
||||||
|
Custom(TypeId, usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToplevelId {
|
impl ToplevelId {
|
||||||
|
@ -30,6 +32,13 @@ impl ToplevelId {
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_custom(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
ToplevelId::Custom(_, _) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use super::{draw_window, Window};
|
use super::{draw_window, Window};
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::renderer::{utils::SurfaceState, Frame, ImportAll, Renderer, Transform},
|
backend::renderer::{utils::SurfaceState, Frame, ImportAll, Renderer, Texture, Transform},
|
||||||
desktop::{layer::*, output::*},
|
desktop::{layer::*, output::*},
|
||||||
utils::{Logical, Point, Rectangle},
|
utils::{Logical, Point, Rectangle},
|
||||||
wayland::{
|
wayland::{
|
||||||
|
@ -14,6 +14,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use indexmap::{IndexMap, IndexSet};
|
use indexmap::{IndexMap, IndexSet};
|
||||||
use std::{
|
use std::{
|
||||||
|
any::{Any, TypeId},
|
||||||
cell::{RefCell, RefMut},
|
cell::{RefCell, RefMut},
|
||||||
collections::{HashMap, HashSet, VecDeque},
|
collections::{HashMap, HashSet, VecDeque},
|
||||||
sync::{
|
sync::{
|
||||||
|
@ -420,10 +421,18 @@ impl Space {
|
||||||
output: &Output,
|
output: &Output,
|
||||||
age: usize,
|
age: usize,
|
||||||
clear_color: [f32; 4],
|
clear_color: [f32; 4],
|
||||||
|
custom_elements: &[&(dyn RenderElement<
|
||||||
|
R,
|
||||||
|
<R as Renderer>::Frame,
|
||||||
|
<R as Renderer>::Error,
|
||||||
|
<R as Renderer>::TextureId,
|
||||||
|
>)],
|
||||||
) -> Result<bool, RenderError<R>>
|
) -> Result<bool, RenderError<R>>
|
||||||
where
|
where
|
||||||
R: Renderer + ImportAll,
|
R: Renderer + ImportAll + 'static,
|
||||||
R::TextureId: 'static,
|
R::TextureId: 'static,
|
||||||
|
R::Error: 'static,
|
||||||
|
R::Frame: 'static,
|
||||||
{
|
{
|
||||||
let mut state = output_state(self.id, output);
|
let mut state = output_state(self.id, output);
|
||||||
let output_size = output
|
let output_size = output
|
||||||
|
@ -439,12 +448,15 @@ impl Space {
|
||||||
// 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
|
||||||
for old_window in state
|
for old_toplevel in state
|
||||||
.last_state
|
.last_state
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(id, w)| {
|
.filter_map(|(id, w)| {
|
||||||
if !self.windows.iter().any(|w| ToplevelId::Xdg(w.0.id) == *id)
|
if !self.windows.iter().any(|w| ToplevelId::Xdg(w.0.id) == *id)
|
||||||
&& !layer_map.layers().any(|l| ToplevelId::Layer(l.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)
|
Some(*w)
|
||||||
} else {
|
} else {
|
||||||
|
@ -453,8 +465,8 @@ impl Space {
|
||||||
})
|
})
|
||||||
.collect::<Vec<Rectangle<i32, Logical>>>()
|
.collect::<Vec<Rectangle<i32, Logical>>>()
|
||||||
{
|
{
|
||||||
slog::trace!(self.logger, "Removing toplevel at: {:?}", old_window);
|
slog::trace!(self.logger, "Removing toplevel at: {:?}", old_toplevel);
|
||||||
damage.push(old_window);
|
damage.push(old_toplevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
// lets iterate front to back and figure out, what new windows or unmoved windows we have
|
// 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
|
// That is all completely new damage, which we need to store for subsequent renders
|
||||||
let new_damage = damage.clone();
|
let new_damage = damage.clone();
|
||||||
|
@ -577,7 +613,7 @@ impl Space {
|
||||||
self.logger,
|
self.logger,
|
||||||
"Rendering layer at {:?} with damage {:#?}",
|
"Rendering layer at {:?} with damage {:#?}",
|
||||||
lgeo,
|
lgeo,
|
||||||
damage
|
layer_damage
|
||||||
);
|
);
|
||||||
draw_layer(
|
draw_layer(
|
||||||
renderer,
|
renderer,
|
||||||
|
@ -606,7 +642,7 @@ impl Space {
|
||||||
self.logger,
|
self.logger,
|
||||||
"Rendering window at {:?} with damage {:#?}",
|
"Rendering window at {:?} with damage {:#?}",
|
||||||
wgeo,
|
wgeo,
|
||||||
damage
|
win_damage
|
||||||
);
|
);
|
||||||
draw_window(
|
draw_window(
|
||||||
renderer,
|
renderer,
|
||||||
|
@ -636,7 +672,7 @@ impl Space {
|
||||||
self.logger,
|
self.logger,
|
||||||
"Rendering layer at {:?} with damage {:#?}",
|
"Rendering layer at {:?} with damage {:#?}",
|
||||||
lgeo,
|
lgeo,
|
||||||
damage
|
layer_damage
|
||||||
);
|
);
|
||||||
draw_layer(
|
draw_layer(
|
||||||
renderer,
|
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::<Vec<_>>();
|
||||||
|
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(())
|
Result::<(), R::Error>::Ok(())
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
|
@ -673,6 +734,10 @@ impl Space {
|
||||||
let lgeo = layer_map.layer_geometry(layer);
|
let lgeo = layer_map.layer_geometry(layer);
|
||||||
(ToplevelId::Layer(layer.0.id), lgeo)
|
(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();
|
.collect();
|
||||||
state.old_damage.push_front(new_damage);
|
state.old_damage.push_front(new_damage);
|
||||||
|
|
||||||
|
@ -703,6 +768,78 @@ impl Space {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait RenderElement<R, F, E, T>
|
||||||
|
where
|
||||||
|
R: Renderer<Error = E, TextureId = T, Frame = F> + ImportAll,
|
||||||
|
F: Frame<Error = E, TextureId = T>,
|
||||||
|
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<i32, Logical>;
|
||||||
|
fn accumulated_damage(&self, for_values: Option<(&Space, &Output)>) -> Vec<Rectangle<i32, Logical>>;
|
||||||
|
fn draw(
|
||||||
|
&self,
|
||||||
|
renderer: &mut R,
|
||||||
|
frame: &mut F,
|
||||||
|
scale: f64,
|
||||||
|
location: Point<i32, Logical>,
|
||||||
|
damage: &[Rectangle<i32, Logical>],
|
||||||
|
log: &slog::Logger,
|
||||||
|
) -> Result<(), R::Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct SurfaceTree {
|
||||||
|
pub surface: WlSurface,
|
||||||
|
pub position: Point<i32, Logical>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R, F, E, T> RenderElement<R, F, E, T> for SurfaceTree
|
||||||
|
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.surface.as_ref().id() as usize
|
||||||
|
}
|
||||||
|
fn geometry(&self) -> Rectangle<i32, Logical> {
|
||||||
|
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<Rectangle<i32, Logical>> {
|
||||||
|
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<i32, Logical>,
|
||||||
|
damage: &[Rectangle<i32, Logical>],
|
||||||
|
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)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum RenderError<R: Renderer> {
|
pub enum RenderError<R: Renderer> {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
|
|
Loading…
Reference in New Issue