2017-06-11 12:33:03 +00:00
|
|
|
//! Utilities for handling surfaces, subsurfaces and regions
|
|
|
|
//!
|
2018-10-30 12:56:30 +00:00
|
|
|
//! This module provides automatic handling of surfaces, subsurfaces
|
|
|
|
//! and region Wayland objects, by registering an implementation for
|
2018-12-08 12:40:07 +00:00
|
|
|
//! for the [`wl_compositor`](wayland_server::protocol::wl_compositor)
|
|
|
|
//! and [`wl_subcompositor`](wayland_server::protocol::wl_subcompositor) globals.
|
2017-06-11 12:33:03 +00:00
|
|
|
//!
|
2017-09-20 07:57:43 +00:00
|
|
|
//! ## Why use this implementation
|
2017-06-11 12:33:03 +00:00
|
|
|
//!
|
2017-09-20 07:57:43 +00:00
|
|
|
//! This implementation does a simple job: it stores in a coherent way the state of
|
2017-06-11 12:33:03 +00:00
|
|
|
//! surface trees with subsurfaces, to provide you a direct access to the tree
|
2021-06-23 07:43:53 +00:00
|
|
|
//! structure and all surface attributes, and handles the application of double-buffered
|
|
|
|
//! state.
|
2017-06-11 12:33:03 +00:00
|
|
|
//!
|
|
|
|
//! As such, you can, given a root surface with a role requiring it to be displayed,
|
|
|
|
//! you can iterate over the whole tree of subsurfaces to recover all the metadata you
|
|
|
|
//! need to display the subsurface tree.
|
|
|
|
//!
|
2017-09-20 07:57:43 +00:00
|
|
|
//! This implementation will not do anything more than present you the metadata specified by the
|
2017-06-11 12:33:03 +00:00
|
|
|
//! client in a coherent and practical way. All the logic regarding to drawing itself, and
|
2018-10-30 12:56:30 +00:00
|
|
|
//! the positioning of windows (surface trees) one relative to another is out of its scope.
|
2017-06-11 12:33:03 +00:00
|
|
|
//!
|
|
|
|
//! ## How to use it
|
|
|
|
//!
|
|
|
|
//! ### Initialization
|
|
|
|
//!
|
2021-05-24 17:15:46 +00:00
|
|
|
//! To initialize this implementation, use the [`compositor_init`]
|
2018-12-08 12:40:07 +00:00
|
|
|
//! method provided by this module. It'll require you to first define as few things, as shown in
|
2017-09-20 07:57:43 +00:00
|
|
|
//! this example:
|
2017-06-11 12:33:03 +00:00
|
|
|
//!
|
|
|
|
//! ```
|
|
|
|
//! # extern crate wayland_server;
|
2017-09-03 17:53:29 +00:00
|
|
|
//! # #[macro_use] extern crate smithay;
|
2018-04-17 09:03:42 +00:00
|
|
|
//! use smithay::wayland::compositor::compositor_init;
|
2017-06-11 12:33:03 +00:00
|
|
|
//!
|
2020-04-05 17:01:08 +00:00
|
|
|
//! # let mut display = wayland_server::Display::new();
|
2017-09-20 07:57:43 +00:00
|
|
|
//! // Call the init function:
|
2021-06-23 07:43:53 +00:00
|
|
|
//! compositor_init(
|
2018-04-17 09:03:42 +00:00
|
|
|
//! &mut display,
|
2021-06-23 07:43:53 +00:00
|
|
|
//! |surface, dispatch_data| {
|
2018-04-17 09:03:42 +00:00
|
|
|
//! /*
|
2021-06-23 07:43:53 +00:00
|
|
|
//! Your handling of surface commits
|
2018-04-17 09:03:42 +00:00
|
|
|
//! */
|
|
|
|
//! },
|
|
|
|
//! None // put a logger here
|
2017-06-11 12:33:03 +00:00
|
|
|
//! );
|
|
|
|
//!
|
|
|
|
//! // You're now ready to go!
|
|
|
|
//! ```
|
|
|
|
//!
|
2021-06-23 07:43:53 +00:00
|
|
|
//! ### Use the surface states
|
|
|
|
//!
|
|
|
|
//! The main access to surface states is done through the [`with_states`] function, which
|
|
|
|
//! gives you access to the [`SurfaceData`] instance associated with this surface. It acts
|
|
|
|
//! as a general purpose container for associating state to a surface, double-buffered or
|
|
|
|
//! not. See its documentation for more details.
|
2017-06-11 12:33:03 +00:00
|
|
|
//!
|
2021-06-23 07:43:53 +00:00
|
|
|
//! ### State application and hooks
|
2017-06-11 12:33:03 +00:00
|
|
|
//!
|
2021-06-23 07:43:53 +00:00
|
|
|
//! On commit of a surface several steps are taken to update the state of the surface. Actions
|
|
|
|
//! are taken by smithay in the following order:
|
2017-09-03 17:53:29 +00:00
|
|
|
//!
|
2021-06-23 07:43:53 +00:00
|
|
|
//! 1. Commit hooks registered to this surface are invoked. Such hooks can be registered using
|
|
|
|
//! the [`add_commit_hook`] function. They are typically used by protocol extensions that
|
|
|
|
//! add state to a surface and need to check on commit that client did not request an
|
|
|
|
//! illegal state before it is applied on commit.
|
|
|
|
//! 2. The pending state is either applied and made current, or cached for later application
|
|
|
|
//! is the surface is a synchronize subsurface. If the current state is applied, state
|
|
|
|
//! of the synchronized children subsurface are applied as well at this point.
|
|
|
|
//! 3. Your user callback provided to [`compositor_init`] is invoked, so that you can access
|
|
|
|
//! the new current state of the surface. The state of sync children subsurfaces of your
|
|
|
|
//! surface may have changed as well, so this is the place to check it, using functions
|
|
|
|
//! like [`with_surface_tree_upward`] or [`with_surface_tree_downward`]. On the other hand,
|
|
|
|
//! if the surface is a sync subsurface, its current state will note have changed as
|
|
|
|
//! the result of that commit. You can check if it is using [`is_sync_subsurface`].
|
|
|
|
//!
|
|
|
|
//! ### Surface roles
|
|
|
|
//!
|
|
|
|
//! The wayland protocol specifies that a surface needs to be assigned a role before it can
|
|
|
|
//! be displayed. Furthermore, a surface can only have a single role during its whole lifetime.
|
|
|
|
//! Smithay represents this role as a `&'static str` identifier, that can only be set once
|
|
|
|
//! on a surface. See [`give_role`] and [`get_role`] for details. This module manages the
|
|
|
|
//! subsurface role, which is identified by the string `"subsurface"`.
|
2017-06-11 12:33:03 +00:00
|
|
|
|
2021-06-23 07:43:53 +00:00
|
|
|
use std::{cell::RefCell, rc::Rc, sync::Mutex};
|
2018-04-17 09:03:42 +00:00
|
|
|
|
2021-06-23 07:43:53 +00:00
|
|
|
mod cache;
|
2017-06-04 15:47:37 +00:00
|
|
|
mod handlers;
|
2021-06-23 07:43:53 +00:00
|
|
|
mod transaction;
|
2018-09-24 22:30:39 +00:00
|
|
|
mod tree;
|
2017-06-04 15:47:37 +00:00
|
|
|
|
2021-06-23 07:43:53 +00:00
|
|
|
pub use self::cache::{Cacheable, MultiCache};
|
|
|
|
pub use self::handlers::SubsurfaceCachedState;
|
|
|
|
use self::tree::PrivateSurfaceData;
|
|
|
|
pub use self::tree::{AlreadyHasRole, TraversalAction};
|
|
|
|
use crate::utils::{DeadResource, Rectangle};
|
2018-10-04 22:37:43 +00:00
|
|
|
use wayland_server::{
|
|
|
|
protocol::{
|
|
|
|
wl_buffer, wl_callback, wl_compositor, wl_output, wl_region, wl_subcompositor, wl_surface::WlSurface,
|
|
|
|
},
|
2021-05-30 21:31:14 +00:00
|
|
|
DispatchData, Display, Filter, Global, UserDataMap,
|
2018-09-24 22:30:39 +00:00
|
|
|
};
|
2017-06-04 15:47:37 +00:00
|
|
|
|
2021-05-24 17:33:03 +00:00
|
|
|
/// Description of a part of a surface that
|
2017-06-04 15:47:37 +00:00
|
|
|
/// should be considered damaged and needs to be redrawn
|
2021-02-12 21:13:38 +00:00
|
|
|
#[derive(Debug)]
|
2017-06-04 15:47:37 +00:00
|
|
|
pub enum Damage {
|
|
|
|
/// A rectangle containing the damaged zone, in surface coordinates
|
|
|
|
Surface(Rectangle),
|
2017-06-11 20:47:27 +00:00
|
|
|
/// A rectangle containing the damaged zone, in buffer coordinates
|
2017-06-04 15:47:37 +00:00
|
|
|
///
|
|
|
|
/// Note: Buffer scaling must be taken into consideration
|
2017-06-04 20:12:22 +00:00
|
|
|
Buffer(Rectangle),
|
2017-06-04 15:47:37 +00:00
|
|
|
}
|
|
|
|
|
2021-02-12 21:13:38 +00:00
|
|
|
#[derive(Debug, Copy, Clone, Default)]
|
2019-04-23 20:46:11 +00:00
|
|
|
struct Marker<R> {
|
2017-09-20 07:57:43 +00:00
|
|
|
_r: ::std::marker::PhantomData<R>,
|
|
|
|
}
|
|
|
|
|
2021-06-23 07:43:53 +00:00
|
|
|
/// The state container associated with a surface
|
|
|
|
///
|
|
|
|
/// This general-purpose container provides 2 main storages:
|
|
|
|
///
|
|
|
|
/// - the `data_map` storage has typemap semantics and allows you
|
|
|
|
/// to associate and access non-buffered data to the surface
|
|
|
|
/// - the `cached_state` storages allows you to associate state to
|
|
|
|
/// the surface that follows the double-buffering semantics associated
|
|
|
|
/// with the `commit` procedure of surfaces, also with typemap-like
|
|
|
|
/// semantics
|
|
|
|
///
|
|
|
|
/// See the respective documentation of each container for its usage.
|
|
|
|
///
|
|
|
|
/// By default, all surfaces have a [`SurfaceAttributes`] cached state,
|
|
|
|
/// and subsurface also have a [`SubsurfaceCachedState`] state as well.
|
|
|
|
pub struct SurfaceData {
|
|
|
|
/// The current role of the surface.
|
|
|
|
///
|
|
|
|
/// If `None` if the surface has not yet been assigned a role
|
|
|
|
pub role: Option<&'static str>,
|
|
|
|
/// The non-buffered typemap storage of this surface
|
|
|
|
pub data_map: UserDataMap,
|
|
|
|
/// The double-buffered typemap storage of this surface
|
|
|
|
pub cached_state: MultiCache,
|
|
|
|
}
|
|
|
|
|
2020-04-15 07:28:22 +00:00
|
|
|
/// New buffer assignation for a surface
|
2021-02-12 21:13:38 +00:00
|
|
|
#[derive(Debug)]
|
2020-04-15 07:28:22 +00:00
|
|
|
pub enum BufferAssignment {
|
|
|
|
/// The surface no longer has a buffer attached to it
|
|
|
|
Removed,
|
|
|
|
/// A new buffer has been attached
|
|
|
|
NewBuffer {
|
|
|
|
/// The buffer object
|
|
|
|
buffer: wl_buffer::WlBuffer,
|
|
|
|
/// location of the new buffer relative to the previous one
|
|
|
|
delta: (i32, i32),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2021-06-23 07:43:53 +00:00
|
|
|
/// General state associated with a surface
|
2017-06-04 15:47:37 +00:00
|
|
|
///
|
2021-06-23 07:43:53 +00:00
|
|
|
/// The fields `buffer`, `damage` and `frame_callbacks` should be
|
|
|
|
/// reset (by clearing their contents) once you have adequately
|
|
|
|
/// processed them, as their contents are aggregated from commit to commit.
|
|
|
|
#[derive(Debug)]
|
2019-04-23 20:46:11 +00:00
|
|
|
pub struct SurfaceAttributes {
|
2017-06-04 15:47:37 +00:00
|
|
|
/// Buffer defining the contents of the surface
|
|
|
|
///
|
|
|
|
/// You are free to set this field to `None` to avoid processing it several
|
2018-10-30 12:56:30 +00:00
|
|
|
/// times. It'll be set to `Some(...)` if the user attaches a buffer (or `NULL`) to
|
2020-04-15 07:28:22 +00:00
|
|
|
/// the surface, and be left to `None` if the user does not attach anything.
|
|
|
|
pub buffer: Option<BufferAssignment>,
|
2017-06-04 15:47:37 +00:00
|
|
|
/// Scale of the contents of the buffer, for higher-resolution contents.
|
|
|
|
///
|
|
|
|
/// If it matches the one of the output displaying this surface, no change
|
|
|
|
/// is necessary.
|
|
|
|
pub buffer_scale: i32,
|
|
|
|
/// Transform under which interpret the contents of the buffer
|
|
|
|
///
|
|
|
|
/// If it matches the one of the output displaying this surface, no change
|
|
|
|
/// is necessary.
|
|
|
|
pub buffer_transform: wl_output::Transform,
|
|
|
|
/// Region of the surface that is guaranteed to be opaque
|
|
|
|
///
|
|
|
|
/// By default the whole surface is potentially transparent
|
|
|
|
pub opaque_region: Option<RegionAttributes>,
|
|
|
|
/// Region of the surface that is sensitive to user input
|
|
|
|
///
|
|
|
|
/// By default the whole surface should be sensitive
|
|
|
|
pub input_region: Option<RegionAttributes>,
|
|
|
|
/// Damage rectangle
|
|
|
|
///
|
|
|
|
/// Hint provided by the client to suggest that only this part
|
|
|
|
/// of the surface was changed and needs to be redrawn
|
2021-05-24 17:33:03 +00:00
|
|
|
pub damage: Vec<Damage>,
|
2021-05-23 09:44:21 +00:00
|
|
|
/// The frame callbacks associated with this surface for the commit
|
2020-04-17 16:27:10 +00:00
|
|
|
///
|
2021-05-23 09:44:21 +00:00
|
|
|
/// The server must send the notifications so that a client
|
|
|
|
/// will not send excessive updates, while still allowing
|
|
|
|
/// the highest possible update rate for clients that wait for the reply
|
|
|
|
/// before drawing again. The server should give some time for the client
|
|
|
|
/// to draw and commit after sending the frame callback events to let it
|
|
|
|
/// hit the next output refresh.
|
|
|
|
///
|
|
|
|
/// A server should avoid signaling the frame callbacks if the
|
|
|
|
/// surface is not visible in any way, e.g. the surface is off-screen,
|
|
|
|
/// or completely obscured by other opaque surfaces.
|
2020-04-17 16:27:10 +00:00
|
|
|
///
|
|
|
|
/// An example possibility would be to trigger it once the frame
|
|
|
|
/// associated with this commit has been displayed on the screen.
|
2021-05-23 09:44:21 +00:00
|
|
|
pub frame_callbacks: Vec<wl_callback::WlCallback>,
|
2021-02-12 21:13:38 +00:00
|
|
|
}
|
|
|
|
|
2019-04-23 20:46:11 +00:00
|
|
|
impl Default for SurfaceAttributes {
|
|
|
|
fn default() -> SurfaceAttributes {
|
2017-06-04 15:47:37 +00:00
|
|
|
SurfaceAttributes {
|
|
|
|
buffer: None,
|
|
|
|
buffer_scale: 1,
|
|
|
|
buffer_transform: wl_output::Transform::Normal,
|
|
|
|
opaque_region: None,
|
|
|
|
input_region: None,
|
2021-05-24 17:33:03 +00:00
|
|
|
damage: Vec::new(),
|
2021-05-23 09:44:21 +00:00
|
|
|
frame_callbacks: Vec::new(),
|
2017-06-04 15:47:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Attributes defining the behaviour of a sub-surface relative to its parent
|
2017-09-03 17:53:29 +00:00
|
|
|
#[derive(Copy, Clone, Debug)]
|
|
|
|
pub struct SubsurfaceRole {
|
2018-04-17 09:03:42 +00:00
|
|
|
/// Location of the top-left corner of this sub-surface relative to
|
2017-06-04 15:47:37 +00:00
|
|
|
/// the top-left corner of its parent
|
2018-04-17 09:03:42 +00:00
|
|
|
pub location: (i32, i32),
|
2017-06-04 15:47:37 +00:00
|
|
|
/// Sync status of this sub-surface
|
|
|
|
///
|
|
|
|
/// If `true`, this surface should be repainted synchronously with its parent
|
2018-10-30 12:56:30 +00:00
|
|
|
/// if `false`, it should be considered independent of its parent regarding
|
2017-06-04 15:47:37 +00:00
|
|
|
/// repaint timings.
|
|
|
|
pub sync: bool,
|
|
|
|
}
|
|
|
|
|
2017-09-03 17:53:29 +00:00
|
|
|
impl Default for SubsurfaceRole {
|
|
|
|
fn default() -> SubsurfaceRole {
|
|
|
|
SubsurfaceRole {
|
2018-04-17 09:03:42 +00:00
|
|
|
location: (0, 0),
|
2017-06-04 15:47:37 +00:00
|
|
|
sync: true,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Kind of a rectangle part of a region
|
2017-09-03 17:53:29 +00:00
|
|
|
#[derive(Copy, Clone, Debug)]
|
2017-06-04 15:47:37 +00:00
|
|
|
pub enum RectangleKind {
|
|
|
|
/// This rectangle should be added to the region
|
|
|
|
Add,
|
|
|
|
/// The intersection of this rectangle with the region should
|
|
|
|
/// be removed from the region
|
|
|
|
Subtract,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Description of the contents of a region
|
|
|
|
///
|
|
|
|
/// A region is defined as an union and difference of rectangle.
|
|
|
|
///
|
2018-10-30 12:56:30 +00:00
|
|
|
/// This struct contains an ordered `Vec` containing the rectangles defining
|
|
|
|
/// a region. They should be added or subtracted in this order to compute the
|
2017-06-04 15:47:37 +00:00
|
|
|
/// actual contents of the region.
|
2017-09-03 17:53:29 +00:00
|
|
|
#[derive(Clone, Debug)]
|
2017-06-04 15:47:37 +00:00
|
|
|
pub struct RegionAttributes {
|
|
|
|
/// List of rectangle part of this region
|
|
|
|
pub rects: Vec<(RectangleKind, Rectangle)>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for RegionAttributes {
|
|
|
|
fn default() -> RegionAttributes {
|
|
|
|
RegionAttributes { rects: Vec::new() }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-22 05:03:18 +00:00
|
|
|
impl RegionAttributes {
|
|
|
|
/// Checks whether given point is inside the region.
|
|
|
|
pub fn contains(&self, point: (i32, i32)) -> bool {
|
|
|
|
let mut contains = false;
|
|
|
|
for (kind, rect) in &self.rects {
|
|
|
|
if rect.contains(point) {
|
|
|
|
match kind {
|
|
|
|
RectangleKind::Add => contains = true,
|
|
|
|
RectangleKind::Subtract => contains = false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
contains
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-23 07:43:53 +00:00
|
|
|
/// Access the data of a surface tree from bottom to top
|
2017-06-04 15:47:37 +00:00
|
|
|
///
|
2021-06-23 07:43:53 +00:00
|
|
|
/// You provide three closures, a "filter", a "processor" and a "post filter".
|
|
|
|
///
|
|
|
|
/// The first closure is initially called on a surface to determine if its children
|
|
|
|
/// should be processed as well. It returns a `TraversalAction<T>` reflecting that.
|
|
|
|
///
|
|
|
|
/// The second closure is supposed to do the actual processing. The processing closure for
|
|
|
|
/// a surface may be called after the processing closure of some of its children, depending
|
|
|
|
/// on the stack ordering the client requested. Here the surfaces are processed in the same
|
|
|
|
/// order as they are supposed to be drawn: from the farthest of the screen to the nearest.
|
|
|
|
///
|
|
|
|
/// The third closure is called once all the subtree of a node has been processed, and gives
|
|
|
|
/// an opportunity for early-stopping. If it returns `true` the processing will continue,
|
|
|
|
/// while if it returns `false` it'll stop.
|
|
|
|
///
|
|
|
|
/// The arguments provided to the closures are, in this order:
|
|
|
|
///
|
|
|
|
/// - The surface object itself
|
|
|
|
/// - a mutable reference to its surface attribute data
|
|
|
|
/// - a mutable reference to its role data,
|
|
|
|
/// - a custom value that is passed in a fold-like manner, but only from the output of a parent
|
|
|
|
/// to its children. See [`TraversalAction`] for details.
|
|
|
|
///
|
|
|
|
/// If the surface not managed by the `CompositorGlobal` that provided this token, this
|
|
|
|
/// will panic (having more than one compositor is not supported).
|
|
|
|
pub fn with_surface_tree_upward<F1, F2, F3, T>(
|
|
|
|
surface: &WlSurface,
|
|
|
|
initial: T,
|
|
|
|
filter: F1,
|
|
|
|
processor: F2,
|
|
|
|
post_filter: F3,
|
|
|
|
) where
|
|
|
|
F1: FnMut(&WlSurface, &SurfaceData, &T) -> TraversalAction<T>,
|
|
|
|
F2: FnMut(&WlSurface, &SurfaceData, &T),
|
|
|
|
F3: FnMut(&WlSurface, &SurfaceData, &T) -> bool,
|
|
|
|
{
|
|
|
|
PrivateSurfaceData::map_tree(surface, &initial, filter, processor, post_filter, false);
|
2017-06-04 15:47:37 +00:00
|
|
|
}
|
|
|
|
|
2021-06-23 07:43:53 +00:00
|
|
|
/// Access the data of a surface tree from top to bottom
|
|
|
|
///
|
|
|
|
/// Behavior is the same as [`with_surface_tree_upward`], but the processing is done in the reverse order,
|
|
|
|
/// from the nearest of the screen to the deepest.
|
|
|
|
///
|
|
|
|
/// This would typically be used to find out which surface of a subsurface tree has been clicked for example.
|
|
|
|
pub fn with_surface_tree_downward<F1, F2, F3, T>(
|
|
|
|
surface: &WlSurface,
|
|
|
|
initial: T,
|
|
|
|
filter: F1,
|
|
|
|
processor: F2,
|
|
|
|
post_filter: F3,
|
|
|
|
) where
|
|
|
|
F1: FnMut(&WlSurface, &SurfaceData, &T) -> TraversalAction<T>,
|
|
|
|
F2: FnMut(&WlSurface, &SurfaceData, &T),
|
|
|
|
F3: FnMut(&WlSurface, &SurfaceData, &T) -> bool,
|
|
|
|
{
|
|
|
|
PrivateSurfaceData::map_tree(surface, &initial, filter, processor, post_filter, true);
|
2017-06-13 14:46:31 +00:00
|
|
|
}
|
|
|
|
|
2021-06-23 07:43:53 +00:00
|
|
|
/// Retrieve the parent of this surface
|
|
|
|
///
|
|
|
|
/// Returns `None` is this surface is a root surface
|
|
|
|
pub fn get_parent(surface: &WlSurface) -> Option<WlSurface> {
|
|
|
|
if !surface.as_ref().is_alive() {
|
|
|
|
return None;
|
2017-09-20 07:57:43 +00:00
|
|
|
}
|
2021-06-23 07:43:53 +00:00
|
|
|
PrivateSurfaceData::get_parent(surface)
|
2017-09-20 07:57:43 +00:00
|
|
|
}
|
|
|
|
|
2021-06-23 07:43:53 +00:00
|
|
|
/// Retrieve the children of this surface
|
|
|
|
pub fn get_children(surface: &WlSurface) -> Vec<WlSurface> {
|
|
|
|
if !surface.as_ref().is_alive() {
|
|
|
|
return Vec::new();
|
2017-06-04 15:47:37 +00:00
|
|
|
}
|
2021-06-23 07:43:53 +00:00
|
|
|
PrivateSurfaceData::get_children(surface)
|
2017-09-03 17:53:29 +00:00
|
|
|
}
|
2017-06-04 15:47:37 +00:00
|
|
|
|
2021-06-23 07:43:53 +00:00
|
|
|
/// Check if this subsurface is a synchronized subsurface
|
|
|
|
///
|
|
|
|
/// Returns false if the surface is already dead
|
|
|
|
pub fn is_sync_subsurface(surface: &WlSurface) -> bool {
|
|
|
|
if !surface.as_ref().is_alive() {
|
|
|
|
return false;
|
2017-06-11 12:31:42 +00:00
|
|
|
}
|
2021-06-23 07:43:53 +00:00
|
|
|
self::handlers::is_effectively_sync(surface)
|
2017-09-03 17:53:29 +00:00
|
|
|
}
|
2017-06-11 12:31:42 +00:00
|
|
|
|
2021-06-23 07:43:53 +00:00
|
|
|
/// Get the current role of this surface
|
|
|
|
pub fn get_role(surface: &WlSurface) -> Option<&'static str> {
|
|
|
|
if !surface.as_ref().is_alive() {
|
|
|
|
return None;
|
2017-06-04 15:47:37 +00:00
|
|
|
}
|
2021-06-23 07:43:53 +00:00
|
|
|
PrivateSurfaceData::get_role(surface)
|
|
|
|
}
|
2017-06-04 15:47:37 +00:00
|
|
|
|
2021-06-23 07:43:53 +00:00
|
|
|
/// Register that this surface has given role
|
|
|
|
///
|
|
|
|
/// Fails if the surface already has a role.
|
|
|
|
pub fn give_role(surface: &WlSurface, role: &'static str) -> Result<(), AlreadyHasRole> {
|
|
|
|
if !surface.as_ref().is_alive() {
|
|
|
|
return Ok(());
|
2017-09-03 17:53:29 +00:00
|
|
|
}
|
2021-06-23 07:43:53 +00:00
|
|
|
PrivateSurfaceData::set_role(surface, role)
|
|
|
|
}
|
2017-09-03 17:53:29 +00:00
|
|
|
|
2021-06-23 07:43:53 +00:00
|
|
|
/// Access the states associated to this surface
|
|
|
|
pub fn with_states<F, T>(surface: &WlSurface, f: F) -> Result<T, DeadResource>
|
|
|
|
where
|
|
|
|
F: FnOnce(&SurfaceData) -> T,
|
|
|
|
{
|
|
|
|
if !surface.as_ref().is_alive() {
|
|
|
|
return Err(DeadResource);
|
2017-09-05 10:05:42 +00:00
|
|
|
}
|
2021-06-23 07:43:53 +00:00
|
|
|
Ok(PrivateSurfaceData::with_states(surface, f))
|
|
|
|
}
|
2017-09-03 17:53:29 +00:00
|
|
|
|
2021-06-23 07:43:53 +00:00
|
|
|
/// Retrieve the metadata associated with a `wl_region`
|
|
|
|
///
|
|
|
|
/// If the region is not managed by the `CompositorGlobal` that provided this token, this
|
|
|
|
/// will panic (having more than one compositor is not supported).
|
|
|
|
pub fn get_region_attributes(region: &wl_region::WlRegion) -> RegionAttributes {
|
|
|
|
match region.as_ref().user_data().get::<Mutex<RegionAttributes>>() {
|
|
|
|
Some(mutex) => mutex.lock().unwrap().clone(),
|
|
|
|
None => panic!("Accessing the data of foreign regions is not supported."),
|
2017-06-04 15:47:37 +00:00
|
|
|
}
|
2021-06-23 07:43:53 +00:00
|
|
|
}
|
2017-06-11 12:31:42 +00:00
|
|
|
|
2021-06-23 07:43:53 +00:00
|
|
|
/// Register a commit hook to be invoked on surface commit
|
|
|
|
///
|
|
|
|
/// For its precise semantics, see module-level documentation.
|
|
|
|
pub fn add_commit_hook(surface: &WlSurface, hook: fn(&WlSurface)) {
|
|
|
|
if !surface.as_ref().is_alive() {
|
|
|
|
return;
|
2017-06-11 12:31:42 +00:00
|
|
|
}
|
2021-06-23 07:43:53 +00:00
|
|
|
PrivateSurfaceData::add_commit_hook(surface, hook)
|
2017-06-04 15:47:37 +00:00
|
|
|
}
|
2017-06-04 19:36:18 +00:00
|
|
|
|
2018-12-08 12:40:07 +00:00
|
|
|
/// Create new [`wl_compositor`](wayland_server::protocol::wl_compositor)
|
|
|
|
/// and [`wl_subcompositor`](wayland_server::protocol::wl_subcompositor) globals.
|
2017-06-11 12:33:03 +00:00
|
|
|
///
|
2021-06-23 07:43:53 +00:00
|
|
|
/// It returns the two global handles, in case you wish to remove these globals from
|
|
|
|
/// the event loop in the future.
|
|
|
|
pub fn compositor_init<Impl, L>(
|
2018-04-17 09:03:42 +00:00
|
|
|
display: &mut Display,
|
|
|
|
implem: Impl,
|
|
|
|
logger: L,
|
2017-12-15 17:38:10 +00:00
|
|
|
) -> (
|
2018-04-17 09:03:42 +00:00
|
|
|
Global<wl_compositor::WlCompositor>,
|
|
|
|
Global<wl_subcompositor::WlSubcompositor>,
|
2017-12-15 17:38:10 +00:00
|
|
|
)
|
2017-09-20 07:57:43 +00:00
|
|
|
where
|
|
|
|
L: Into<Option<::slog::Logger>>,
|
2021-06-23 07:43:53 +00:00
|
|
|
Impl: for<'a> FnMut(WlSurface, DispatchData<'a>) + 'static,
|
2017-09-20 07:57:43 +00:00
|
|
|
{
|
2020-07-10 10:50:58 +00:00
|
|
|
let log = crate::slog_or_fallback(logger).new(o!("smithay_module" => "compositor_handler"));
|
2018-04-17 09:03:42 +00:00
|
|
|
let implem = Rc::new(RefCell::new(implem));
|
|
|
|
|
2020-04-05 17:01:08 +00:00
|
|
|
let compositor = display.create_global(
|
|
|
|
4,
|
|
|
|
Filter::new(move |(new_compositor, _version), _, _| {
|
2021-06-23 07:43:53 +00:00
|
|
|
self::handlers::implement_compositor::<Impl>(new_compositor, log.clone(), implem.clone());
|
2020-04-05 17:01:08 +00:00
|
|
|
}),
|
|
|
|
);
|
2018-04-17 09:03:42 +00:00
|
|
|
|
2020-04-05 17:01:08 +00:00
|
|
|
let subcompositor = display.create_global(
|
|
|
|
1,
|
|
|
|
Filter::new(move |(new_subcompositor, _version), _, _| {
|
2021-06-23 07:43:53 +00:00
|
|
|
self::handlers::implement_subcompositor(new_subcompositor);
|
2020-04-05 17:01:08 +00:00
|
|
|
}),
|
|
|
|
);
|
2018-04-17 09:03:42 +00:00
|
|
|
|
2021-06-23 07:43:53 +00:00
|
|
|
(compositor, subcompositor)
|
2017-06-04 19:36:18 +00:00
|
|
|
}
|
2020-01-22 05:03:18 +00:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn region_attributes_empty() {
|
|
|
|
let region = RegionAttributes { rects: vec![] };
|
|
|
|
assert_eq!(region.contains((0, 0)), false);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn region_attributes_add() {
|
|
|
|
let region = RegionAttributes {
|
|
|
|
rects: vec![(
|
|
|
|
RectangleKind::Add,
|
|
|
|
Rectangle {
|
|
|
|
x: 0,
|
|
|
|
y: 0,
|
|
|
|
width: 10,
|
|
|
|
height: 10,
|
|
|
|
},
|
|
|
|
)],
|
|
|
|
};
|
|
|
|
|
|
|
|
assert_eq!(region.contains((0, 0)), true);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn region_attributes_add_subtract() {
|
|
|
|
let region = RegionAttributes {
|
|
|
|
rects: vec![
|
|
|
|
(
|
|
|
|
RectangleKind::Add,
|
|
|
|
Rectangle {
|
|
|
|
x: 0,
|
|
|
|
y: 0,
|
|
|
|
width: 10,
|
|
|
|
height: 10,
|
|
|
|
},
|
|
|
|
),
|
|
|
|
(
|
|
|
|
RectangleKind::Subtract,
|
|
|
|
Rectangle {
|
|
|
|
x: 0,
|
|
|
|
y: 0,
|
|
|
|
width: 5,
|
|
|
|
height: 5,
|
|
|
|
},
|
|
|
|
),
|
|
|
|
],
|
|
|
|
};
|
|
|
|
|
|
|
|
assert_eq!(region.contains((0, 0)), false);
|
|
|
|
assert_eq!(region.contains((5, 5)), true);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn region_attributes_add_subtract_add() {
|
|
|
|
let region = RegionAttributes {
|
|
|
|
rects: vec![
|
|
|
|
(
|
|
|
|
RectangleKind::Add,
|
|
|
|
Rectangle {
|
|
|
|
x: 0,
|
|
|
|
y: 0,
|
|
|
|
width: 10,
|
|
|
|
height: 10,
|
|
|
|
},
|
|
|
|
),
|
|
|
|
(
|
|
|
|
RectangleKind::Subtract,
|
|
|
|
Rectangle {
|
|
|
|
x: 0,
|
|
|
|
y: 0,
|
|
|
|
width: 5,
|
|
|
|
height: 5,
|
|
|
|
},
|
|
|
|
),
|
|
|
|
(
|
|
|
|
RectangleKind::Add,
|
|
|
|
Rectangle {
|
|
|
|
x: 2,
|
|
|
|
y: 2,
|
|
|
|
width: 2,
|
|
|
|
height: 2,
|
|
|
|
},
|
|
|
|
),
|
|
|
|
],
|
|
|
|
};
|
|
|
|
|
|
|
|
assert_eq!(region.contains((0, 0)), false);
|
|
|
|
assert_eq!(region.contains((5, 5)), true);
|
|
|
|
assert_eq!(region.contains((2, 2)), true);
|
|
|
|
}
|
|
|
|
}
|