desktop: docs

This commit is contained in:
Victor Brekenfeld 2022-01-05 20:41:46 +01:00
parent 8e34865acc
commit 8059bdc5db
11 changed files with 317 additions and 23 deletions

View File

@ -257,7 +257,7 @@ pub trait Renderer {
pub trait ImportShm: Renderer { pub trait ImportShm: Renderer {
/// Import a given shm-based buffer into the renderer (see [`buffer_type`]). /// Import a given shm-based buffer into the renderer (see [`buffer_type`]).
/// ///
/// Returns a texture_id, which can be used with [`Frame::render_texture`] (or [`Frame::render_texture_at`]) /// Returns a texture_id, which can be used with [`Frame::render_texture_from_to`] (or [`Frame::render_texture_at`])
/// or implementation-specific functions. /// or implementation-specific functions.
/// ///
/// If not otherwise defined by the implementation, this texture id is only valid for the renderer, that created it. /// If not otherwise defined by the implementation, this texture id is only valid for the renderer, that created it.
@ -324,7 +324,7 @@ pub trait ImportEgl: Renderer {
/// Import a given wl_drm-based buffer into the renderer (see [`buffer_type`]). /// Import a given wl_drm-based buffer into the renderer (see [`buffer_type`]).
/// ///
/// Returns a texture_id, which can be used with [`Frame::render_texture`] (or [`Frame::render_texture_at`]) /// Returns a texture_id, which can be used with [`Frame::render_texture_from_to`] (or [`Frame::render_texture_at`])
/// or implementation-specific functions. /// or implementation-specific functions.
/// ///
/// If not otherwise defined by the implementation, this texture id is only valid for the renderer, that created it. /// If not otherwise defined by the implementation, this texture id is only valid for the renderer, that created it.
@ -372,7 +372,7 @@ pub trait ImportDma: Renderer {
/// Import a given raw dmabuf into the renderer. /// Import a given raw dmabuf into the renderer.
/// ///
/// Returns a texture_id, which can be used with [`Frame::render_texture`] (or [`Frame::render_texture_at`]) /// Returns a texture_id, which can be used with [`Frame::render_texture_from_to`] (or [`Frame::render_texture_at`])
/// or implementation-specific functions. /// or implementation-specific functions.
/// ///
/// If not otherwise defined by the implementation, this texture id is only valid for the renderer, that created it. /// If not otherwise defined by the implementation, this texture id is only valid for the renderer, that created it.
@ -395,7 +395,7 @@ pub trait ImportDma: Renderer {
pub trait ImportAll: Renderer { pub trait ImportAll: Renderer {
/// Import a given buffer into the renderer. /// Import a given buffer into the renderer.
/// ///
/// Returns a texture_id, which can be used with [`Frame::render_texture`] (or [`Frame::render_texture_at`]) /// Returns a texture_id, which can be used with [`Frame::render_texture_from_to`] (or [`Frame::render_texture_at`])
/// or implementation-specific functions. /// or implementation-specific functions.
/// ///
/// If not otherwise defined by the implementation, this texture id is only valid for the renderer, that created it. /// If not otherwise defined by the implementation, this texture id is only valid for the renderer, that created it.

View File

@ -1,3 +1,5 @@
//! Utility module for helpers around drawing [`WlSurface`]s with [`Renderer`]s.
use crate::{ use crate::{
backend::renderer::{buffer_dimensions, Frame, ImportAll, Renderer, Texture}, backend::renderer::{buffer_dimensions, Frame, ImportAll, Renderer, Texture},
utils::{Logical, Physical, Point, Rectangle, Size}, utils::{Logical, Physical, Point, Rectangle, Size},
@ -47,6 +49,15 @@ impl SurfaceState {
} }
} }
/// Handler to let smithay take over buffer management.
///
/// Needs to be called first on the commit-callback of
/// [`crate::wayland::compositor::compositor_init`].
///
/// Consumes the buffer of [`SurfaceAttributes`], the buffer will
/// not be accessible anymore, but [`draw_surface_tree`] and other
/// `draw_*` helpers of the [desktop module](`crate::desktop`) will
/// become usable for surfaces handled this way.
pub fn on_commit_buffer_handler(surface: &WlSurface) { pub fn on_commit_buffer_handler(surface: &WlSurface) {
if !is_sync_subsurface(surface) { if !is_sync_subsurface(surface) {
with_surface_tree_upward( with_surface_tree_upward(
@ -69,6 +80,15 @@ pub fn on_commit_buffer_handler(surface: &WlSurface) {
} }
} }
/// Draws a surface and its subsurfaces using a given [`Renderer`] and [`Frame`].
///
/// - `scale` needs to be equivalent to the fractional scale the rendered result should have.
/// - `location` is the position the surface should be drawn at.
/// - `damage` is the set of regions of the surface that should be drawn.
///
/// Note: This element will render nothing, if you are not using
/// [`crate::backend::renderer::utils::on_commit_buffer_handler`]
/// to let smithay handle buffer management.
pub fn draw_surface_tree<R, E, F, T>( pub fn draw_surface_tree<R, E, F, T>(
renderer: &mut R, renderer: &mut R,
frame: &mut F, frame: &mut F,

View File

@ -10,7 +10,8 @@
//! you want on the initialization of the backend. These functions will provide you //! you want on the initialization of the backend. These functions will provide you
//! with two objects: //! with two objects:
//! //!
//! - a [`WinitGraphicsBackend`], which can give you an implementation of a [`Renderer`] //! - a [`WinitGraphicsBackend`], which can give you an implementation of a
//! [`Renderer`](crate::backend::renderer::Renderer)
//! (or even [`Gles2Renderer`]) through its `renderer` method in addition to further //! (or even [`Gles2Renderer`]) through its `renderer` method in addition to further
//! functionality to access and manage the created winit-window. //! functionality to access and manage the created winit-window.
//! - a [`WinitEventLoop`], which dispatches some [`WinitEvent`] from the host graphics server. //! - a [`WinitEventLoop`], which dispatches some [`WinitEvent`] from the host graphics server.
@ -81,7 +82,7 @@ impl WindowSize {
} }
} }
/// Window with an active EGL Context created by `winit`. Implements the [`Renderer`] trait /// Window with an active EGL Context created by `winit`.
#[derive(Debug)] #[derive(Debug)]
pub struct WinitGraphicsBackend { pub struct WinitGraphicsBackend {
renderer: Gles2Renderer, renderer: Gles2Renderer,
@ -112,7 +113,8 @@ pub struct WinitEventLoop {
is_x11: bool, is_x11: bool,
} }
/// Create a new [`WinitGraphicsBackend`], which implements the [`Renderer`] trait and a corresponding /// Create a new [`WinitGraphicsBackend`], which implements the
/// [`Renderer`](crate::backend::renderer::Renderer) trait and a corresponding
/// [`WinitEventLoop`]. /// [`WinitEventLoop`].
pub fn init<L>(logger: L) -> Result<(WinitGraphicsBackend, WinitEventLoop), Error> pub fn init<L>(logger: L) -> Result<(WinitGraphicsBackend, WinitEventLoop), Error>
where where
@ -127,7 +129,8 @@ where
) )
} }
/// Create a new [`WinitGraphicsBackend`], which implements the [`Renderer`] trait, from a given [`WindowBuilder`] /// Create a new [`WinitGraphicsBackend`], which implements the
/// [`Renderer`](crate::backend::renderer::Renderer) trait, from a given [`WindowBuilder`]
/// struct and a corresponding [`WinitEventLoop`]. /// struct and a corresponding [`WinitEventLoop`].
pub fn init_from_builder<L>( pub fn init_from_builder<L>(
builder: WindowBuilder, builder: WindowBuilder,
@ -148,7 +151,8 @@ where
) )
} }
/// Create a new [`WinitGraphicsBackend`], which implements the [`Renderer`] trait, from a given [`WindowBuilder`] /// Create a new [`WinitGraphicsBackend`], which implements the
/// [`Renderer`](crate::backend::renderer::Renderer) trait, from a given [`WindowBuilder`]
/// struct, as well as given [`GlAttributes`] for further customization of the rendering pipeline and a /// struct, as well as given [`GlAttributes`] for further customization of the rendering pipeline and a
/// corresponding [`WinitEventLoop`]. /// corresponding [`WinitEventLoop`].
pub fn init_from_builder_with_gl_attr<L>( pub fn init_from_builder_with_gl_attr<L>(

View File

@ -72,7 +72,7 @@ impl X11Surface {
/// ///
/// You may bind this buffer to a renderer to render. /// You may bind this buffer to a renderer to render.
/// This function will return the same buffer until [`submit`](Self::submit) is called /// This function will return the same buffer until [`submit`](Self::submit) is called
/// or [`reset_buffers`](Self::reset_buffer) is used to reset the buffers. /// or [`reset_buffers`](Self::reset_buffers) is used to reset the buffers.
pub fn buffer(&mut self) -> Result<(Dmabuf, u8), AllocateBuffersError> { pub fn buffer(&mut self) -> Result<(Dmabuf, u8), AllocateBuffersError> {
if let Some(new_size) = self.resize.try_iter().last() { if let Some(new_size) = self.resize.try_iter().last() {
self.resize(new_size); self.resize(new_size);

View File

@ -23,6 +23,7 @@ use std::{
crate::utils::ids::id_gen!(next_layer_id, LAYER_ID, LAYER_IDS); crate::utils::ids::id_gen!(next_layer_id, LAYER_ID, LAYER_IDS);
/// Map of [`LayerSurface`]s on an [`Output`]
#[derive(Debug)] #[derive(Debug)]
pub struct LayerMap { pub struct LayerMap {
layers: IndexSet<LayerSurface>, layers: IndexSet<LayerSurface>,
@ -30,6 +31,15 @@ pub struct LayerMap {
zone: Rectangle<i32, Logical>, zone: Rectangle<i32, Logical>,
} }
/// Retrieve a [`LayerMap`] for a given [`Output`].
///
/// If none existed before a new empty [`LayerMap`] is attached
/// to the output and returned on subsequent calls.
///
/// Note: This function internally uses a [`RefCell`] per
/// [`Output`] as exposed by its return type. Therefor
/// trying to hold on to multiple references of a [`LayerMap`]
/// of the same output using this function *will* result in a panic.
pub fn layer_map_for_output(o: &Output) -> RefMut<'_, LayerMap> { pub fn layer_map_for_output(o: &Output) -> RefMut<'_, LayerMap> {
let userdata = o.user_data(); let userdata = o.user_data();
let weak_output = Arc::downgrade(&o.inner); let weak_output = Arc::downgrade(&o.inner);
@ -55,6 +65,7 @@ pub enum LayerError {
} }
impl LayerMap { impl LayerMap {
/// Map a [`LayerSurface`] to this [`LayerMap`].
pub fn map_layer(&mut self, layer: &LayerSurface) -> Result<(), LayerError> { pub fn map_layer(&mut self, layer: &LayerSurface) -> Result<(), LayerError> {
if !self.layers.contains(layer) { if !self.layers.contains(layer) {
if layer if layer
@ -73,6 +84,7 @@ impl LayerMap {
Ok(()) Ok(())
} }
/// Remove a [`LayerSurface`] from this [`LayerMap`].
pub fn unmap_layer(&mut self, layer: &LayerSurface) { pub fn unmap_layer(&mut self, layer: &LayerSurface) {
if self.layers.shift_remove(layer) { if self.layers.shift_remove(layer) {
let _ = layer.user_data().get::<LayerUserdata>().take(); let _ = layer.user_data().get::<LayerUserdata>().take();
@ -80,10 +92,15 @@ impl LayerMap {
} }
} }
/// Return the area of this output, that is not exclusive to any [`LayerSurface`]s.
pub fn non_exclusive_zone(&self) -> Rectangle<i32, Logical> { pub fn non_exclusive_zone(&self) -> Rectangle<i32, Logical> {
self.zone self.zone
} }
/// Returns the geometry of a given mapped layer.
///
/// If the layer was not previously mapped onto this layer map,
/// this function return `None`.
pub fn layer_geometry(&self, layer: &LayerSurface) -> Option<Rectangle<i32, Logical>> { pub fn layer_geometry(&self, layer: &LayerSurface) -> Option<Rectangle<i32, Logical>> {
if !self.layers.contains(layer) { if !self.layers.contains(layer) {
return None; return None;
@ -94,6 +111,7 @@ impl LayerMap {
Some(bbox) Some(bbox)
} }
/// Returns a `LayerSurface` under a given point and on a given layer, if any.
pub fn layer_under<P: Into<Point<f64, Logical>>>( pub fn layer_under<P: Into<Point<f64, Logical>>>(
&self, &self,
layer: WlrLayer, layer: WlrLayer,
@ -106,16 +124,19 @@ impl LayerMap {
}) })
} }
/// Iterator over all [`LayerSurface`]s currently mapped.
pub fn layers(&self) -> impl DoubleEndedIterator<Item = &LayerSurface> { pub fn layers(&self) -> impl DoubleEndedIterator<Item = &LayerSurface> {
self.layers.iter() self.layers.iter()
} }
/// Iterator over all [`LayerSurface`]s currently mapped on a given layer.
pub fn layers_on(&self, layer: WlrLayer) -> impl DoubleEndedIterator<Item = &LayerSurface> { pub fn layers_on(&self, layer: WlrLayer) -> impl DoubleEndedIterator<Item = &LayerSurface> {
self.layers self.layers
.iter() .iter()
.filter(move |l| l.layer().map(|l| l == layer).unwrap_or(false)) .filter(move |l| l.layer().map(|l| l == layer).unwrap_or(false))
} }
/// Returns the [`LayerSurface`] matching a given [`WlSurface`], if any.
pub fn layer_for_surface(&self, surface: &WlSurface) -> Option<&LayerSurface> { pub fn layer_for_surface(&self, surface: &WlSurface) -> Option<&LayerSurface> {
if !surface.as_ref().is_alive() { if !surface.as_ref().is_alive() {
return None; return None;
@ -126,6 +147,9 @@ impl LayerMap {
.find(|w| w.get_surface().map(|x| x == surface).unwrap_or(false)) .find(|w| w.get_surface().map(|x| x == surface).unwrap_or(false))
} }
/// Force re-arranging the layers, e.g. when the output size changes.
///
/// Note: Mapping or unmapping a layer will automatically cause a re-arrangement.
pub fn arrange(&mut self) { pub fn arrange(&mut self) {
if let Some(output) = self.output() { if let Some(output) = self.output() {
let output_rect = Rectangle::from_loc_and_size( let output_rect = Rectangle::from_loc_and_size(
@ -238,6 +262,10 @@ impl LayerMap {
self.output.upgrade().map(|inner| Output { inner }) self.output.upgrade().map(|inner| Output { inner })
} }
/// Cleanup some internally used resources.
///
/// This function needs to be called periodically (though not necessarily frequently)
/// to be able cleanup internally used resources.
pub fn cleanup(&mut self) { pub fn cleanup(&mut self) {
self.layers.retain(|layer| layer.alive()) self.layers.retain(|layer| layer.alive())
} }
@ -260,6 +288,7 @@ pub fn layer_state(layer: &LayerSurface) -> RefMut<'_, LayerState> {
}) })
} }
/// A [`LayerSurface`] represents a single layer surface as given by the wlr-layer-shell protocol.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct LayerSurface(pub(crate) Rc<LayerSurfaceInner>); pub struct LayerSurface(pub(crate) Rc<LayerSurfaceInner>);
@ -292,6 +321,7 @@ impl Drop for LayerSurfaceInner {
} }
impl LayerSurface { impl LayerSurface {
/// Create a new [`LayerSurface`] from a given [`WlrLayerSurface`] and its namespace.
pub fn new(surface: WlrLayerSurface, namespace: String) -> LayerSurface { pub fn new(surface: WlrLayerSurface, namespace: String) -> LayerSurface {
LayerSurface(Rc::new(LayerSurfaceInner { LayerSurface(Rc::new(LayerSurfaceInner {
id: next_layer_id(), id: next_layer_id(),
@ -301,18 +331,22 @@ impl LayerSurface {
})) }))
} }
/// Checks if the surface is still alive
pub fn alive(&self) -> bool { pub fn alive(&self) -> bool {
self.0.surface.alive() self.0.surface.alive()
} }
/// Returns the underlying [`WlrLayerSurface`]
pub fn layer_surface(&self) -> &WlrLayerSurface { pub fn layer_surface(&self) -> &WlrLayerSurface {
&self.0.surface &self.0.surface
} }
/// Returns the underlying [`WlSurface`]
pub fn get_surface(&self) -> Option<&WlSurface> { pub fn get_surface(&self) -> Option<&WlSurface> {
self.0.surface.get_surface() self.0.surface.get_surface()
} }
/// Returns the cached protocol state
pub fn cached_state(&self) -> Option<LayerSurfaceCachedState> { pub fn cached_state(&self) -> Option<LayerSurfaceCachedState> {
self.0.surface.get_surface().map(|surface| { self.0.surface.get_surface().map(|surface| {
with_states(surface, |states| { with_states(surface, |states| {
@ -322,6 +356,7 @@ impl LayerSurface {
}) })
} }
/// Returns true, if the surface has indicated, that it is able to process keyboard events.
pub fn can_receive_keyboard_focus(&self) -> bool { pub fn can_receive_keyboard_focus(&self) -> bool {
self.0 self.0
.surface .surface
@ -342,6 +377,7 @@ impl LayerSurface {
.unwrap_or(false) .unwrap_or(false)
} }
/// Returns the layer this surface resides on, if any yet.
pub fn layer(&self) -> Option<WlrLayer> { pub fn layer(&self) -> Option<WlrLayer> {
self.0.surface.get_surface().map(|surface| { self.0.surface.get_surface().map(|surface| {
with_states(surface, |states| { with_states(surface, |states| {
@ -351,12 +387,12 @@ impl LayerSurface {
}) })
} }
/// Returns the namespace of this surface
pub fn namespace(&self) -> &str { pub fn namespace(&self) -> &str {
&self.0.namespace &self.0.namespace
} }
/// A bounding box over this window and its children. /// Returns the bounding box over this layer surface and its subsurfaces.
// TODO: Cache and document when to trigger updates. If possible let space do it
pub fn bbox(&self) -> Rectangle<i32, Logical> { pub fn bbox(&self) -> Rectangle<i32, Logical> {
if let Some(surface) = self.0.surface.get_surface() { if let Some(surface) = self.0.surface.get_surface() {
bbox_from_surface_tree(surface, (0, 0)) bbox_from_surface_tree(surface, (0, 0))
@ -365,6 +401,10 @@ impl LayerSurface {
} }
} }
/// Returns the bounding box over this layer, it subsurfaces as well as any popups.
///
/// Note: You need to use a [`PopupManager`] to track popups, otherwise the bounding box
/// will not include the popups.
pub fn bbox_with_popups(&self) -> Rectangle<i32, Logical> { pub fn bbox_with_popups(&self) -> Rectangle<i32, Logical> {
let mut bounding_box = self.bbox(); let mut bounding_box = self.bbox();
if let Some(surface) = self.0.surface.get_surface() { if let Some(surface) = self.0.surface.get_surface() {
@ -383,6 +423,8 @@ impl LayerSurface {
/// Finds the topmost surface under this point if any and returns it together with the location of this /// Finds the topmost surface under this point if any and returns it together with the location of this
/// surface. /// surface.
///
/// - `point` needs to be relative to (0,0) of the layer surface.
pub fn surface_under<P: Into<Point<f64, Logical>>>( pub fn surface_under<P: Into<Point<f64, Logical>>>(
&self, &self,
point: P, point: P,
@ -408,7 +450,11 @@ impl LayerSurface {
} }
} }
/// Damage of all the surfaces of this layer /// Returns the damage of all the surfaces of this layer.
///
/// If `for_values` is `Some(_)` it will only return the damage on the
/// first call for a given [`Space`] and [`Output`], if the buffer hasn't changed.
/// Subsequent calls will return an empty vector until the buffer is updated again.
pub(super) fn accumulated_damage( pub(super) fn accumulated_damage(
&self, &self,
for_values: Option<(&Space, &Output)>, for_values: Option<(&Space, &Output)>,
@ -443,11 +489,21 @@ impl LayerSurface {
} }
} }
/// Returns a [`UserDataMap`] to allow associating arbitrary data with this surface.
pub fn user_data(&self) -> &UserDataMap { pub fn user_data(&self) -> &UserDataMap {
&self.0.userdata &self.0.userdata
} }
} }
/// Renders a given [`LayerSurface`] using a provided renderer and frame.
///
/// - `scale` needs to be equivalent to the fractional scale the rendered result should have.
/// - `location` is the position the layer surface should be drawn at.
/// - `damage` is the set of regions of the layer surface that should be drawn.
///
/// Note: This function will render nothing, if you are not using
/// [`crate::backend::renderer::utils::on_commit_buffer_handler`]
/// to let smithay handle buffer management.
pub fn draw_layer<R, E, F, T, P>( pub fn draw_layer<R, E, F, T, P>(
renderer: &mut R, renderer: &mut R,
frame: &mut F, frame: &mut F,

View File

@ -1,5 +1,54 @@
// TODO: Remove - but for now, this makes sure these files are not completely highlighted with warnings //! Desktop management helpers
#![allow(missing_docs)] //!
//! This module contains helpers to organize and interact with desktop-style shells.
//!
//! It is therefor a lot more opinionate then for example the [xdg-shell handler](crate::wayland::shell::xdg::xdg_shell_init)
//! and tightly integrates with some protocols (e.g. xdg-shell).
//!
//! The usage of this module is therefor entirely optional and depending on your use-case you might also only want
//! to use a limited set of the helpers provided.
//!
//! ## Helpers
//!
//! ### [`Window`]
//!
//! A window represents what is by the user typically understood as a single application window.
//!
//! Currently it abstracts over xdg-shell toplevels and Xwayland surfaces (TODO).
//! It provides a bunch of methods to calculate and retrieve its size, manage itself, attach additional user_data
//! as well as a [drawing function](`draw_window`) to ease rendering it's related surfaces.
//!
//! Note that a [`Window`] on it's own has no position. For that it needs to be placed inside a [`Space`].
//!
//! ### [`Space`]
//!
//! A space represents a two-dimensional plane of undefined dimensions.
//! [`Window`]s and [`Output`](crate::wayland::output::Output)s can be mapped onto it.
//!
//! Windows get a position and stacking order through mapping. Outputs become views of a part of the [`Space`]
//! and can be rendered via [`Space::render_output`]. Rendering results of spaces are automatically damage-tracked.
//!
//! ### Layer
//!
//! A [`LayerSurface`] represents a surface as provided by e.g. the layer-shell protocol.
//! It provides similar helper methods as a [`Window`] does to toplevel surfaces.
//!
//! Each [`Output`](crate::wayland::output::Output) can be associated a [`LayerMap`] by calling [`layer_map_for_output`],
//! which [`LayerSurface`]s can be mapped upon. Associated layer maps are automatically rendered by [`Space::render_output`],
//! but a [draw function](`draw_layer`) is also provided for manual layer-surface management.
//!
//! ### Popups
//!
//! Provides a [`PopupManager`], which can be used to automatically keep track of popups and their
//! relations to one-another. Popups are then automatically rendered with their matching toplevel surfaces,
//! when either [`draw_window`], [`draw_layer`] or [`Space::render_output`] is called.
//!
//! ## Remarks
//!
//! Note that the desktop abstractions are concerned with easing rendering different clients and therefor need to be able
//! to manage client buffers to do so. If you plan to use the provided drawing functions, you need to use
//! [`crate::backend::renderer::utils::on_commit_buffer_handler`].
pub(crate) mod layer; pub(crate) mod layer;
mod popup; mod popup;
pub mod space; pub mod space;

View File

@ -8,6 +8,7 @@ use crate::{
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use wayland_server::protocol::wl_surface::WlSurface; use wayland_server::protocol::wl_surface::WlSurface;
/// Helper to track popups.
#[derive(Debug)] #[derive(Debug)]
pub struct PopupManager { pub struct PopupManager {
unmapped_popups: Vec<PopupKind>, unmapped_popups: Vec<PopupKind>,
@ -16,6 +17,7 @@ pub struct PopupManager {
} }
impl PopupManager { impl PopupManager {
/// Create a new [`PopupManager`].
pub fn new<L: Into<Option<::slog::Logger>>>(logger: L) -> Self { pub fn new<L: Into<Option<::slog::Logger>>>(logger: L) -> Self {
PopupManager { PopupManager {
unmapped_popups: Vec::new(), unmapped_popups: Vec::new(),
@ -24,6 +26,7 @@ impl PopupManager {
} }
} }
/// Start tracking a new popup.
pub fn track_popup(&mut self, kind: PopupKind) -> Result<(), DeadResource> { pub fn track_popup(&mut self, kind: PopupKind) -> Result<(), DeadResource> {
if kind.parent().is_some() { if kind.parent().is_some() {
self.add_popup(kind) self.add_popup(kind)
@ -34,6 +37,7 @@ impl PopupManager {
} }
} }
/// Needs to be called for [`PopupManager`] to correctly update its internal state.
pub fn commit(&mut self, surface: &WlSurface) { pub fn commit(&mut self, surface: &WlSurface) {
if get_role(surface) == Some(XDG_POPUP_ROLE) { if get_role(surface) == Some(XDG_POPUP_ROLE) {
if let Some(i) = self if let Some(i) = self
@ -84,6 +88,7 @@ impl PopupManager {
}) })
} }
/// Finds the popup belonging to a given [`WlSurface`], if any.
pub fn find_popup(&self, surface: &WlSurface) -> Option<PopupKind> { pub fn find_popup(&self, surface: &WlSurface) -> Option<PopupKind> {
self.unmapped_popups self.unmapped_popups
.iter() .iter()
@ -99,6 +104,7 @@ impl PopupManager {
}) })
} }
/// Returns the popups and their relative positions for a given toplevel surface, if any.
pub fn popups_for_surface( pub fn popups_for_surface(
surface: &WlSurface, surface: &WlSurface,
) -> Result<impl Iterator<Item = (PopupKind, Point<i32, Logical>)>, DeadResource> { ) -> Result<impl Iterator<Item = (PopupKind, Point<i32, Logical>)>, DeadResource> {
@ -112,6 +118,8 @@ impl PopupManager {
}) })
} }
/// Needs to be called periodically (but not necessarily frequently)
/// to cleanup internal resources.
pub fn cleanup(&mut self) { pub fn cleanup(&mut self) {
// retain_mut is sadly still unstable // retain_mut is sadly still unstable
self.popup_trees.iter_mut().for_each(|tree| tree.cleanup()); self.popup_trees.iter_mut().for_each(|tree| tree.cleanup());
@ -211,8 +219,10 @@ impl PopupNode {
} }
} }
/// Represents a popup surface
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum PopupKind { pub enum PopupKind {
/// xdg-shell [`PopupSurface`]
Xdg(PopupSurface), Xdg(PopupSurface),
} }
@ -223,6 +233,7 @@ impl PopupKind {
} }
} }
/// Retrieves the underlying [`WlSurface`]
pub fn get_surface(&self) -> Option<&WlSurface> { pub fn get_surface(&self) -> Option<&WlSurface> {
match *self { match *self {
PopupKind::Xdg(ref t) => t.get_surface(), PopupKind::Xdg(ref t) => t.get_surface(),
@ -235,6 +246,7 @@ impl PopupKind {
} }
} }
/// Returns the surface geometry as set by the client using `xdg_surface::set_window_geometry`
pub fn geometry(&self) -> Rectangle<i32, Logical> { pub fn geometry(&self) -> Rectangle<i32, Logical> {
let wl_surface = match self.get_surface() { let wl_surface = match self.get_surface() {
Some(s) => s, Some(s) => s,

View File

@ -10,6 +10,7 @@ use std::{
}; };
use wayland_server::protocol::wl_surface::WlSurface; use wayland_server::protocol::wl_surface::WlSurface;
/// Trait for custom elements to be rendered during [`Space::render_output`].
pub trait RenderElement<R, F, E, T> pub trait RenderElement<R, F, E, T>
where where
R: Renderer<Error = E, TextureId = T, Frame = F> + ImportAll, R: Renderer<Error = E, TextureId = T, Frame = F> + ImportAll,
@ -18,16 +19,33 @@ where
T: Texture + 'static, T: Texture + 'static,
Self: Any + 'static, Self: Any + 'static,
{ {
/// Returns an id unique to this element for the type of Self.
fn id(&self) -> usize; fn id(&self) -> usize;
#[doc(hidden)] #[doc(hidden)]
fn type_of(&self) -> TypeId { fn type_of(&self) -> TypeId {
std::any::Any::type_id(self) std::any::Any::type_id(self)
} }
/// Returns the bounding box of this element including its position in the space.
fn geometry(&self) -> Rectangle<i32, Logical>; fn geometry(&self) -> Rectangle<i32, Logical>;
/// Returns the damage of the element since it's last update.
///
/// If you receive `Some(_)` for `for_values` you may cache that you
/// send the damage for this `Space` and `Output` combination once
/// and return an empty vector for subsequent calls until the contents
/// of this element actually change again for optimization reasons.
///
/// Returning `vec![Rectangle::from_loc_and_size((0, 0), (i32::MAX, i32::MAX))]` is always
/// correct, but very inefficient.
fn accumulated_damage( fn accumulated_damage(
&self, &self,
for_values: Option<SpaceOutputTuple<'_, '_>>, for_values: Option<SpaceOutputTuple<'_, '_>>,
) -> Vec<Rectangle<i32, Logical>>; ) -> Vec<Rectangle<i32, Logical>>;
/// Draws the element using the provided `Frame` and `Renderer`.
///
/// - `scale` provides the current fractional scale value to render as
/// - `damage` provides the regions you need to re-draw and *may* not
/// be equivalent to the damage returned by `accumulated_damage`.
/// Redrawing other parts of the element is not valid and may cause rendering artifacts.
fn draw( fn draw(
&self, &self,
renderer: &mut R, renderer: &mut R,
@ -98,9 +116,19 @@ where
} }
} }
/// Generic helper for drawing [`WlSurface`]s and their subsurfaces
/// as custom elements via [`RenderElement`].
///
/// For example useful for cursor or drag-and-drop surfaces.
///
/// Note: This element will render nothing, if you are not using
/// [`crate::backend::renderer::utils::on_commit_buffer_handler`]
/// to let smithay handle buffer management.
#[derive(Debug)] #[derive(Debug)]
pub struct SurfaceTree { pub struct SurfaceTree {
/// Surface to be drawn
pub surface: WlSurface, pub surface: WlSurface,
/// Position to draw add
pub position: Point<i32, Logical>, pub position: Point<i32, Logical>,
} }

View File

@ -1,3 +1,6 @@
//! This module contains the [`Space`] helper class as well has related
//! rendering helpers to add custom elements or different clients to a space.
use crate::{ use crate::{
backend::renderer::{utils::SurfaceState, Frame, ImportAll, Renderer, Transform}, backend::renderer::{utils::SurfaceState, Frame, ImportAll, Renderer, Transform},
desktop::{ desktop::{
@ -40,6 +43,7 @@ pub struct Space {
logger: ::slog::Logger, logger: ::slog::Logger,
} }
/// Elements rendered by [`Space::render_output`] in addition to windows, layers and popups.
pub type DynamicRenderElements<R> = pub type DynamicRenderElements<R> =
Box<dyn RenderElement<R, <R as Renderer>::Frame, <R as Renderer>::Error, <R as Renderer>::TextureId>>; Box<dyn RenderElement<R, <R as Renderer>::Frame, <R as Renderer>::Error, <R as Renderer>::TextureId>>;
@ -56,6 +60,7 @@ impl Drop for Space {
} }
impl Space { impl Space {
/// Create a new [`Space`]
pub fn new<L>(log: L) -> Space pub fn new<L>(log: L) -> Space
where where
L: Into<Option<slog::Logger>>, L: Into<Option<slog::Logger>>,
@ -68,14 +73,26 @@ impl Space {
} }
} }
/// Map window and moves it to top of the stack /// Map a [`Window`] and move it to top of the stack
/// ///
/// This can safely be called on an already mapped window /// This can safely be called on an already mapped window
/// to update its location inside the space.
///
/// If activate is true it will set the new windows state
/// to be activate and removes that state from every
/// other mapped window.
pub fn map_window<P: Into<Point<i32, Logical>>>(&mut self, window: &Window, location: P, activate: bool) { pub fn map_window<P: Into<Point<i32, Logical>>>(&mut self, window: &Window, location: P, activate: bool) {
self.insert_window(window, activate); self.insert_window(window, activate);
window_state(self.id, window).location = location.into(); window_state(self.id, window).location = location.into();
} }
/// Moves an already mapped [`Window`] to top of the stack
///
/// This function does nothing for unmapped windows.
///
/// If activate is true it will set the new windows state
/// to be activate and removes that state from every
/// other mapped window.
pub fn raise_window(&mut self, window: &Window, activate: bool) { pub fn raise_window(&mut self, window: &Window, activate: bool) {
if self.windows.shift_remove(window) { if self.windows.shift_remove(window) {
self.insert_window(window, activate); self.insert_window(window, activate);
@ -95,7 +112,9 @@ impl Space {
} }
} }
/// Unmap a window from this space by its id /// Unmap a [`Window`] from this space by.
///
/// This function does nothing for already unmapped windows
pub fn unmap_window(&mut self, window: &Window) { pub fn unmap_window(&mut self, window: &Window) {
if let Some(map) = window.user_data().get::<WindowUserdata>() { if let Some(map) = window.user_data().get::<WindowUserdata>() {
map.borrow_mut().remove(&self.id); map.borrow_mut().remove(&self.id);
@ -126,6 +145,7 @@ impl Space {
}) })
} }
/// Returns the window matching a given surface, if any
pub fn window_for_surface(&self, surface: &WlSurface) -> Option<&Window> { pub fn window_for_surface(&self, surface: &WlSurface) -> Option<&Window> {
if !surface.as_ref().is_alive() { if !surface.as_ref().is_alive() {
return None; return None;
@ -136,6 +156,7 @@ impl Space {
.find(|w| w.toplevel().get_surface().map(|x| x == surface).unwrap_or(false)) .find(|w| w.toplevel().get_surface().map(|x| x == surface).unwrap_or(false))
} }
/// Returns the layer matching a given surface, if any
pub fn layer_for_surface(&self, surface: &WlSurface) -> Option<LayerSurface> { pub fn layer_for_surface(&self, surface: &WlSurface) -> Option<LayerSurface> {
if !surface.as_ref().is_alive() { if !surface.as_ref().is_alive() {
return None; return None;
@ -146,6 +167,7 @@ impl Space {
}) })
} }
/// Returns the geometry of a [`Window`] including its relative position inside the Space.
pub fn window_geometry(&self, w: &Window) -> Option<Rectangle<i32, Logical>> { pub fn window_geometry(&self, w: &Window) -> Option<Rectangle<i32, Logical>> {
if !self.windows.contains(w) { if !self.windows.contains(w) {
return None; return None;
@ -154,6 +176,7 @@ impl Space {
Some(window_geo(w, &self.id)) Some(window_geo(w, &self.id))
} }
/// Returns the bounding box of a [`Window`] including its relative position inside the Space.
pub fn window_bbox(&self, w: &Window) -> Option<Rectangle<i32, Logical>> { pub fn window_bbox(&self, w: &Window) -> Option<Rectangle<i32, Logical>> {
if !self.windows.contains(w) { if !self.windows.contains(w) {
return None; return None;
@ -162,6 +185,14 @@ impl Space {
Some(window_rect(w, &self.id)) Some(window_rect(w, &self.id))
} }
/// Maps an [`Output`] inside the space.
///
/// Can be safely called on an already mapped
/// [`Output`] to update its scale or location.
///
/// The scale is the what is rendered for the given output
/// and may be fractional. It is independent from the integer scale
/// reported to clients by the output.
pub fn map_output<P: Into<Point<i32, Logical>>>(&mut self, output: &Output, scale: f64, location: P) { pub fn map_output<P: Into<Point<i32, Logical>>>(&mut self, output: &Output, scale: f64, location: P) {
let mut state = output_state(self.id, output); let mut state = output_state(self.id, output);
*state = OutputState { *state = OutputState {
@ -174,17 +205,28 @@ impl Space {
} }
} }
/// Iterate over all mapped [`Output`]s of this space.
pub fn outputs(&self) -> impl Iterator<Item = &Output> { pub fn outputs(&self) -> impl Iterator<Item = &Output> {
self.outputs.iter() self.outputs.iter()
} }
/// Unmap an [`Output`] from this space.
///
/// Does nothing if the output was not previously mapped.
pub fn unmap_output(&mut self, output: &Output) { pub fn unmap_output(&mut self, output: &Output) {
if !self.outputs.contains(output) {
return;
}
if let Some(map) = output.user_data().get::<OutputUserdata>() { if let Some(map) = output.user_data().get::<OutputUserdata>() {
map.borrow_mut().remove(&self.id); map.borrow_mut().remove(&self.id);
} }
self.outputs.retain(|o| o != output); self.outputs.retain(|o| o != output);
} }
/// Returns the geometry of the output including it's relative position inside the space.
///
/// The size is matching the amount of logical pixels of the space visible on the output
/// given is current mode and render scale.
pub fn output_geometry(&self, o: &Output) -> Option<Rectangle<i32, Logical>> { pub fn output_geometry(&self, o: &Output) -> Option<Rectangle<i32, Logical>> {
if !self.outputs.contains(o) { if !self.outputs.contains(o) {
return None; return None;
@ -204,6 +246,10 @@ impl Space {
}) })
} }
/// Returns the reder scale of a mapped output.
///
/// If the output was not previously mapped to the `Space`
/// this function returns `None`.
pub fn output_scale(&self, o: &Output) -> Option<f64> { pub fn output_scale(&self, o: &Output) -> Option<f64> {
if !self.outputs.contains(o) { if !self.outputs.contains(o) {
return None; return None;
@ -213,6 +259,7 @@ impl Space {
Some(state.render_scale) Some(state.render_scale)
} }
/// Returns all [`Output`]s a [`Window`] overlaps with.
pub fn outputs_for_window(&self, w: &Window) -> Vec<Output> { pub fn outputs_for_window(&self, w: &Window) -> Vec<Output> {
if !self.windows.contains(w) { if !self.windows.contains(w) {
return Vec::new(); return Vec::new();
@ -242,6 +289,11 @@ impl Space {
outputs outputs
} }
/// Refresh some internal values and update client state
/// based on the position of windows and outputs.
///
/// Needs to be called periodically, at best before every
/// wayland socket flush.
pub fn refresh(&mut self) { pub fn refresh(&mut self) {
self.windows.retain(|w| w.toplevel().alive()); self.windows.retain(|w| w.toplevel().alive());
@ -362,8 +414,8 @@ impl Space {
} }
} }
/// Automatically calls `Window::refresh` for the window that belongs to the given surface, /// Should be called on commit to let the space automatically call [`Window::refresh`]
/// if managed by this space. /// for the window that belongs to the given surface, if managed by this space.
pub fn commit(&self, surface: &WlSurface) { pub fn commit(&self, surface: &WlSurface) {
if is_sync_subsurface(surface) { if is_sync_subsurface(surface) {
return; return;
@ -377,6 +429,24 @@ impl Space {
} }
} }
/// Render a given [`Output`] using a given [`Renderer`].
///
/// [`Space`] will render all mapped [`Window`]s, mapped [`LayerSurface`](super::LayerSurface)s
/// of the given [`Output`] and their popups (if tracked by a [`PopupManager`](super::PopupManager)).
/// `clear_color` will be used to fill all unoccupied regions.
///
/// Rendering using this function will automatically apply damage-tracking.
/// To facilitate this you need to provide age values of the buffers bound to
/// the given `renderer`. If you stop using `Space` temporarily for rendering
/// or apply additional rendering operations, you need to reset the age values
/// accordingly as `Space` will be unable to track your custom rendering operations
/// to avoid rendering artifacts.
///
/// To add aditional elements without breaking damage-tracking implement the `RenderElement`
/// trait and use `custom_elements` to provide them to this function. `custom_elements are rendered
/// after every other element.
///
/// Returns a list of updated regions (or `None` if that list would be empty) in case of success.
pub fn render_output<R>( pub fn render_output<R>(
&mut self, &mut self,
renderer: &mut R, renderer: &mut R,
@ -467,7 +537,7 @@ impl Space {
let new_damage = damage.clone(); let new_damage = damage.clone();
// We now add old damage states, if we have an age value // We now add old damage states, if we have an age value
if age > 0 && state.old_damage.len() >= age { if age > 0 && state.old_damage.len() >= age {
// We do not need older states anymore // We do not need even older states anymore
state.old_damage.truncate(age); state.old_damage.truncate(age);
damage.extend(state.old_damage.iter().flatten().copied()); damage.extend(state.old_damage.iter().flatten().copied());
} else { } else {
@ -582,6 +652,11 @@ impl Space {
Ok(Some(new_damage)) Ok(Some(new_damage))
} }
/// Sends the frame callback to mapped [`Window`]s and [`LayerSurface`]s.
///
/// If `all` is set this will be send to `all` mapped surfaces.
/// Otherwise only windows and layers previously drawn during the
/// previous frame will be send frame events.
pub fn send_frames(&self, all: bool, time: u32) { pub fn send_frames(&self, all: bool, time: u32) {
for window in self.windows.iter().filter(|w| { for window in self.windows.iter().filter(|w| {
all || { all || {
@ -606,12 +681,16 @@ impl Space {
} }
} }
/// Errors thrown by [`Space::render_output`]
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum RenderError<R: Renderer> { pub enum RenderError<R: Renderer> {
/// The provided [`Renderer`] did return an error during an operation
#[error(transparent)] #[error(transparent)]
Rendering(R::Error), Rendering(R::Error),
/// The given [`Output`] has no set mode
#[error("Output has no active mode")] #[error("Output has no active mode")]
OutputNoMode, OutputNoMode,
/// The given [`Output`] is not mapped to this [`Space`].
#[error("Output was not mapped to this space")] #[error("Output was not mapped to this space")]
UnmappedOutput, UnmappedOutput,
} }

View File

@ -1,3 +1,5 @@
//! Helper functions to ease dealing with surface trees
use crate::{ use crate::{
backend::renderer::utils::SurfaceState, backend::renderer::utils::SurfaceState,
desktop::Space, desktop::Space,
@ -53,6 +55,9 @@ impl SurfaceState {
} }
} }
/// Returns the bounding box of a given surface and all its subsurfaces.
///
/// - `location` can be set to offset the returned bounding box.
pub fn bbox_from_surface_tree<P>(surface: &wl_surface::WlSurface, location: P) -> Rectangle<i32, Logical> pub fn bbox_from_surface_tree<P>(surface: &wl_surface::WlSurface, location: P) -> Rectangle<i32, Logical>
where where
P: Into<Point<i32, Logical>>, P: Into<Point<i32, Logical>>,
@ -88,6 +93,12 @@ where
bounding_box bounding_box
} }
/// Returns the damage rectangles of the current buffer for a given surface and its subsurfaces.
///
/// - `location` can be set to offset the returned bounding box.
/// - if a `key` is set the damage is only returned on the first call with the given key values.
/// Subsequent calls will return an empty vector until the buffer is updated again and new
/// damage values may be retrieved.
pub fn damage_from_surface_tree<P>( pub fn damage_from_surface_tree<P>(
surface: &wl_surface::WlSurface, surface: &wl_surface::WlSurface,
location: P, location: P,
@ -155,6 +166,10 @@ where
damage damage
} }
/// Returns the (sub-)surface under a given position given a surface, if any.
///
/// - `point` has to be the position to query, relative to (0, 0) of the given surface + `location`.
/// - `location` can be used to offset the returned point.
pub fn under_from_surface_tree<P>( pub fn under_from_surface_tree<P>(
surface: &wl_surface::WlSurface, surface: &wl_surface::WlSurface,
point: Point<f64, Logical>, point: Point<f64, Logical>,
@ -197,6 +212,7 @@ where
found.into_inner() found.into_inner()
} }
/// Sends frame callbacks for a surface and its subsurfaces with the given `time`.
pub fn send_frames_surface_tree(surface: &wl_surface::WlSurface, time: u32) { pub fn send_frames_surface_tree(surface: &wl_surface::WlSurface, time: u32) {
with_surface_tree_downward( with_surface_tree_downward(
surface, surface,

View File

@ -19,14 +19,17 @@ use wayland_server::protocol::wl_surface;
crate::utils::ids::id_gen!(next_window_id, WINDOW_ID, WINDOW_IDS); crate::utils::ids::id_gen!(next_window_id, WINDOW_ID, WINDOW_IDS);
/// Abstraction around different toplevel kinds
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum Kind { pub enum Kind {
/// xdg-shell [`ToplevelSurface`]
Xdg(ToplevelSurface), Xdg(ToplevelSurface),
/// XWayland surface (TODO)
#[cfg(feature = "xwayland")] #[cfg(feature = "xwayland")]
X11(X11Surface), X11(X11Surface),
} }
// Big TODO /// TODO
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct X11Surface { pub struct X11Surface {
surface: wl_surface::WlSurface, surface: wl_surface::WlSurface,
@ -39,10 +42,12 @@ impl std::cmp::PartialEq for X11Surface {
} }
impl X11Surface { impl X11Surface {
/// Checks if the surface is still alive.
pub fn alive(&self) -> bool { pub fn alive(&self) -> bool {
self.surface.as_ref().is_alive() self.surface.as_ref().is_alive()
} }
/// Returns the underlying [`WlSurface`](wl_surface::WlSurface), if still any.
pub fn get_surface(&self) -> Option<&wl_surface::WlSurface> { pub fn get_surface(&self) -> Option<&wl_surface::WlSurface> {
if self.alive() { if self.alive() {
Some(&self.surface) Some(&self.surface)
@ -53,6 +58,7 @@ impl X11Surface {
} }
impl Kind { impl Kind {
/// Checks if the surface is still alive.
pub fn alive(&self) -> bool { pub fn alive(&self) -> bool {
match *self { match *self {
Kind::Xdg(ref t) => t.alive(), Kind::Xdg(ref t) => t.alive(),
@ -61,6 +67,7 @@ impl Kind {
} }
} }
/// Returns the underlying [`WlSurface`](wl_surface::WlSurface), if still any.
pub fn get_surface(&self) -> Option<&wl_surface::WlSurface> { pub fn get_surface(&self) -> Option<&wl_surface::WlSurface> {
match *self { match *self {
Kind::Xdg(ref t) => t.get_surface(), Kind::Xdg(ref t) => t.get_surface(),
@ -84,6 +91,7 @@ impl Drop for WindowInner {
} }
} }
/// Represents a single application window
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Window(pub(super) Rc<WindowInner>); pub struct Window(pub(super) Rc<WindowInner>);
@ -102,6 +110,7 @@ impl Hash for Window {
} }
impl Window { impl Window {
/// Construct a new [`Window`] from a given compatible toplevel surface
pub fn new(toplevel: Kind) -> Window { pub fn new(toplevel: Kind) -> Window {
let id = next_window_id(); let id = next_window_id();
@ -123,7 +132,7 @@ impl Window {
.unwrap_or_else(|| self.bbox()) .unwrap_or_else(|| self.bbox())
} }
/// A bounding box over this window and its children. /// Returns a bounding box over this window and its children.
pub fn bbox(&self) -> Rectangle<i32, Logical> { pub fn bbox(&self) -> Rectangle<i32, Logical> {
if self.0.toplevel.get_surface().is_some() { if self.0.toplevel.get_surface().is_some() {
self.0.bbox.get() self.0.bbox.get()
@ -132,6 +141,10 @@ impl Window {
} }
} }
/// Returns a bounding box over this window and children including popups.
///
/// Note: You need to use a [`PopupManager`] to track popups, otherwise the bounding box
/// will not include the popups.
pub fn bbox_with_popups(&self) -> Rectangle<i32, Logical> { pub fn bbox_with_popups(&self) -> Rectangle<i32, Logical> {
let mut bounding_box = self.bbox(); let mut bounding_box = self.bbox();
if let Some(surface) = self.0.toplevel.get_surface() { if let Some(surface) = self.0.toplevel.get_surface() {
@ -204,6 +217,8 @@ impl Window {
/// Finds the topmost surface under this point if any and returns it together with the location of this /// Finds the topmost surface under this point if any and returns it together with the location of this
/// surface. /// surface.
///
/// - `point` should be relative to (0,0) of the window.
pub fn surface_under<P: Into<Point<f64, Logical>>>( pub fn surface_under<P: Into<Point<f64, Logical>>>(
&self, &self,
point: P, point: P,
@ -230,7 +245,11 @@ impl Window {
} }
} }
/// Damage of all the surfaces of this window /// Damage of all the surfaces of this window.
///
/// If `for_values` is `Some(_)` it will only return the damage on the
/// first call for a given [`Space`] and [`Output`], if the buffer hasn't changed.
/// Subsequent calls will return an empty vector until the buffer is updated again.
pub fn accumulated_damage(&self, for_values: Option<(&Space, &Output)>) -> Vec<Rectangle<i32, Logical>> { pub fn accumulated_damage(&self, for_values: Option<(&Space, &Output)>) -> Vec<Rectangle<i32, Logical>> {
let mut damage = Vec::new(); let mut damage = Vec::new();
if let Some(surface) = self.0.toplevel.get_surface() { if let Some(surface) = self.0.toplevel.get_surface() {
@ -255,15 +274,26 @@ impl Window {
damage damage
} }
/// Returns the underlying toplevel
pub fn toplevel(&self) -> &Kind { pub fn toplevel(&self) -> &Kind {
&self.0.toplevel &self.0.toplevel
} }
/// Returns a [`UserDataMap`] to allow associating arbitrary data with this window.
pub fn user_data(&self) -> &UserDataMap { pub fn user_data(&self) -> &UserDataMap {
&self.0.user_data &self.0.user_data
} }
} }
/// Renders a given [`Window`] using a provided renderer and frame.
///
/// - `scale` needs to be equivalent to the fractional scale the rendered result should have.
/// - `location` is the position the window should be drawn at.
/// - `damage` is the set of regions of the window that should be drawn.
///
/// Note: This function will render nothing, if you are not using
/// [`crate::backend::renderer::utils::on_commit_buffer_handler`]
/// to let smithay handle buffer management.
pub fn draw_window<R, E, F, T, P>( pub fn draw_window<R, E, F, T, P>(
renderer: &mut R, renderer: &mut R,
frame: &mut F, frame: &mut F,