desktop: docs
This commit is contained in:
parent
8e34865acc
commit
8059bdc5db
|
@ -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.
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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>(
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue