smithay/wayland/compositor/
mod.rs

1//! Utilities for handling surfaces, subsurfaces and regions
2//!
3//! This module provides automatic handling of surfaces, subsurfaces
4//! and region Wayland objects, by registering an implementation for
5//! for the [`wl_compositor`](wayland_server::protocol::wl_compositor)
6//! and [`wl_subcompositor`](wayland_server::protocol::wl_subcompositor) globals.
7//!
8//! ## Why use this implementation
9//!
10//! This implementation does a simple job: it stores in a coherent way the state of
11//! surface trees with subsurfaces, to provide you direct access to the tree
12//! structure and all surface attributes, and handles the application of double-buffered
13//! state.
14//!
15//! As such, you can, given a root surface with a role requiring it to be displayed,
16//! you can iterate over the whole tree of subsurfaces to recover all the metadata you
17//! need to display the subsurface tree.
18//!
19//! This implementation will not do anything more than present you the metadata specified by the
20//! client in a coherent and practical way. All the logic regarding drawing itself, and
21//! the positioning of windows (surface trees) one relative to another is out of its scope.
22//!
23//! ## How to use it
24//!
25//! ### Initialization
26//!
27//! To initialize this implementation create the [`CompositorState`], store it inside your `State` struct
28//! and implement the [`CompositorHandler`], as shown in this example:
29//!
30//! ```
31//! # extern crate wayland_server;
32//! # #[macro_use] extern crate smithay;
33//! use smithay::delegate_compositor;
34//! use smithay::wayland::compositor::{CompositorState, CompositorClientState, CompositorHandler};
35//!
36//! # struct State { compositor_state: CompositorState }
37//! # struct ClientState { compositor_state: CompositorClientState }
38//! # impl wayland_server::backend::ClientData for ClientState {}
39//! # let mut display = wayland_server::Display::<State>::new().unwrap();
40//! // Create the compositor state
41//! let compositor_state = CompositorState::new::<State>(
42//!     &display.handle(),
43//! );
44//!
45//! // insert the CompositorState into your state
46//! // ..
47//!
48//! // implement the necessary traits
49//! impl CompositorHandler for State {
50//!    fn compositor_state(&mut self) -> &mut CompositorState {
51//!        &mut self.compositor_state
52//!    }
53//!
54//!    fn client_compositor_state<'a>(&self, client: &'a wayland_server::Client) -> &'a CompositorClientState {
55//!        &client.get_data::<ClientState>().unwrap().compositor_state    
56//!    }
57//!
58//!    fn commit(&mut self, surface: &wayland_server::protocol::wl_surface::WlSurface) {
59//!        // called on every buffer commit.
60//!        // .. your implementation ..
61//!    }
62//! }
63//! delegate_compositor!(State);
64//!
65//! // You're now ready to go!
66//! ```
67//!
68//! ### Use the surface states
69//!
70//! The main access to surface states is done through the [`with_states`] function, which
71//! gives you access to the [`SurfaceData`] instance associated with this surface. It acts
72//! as a general purpose container for associating state to a surface, double-buffered or
73//! not. See its documentation for more details.
74//!
75//! ### State application and hooks
76//!
77//! On commit of a surface several steps are taken to update the state of the surface. Actions
78//! are taken by smithay in the following order:
79//!
80//! 1. Pre Commit hooks registered to this surface are invoked. Such hooks can be registered using
81//!    the [`add_pre_commit_hook`] function. They are typically used by protocol extensions that
82//!    add state to a surface and need to check on commit that client did not request an
83//!    illegal state before it is applied on commit.
84//! 2. The pending state is either applied and made current, or cached for later application
85//!    is the surface is a synchronize subsurface. If the current state is applied, state
86//!    of the synchronized children subsurface are applied as well at this point.
87//! 3. Post Commit hooks registered to this surface are invoked. Such hooks can be registered using
88//!    the [`add_post_commit_hook`] function. They are typically used by abstractions that further process
89//!    the state.
90//! 4. Your implementation of [`CompositorHandler::commit`] is invoked, so that you can access
91//!    the new current state of the surface. The state of sync children subsurfaces of your
92//!    surface may have changed as well, so this is the place to check it, using functions
93//!    like [`with_surface_tree_upward`] or [`with_surface_tree_downward`]. On the other hand,
94//!    if the surface is a sync subsurface, its current state will note have changed as
95//!    the result of that commit. You can check if it is using [`is_sync_subsurface`].
96//! 5. If the surface is destroyed, destruction hooks are invoked. Such hooks can be registered
97//!    using the [`add_destruction_hook`] function. They are typically used to cleanup associated
98//!    state.
99//!
100//! ### Surface roles
101//!
102//! The wayland protocol specifies that a surface needs to be assigned a role before it can
103//! be displayed. Furthermore, a surface can only have a single role during its whole lifetime.
104//! Smithay represents this role as a `&'static str` identifier, that can only be set once
105//! on a surface. See [`give_role`] and [`get_role`] for details. This module manages the
106//! subsurface role, which is identified by the string `"subsurface"`.
107
108mod cache;
109mod handlers;
110mod transaction;
111mod tree;
112
113use std::cell::RefCell;
114use std::sync::atomic::Ordering;
115use std::sync::Arc;
116use std::{any::Any, sync::Mutex};
117
118pub use self::cache::{Cacheable, CachedState, MultiCache};
119pub use self::handlers::{RegionUserData, SubsurfaceCachedState, SubsurfaceUserData, SurfaceUserData};
120use self::transaction::TransactionQueue;
121pub use self::transaction::{Barrier, Blocker, BlockerState};
122pub use self::tree::{AlreadyHasRole, TraversalAction};
123use self::tree::{PrivateSurfaceData, SuggestedSurfaceState};
124pub use crate::utils::hook::HookId;
125use crate::utils::Transform;
126use crate::utils::{user_data::UserDataMap, Buffer, Logical, Point, Rectangle};
127use atomic_float::AtomicF64;
128use wayland_server::backend::GlobalId;
129use wayland_server::protocol::wl_compositor::WlCompositor;
130use wayland_server::protocol::wl_subcompositor::WlSubcompositor;
131use wayland_server::protocol::{wl_buffer, wl_callback, wl_output, wl_region, wl_surface::WlSurface};
132use wayland_server::{Client, DisplayHandle, GlobalDispatch, Resource};
133
134/// The role of a subsurface surface.
135pub const SUBSURFACE_ROLE: &str = "subsurface";
136
137/// Description of a part of a surface that
138/// should be considered damaged and needs to be redrawn
139#[derive(Debug, PartialEq, Eq)]
140pub enum Damage {
141    /// A rectangle containing the damaged zone, in surface coordinates
142    Surface(Rectangle<i32, Logical>),
143    /// A rectangle containing the damaged zone, in buffer coordinates
144    ///
145    /// Note: Buffer scaling must be taken into consideration
146    Buffer(Rectangle<i32, Buffer>),
147}
148
149/// The state container associated with a surface
150///
151/// This general-purpose container provides 2 main storages:
152///
153/// - the `data_map` storage has typemap semantics and allows you
154///   to associate and access non-buffered data to the surface
155/// - the `cached_state` storages allows you to associate state to
156///   the surface that follows the double-buffering semantics associated
157///   with the `commit` procedure of surfaces, also with typemap-like
158///   semantics
159///
160/// See the respective documentation of each container for its usage.
161///
162/// By default, all surfaces have a [`SurfaceAttributes`] cached state,
163/// and subsurface also have a [`SubsurfaceCachedState`] state as well.
164#[derive(Debug)]
165pub struct SurfaceData {
166    /// The current role of the surface.
167    ///
168    /// If `None` if the surface has not yet been assigned a role
169    pub role: Option<&'static str>,
170    /// The non-buffered typemap storage of this surface
171    pub data_map: UserDataMap,
172    /// The double-buffered typemap storage of this surface
173    pub cached_state: MultiCache,
174}
175
176/// New buffer assignation for a surface
177#[derive(Debug)]
178pub enum BufferAssignment {
179    /// The surface no longer has a buffer attached to it
180    Removed,
181    /// A new buffer has been attached
182    NewBuffer(wl_buffer::WlBuffer),
183}
184
185/// General state associated with a surface
186///
187/// The fields `buffer`, `damage` and `frame_callbacks` should be
188/// reset (by clearing their contents) once you have adequately
189/// processed them, as their contents are aggregated from commit to commit.
190#[derive(Debug)]
191pub struct SurfaceAttributes {
192    /// Buffer defining the contents of the surface
193    ///
194    /// You are free to set this field to `None` to avoid processing it several
195    /// times. It'll be set to `Some(...)` if the user attaches a buffer (or `NULL`) to
196    /// the surface, and be left to `None` if the user does not attach anything.
197    pub buffer: Option<BufferAssignment>,
198
199    /// Location of the new buffer relative to the previous one
200    ///
201    /// The x and y arguments specify the location of the new pending buffer's upper left corner,
202    /// relative to the current buffer's upper left corner, in surface-local coordinates.
203    ///
204    /// In other words, the x and y, combined with the new surface size define in which directions
205    /// the surface's size changes.
206    ///
207    /// You are free to set this field to `None` to avoid processing it several times.
208    pub buffer_delta: Option<Point<i32, Logical>>,
209
210    /// Scale of the contents of the buffer, for higher-resolution contents.
211    ///
212    /// If it matches the one of the output displaying this surface, no change
213    /// is necessary.
214    pub buffer_scale: i32,
215    /// Transform under which interpret the contents of the buffer
216    ///
217    /// If it matches the one of the output displaying this surface, no change
218    /// is necessary.
219    pub buffer_transform: wl_output::Transform,
220    /// Region of the surface that is guaranteed to be opaque
221    ///
222    /// By default the whole surface is potentially transparent
223    pub opaque_region: Option<RegionAttributes>,
224    /// Region of the surface that is sensitive to user input
225    ///
226    /// By default the whole surface should be sensitive
227    pub input_region: Option<RegionAttributes>,
228    /// Damage rectangle
229    ///
230    /// Hint provided by the client to suggest that only this part
231    /// of the surface was changed and needs to be redrawn
232    pub damage: Vec<Damage>,
233    /// The frame callbacks associated with this surface for the commit
234    ///
235    /// The server must send the notifications so that a client
236    /// will not send excessive updates, while still allowing
237    /// the highest possible update rate for clients that wait for the reply
238    /// before drawing again. The server should give some time for the client
239    /// to draw and commit after sending the frame callback events to let it
240    /// hit the next output refresh.
241    ///
242    /// A server should avoid signaling the frame callbacks if the
243    /// surface is not visible in any way, e.g. the surface is off-screen,
244    /// or completely obscured by other opaque surfaces.
245    ///
246    /// An example possibility would be to trigger it once the frame
247    /// associated with this commit has been displayed on the screen.
248    pub frame_callbacks: Vec<wl_callback::WlCallback>,
249
250    pub(crate) client_scale: f64,
251}
252
253impl Default for SurfaceAttributes {
254    fn default() -> SurfaceAttributes {
255        SurfaceAttributes {
256            buffer: None,
257            buffer_delta: None,
258            buffer_scale: 1,
259            buffer_transform: wl_output::Transform::Normal,
260            opaque_region: None,
261            input_region: None,
262            damage: Vec::new(),
263            frame_callbacks: Vec::new(),
264            client_scale: 1.,
265        }
266    }
267}
268
269/// Kind of a rectangle part of a region
270#[derive(Copy, Clone, Debug)]
271pub enum RectangleKind {
272    /// This rectangle should be added to the region
273    Add,
274    /// The intersection of this rectangle with the region should
275    /// be removed from the region
276    Subtract,
277}
278
279/// Description of the contents of a region
280///
281/// A region is defined as an union and difference of rectangle.
282///
283/// This struct contains an ordered `Vec` containing the rectangles defining
284/// a region. They should be added or subtracted in this order to compute the
285/// actual contents of the region.
286#[derive(Clone, Debug, Default)]
287pub struct RegionAttributes {
288    /// List of rectangle part of this region
289    pub rects: Vec<(RectangleKind, Rectangle<i32, Logical>)>,
290}
291
292impl RegionAttributes {
293    /// Checks whether given point is inside the region.
294    pub fn contains<P: Into<Point<i32, Logical>>>(&self, point: P) -> bool {
295        let point: Point<i32, Logical> = point.into();
296        let mut contains = false;
297        for (kind, rect) in &self.rects {
298            if rect.contains(point) {
299                match kind {
300                    RectangleKind::Add => contains = true,
301                    RectangleKind::Subtract => contains = false,
302                }
303            }
304        }
305        contains
306    }
307}
308
309/// Access the data of a surface tree from bottom to top
310///
311/// You provide three closures, a "filter", a "processor" and a "post filter".
312///
313/// The first closure is initially called on a surface to determine if its children
314/// should be processed as well. It returns a `TraversalAction<T>` reflecting that.
315///
316/// The second closure is supposed to do the actual processing. The processing closure for
317/// a surface may be called after the processing closure of some of its children, depending
318/// on the stack ordering the client requested. Here the surfaces are processed in the same
319/// order as they are supposed to be drawn: from the farthest of the screen to the nearest.
320///
321/// The third closure is called once all the subtree of a node has been processed, and gives
322/// an opportunity for early-stopping. If it returns `true` the processing will continue,
323/// while if it returns `false` it'll stop.
324///
325/// The arguments provided to the closures are, in this order:
326///
327/// - The surface object itself
328/// - a mutable reference to its surface attribute data
329/// - a mutable reference to its role data,
330/// - a custom value that is passed in a fold-like manner, but only from the output of a parent
331///   to its children. See [`TraversalAction`] for details.
332///
333/// If the surface not managed by the `CompositorGlobal` that provided this token, this
334/// will panic (having more than one compositor is not supported).
335pub fn with_surface_tree_upward<F1, F2, F3, T>(
336    surface: &WlSurface,
337    initial: T,
338    filter: F1,
339    processor: F2,
340    post_filter: F3,
341) where
342    F1: FnMut(&WlSurface, &SurfaceData, &T) -> TraversalAction<T>,
343    F2: FnMut(&WlSurface, &SurfaceData, &T),
344    F3: FnMut(&WlSurface, &SurfaceData, &T) -> bool,
345{
346    PrivateSurfaceData::map_tree(surface, &initial, filter, processor, post_filter, false);
347}
348
349/// Access the data of a surface tree from top to bottom
350///
351/// Behavior is the same as [`with_surface_tree_upward`], but the processing is done in the reverse order,
352/// from the nearest of the screen to the deepest.
353///
354/// This would typically be used to find out which surface of a subsurface tree has been clicked for example.
355pub fn with_surface_tree_downward<F1, F2, F3, T>(
356    surface: &WlSurface,
357    initial: T,
358    filter: F1,
359    processor: F2,
360    post_filter: F3,
361) where
362    F1: FnMut(&WlSurface, &SurfaceData, &T) -> TraversalAction<T>,
363    F2: FnMut(&WlSurface, &SurfaceData, &T),
364    F3: FnMut(&WlSurface, &SurfaceData, &T) -> bool,
365{
366    PrivateSurfaceData::map_tree(surface, &initial, filter, processor, post_filter, true);
367}
368
369/// Retrieve the parent of this surface
370///
371/// Returns `None` is this surface is a root surface
372pub fn get_parent(surface: &WlSurface) -> Option<WlSurface> {
373    PrivateSurfaceData::get_parent(surface)
374}
375
376/// Retrieve the children of this surface
377pub fn get_children(surface: &WlSurface) -> Vec<WlSurface> {
378    PrivateSurfaceData::get_children(surface)
379}
380
381/// Check if this subsurface is a synchronized subsurface
382pub fn is_sync_subsurface(surface: &WlSurface) -> bool {
383    self::handlers::is_effectively_sync(surface)
384}
385
386/// Get the current role of this surface
387pub fn get_role(surface: &WlSurface) -> Option<&'static str> {
388    PrivateSurfaceData::get_role(surface)
389}
390
391/// Register that this surface has given role
392///
393/// Fails if the surface already has a role.
394pub fn give_role(surface: &WlSurface, role: &'static str) -> Result<(), AlreadyHasRole> {
395    PrivateSurfaceData::set_role(surface, role)
396}
397
398/// Access the states associated to this surface
399pub fn with_states<F, T>(surface: &WlSurface, f: F) -> T
400where
401    F: FnOnce(&SurfaceData) -> T,
402{
403    PrivateSurfaceData::with_states(surface, f)
404}
405
406/// Send the `scale` and `transform` preferences for the given surface when it supports them.
407///
408/// The new state is only send when it differs from the already cached one on the calling thread.
409pub fn send_surface_state(surface: &WlSurface, data: &SurfaceData, scale: i32, transform: Transform) {
410    if surface.version() < 6 {
411        return;
412    }
413
414    // NOTE we insert default for checks below to work properly.
415    let mut storage = data
416        .data_map
417        .get_or_insert(|| RefCell::new(SuggestedSurfaceState::default()))
418        .borrow_mut();
419
420    if storage.scale != scale {
421        surface.preferred_buffer_scale(scale);
422        storage.scale = scale;
423    }
424
425    let transform = transform.into();
426    if storage.transform != transform {
427        surface.preferred_buffer_transform(transform);
428        storage.transform = transform;
429    }
430}
431
432/// Retrieve the metadata associated with a `wl_region`
433///
434/// If the region is not managed by the `CompositorGlobal` that provided this token, this
435/// will panic (having more than one compositor is not supported).
436pub fn get_region_attributes(region: &wl_region::WlRegion) -> RegionAttributes {
437    match region.data::<RegionUserData>() {
438        Some(data) => data.inner.lock().unwrap().clone(),
439        None => panic!("Accessing the data of foreign regions is not supported."),
440    }
441}
442
443/// Register a pre-commit hook to be invoked on surface commit
444///
445/// It'll be invoked on surface commit, *before* the new state is merged into the current state.
446///
447/// Protocol implementations should use this for error checking, but they should **not** apply
448/// state changes here, since the commit may be further arbitrarily delayed by blockers. Use a
449/// post-commit hook to apply state changes (i.e. copy last acked state to current).
450///
451/// Compositors should use this for adding blockers if needed, e.g. the DMA-BUF readiness blocker.
452pub fn add_pre_commit_hook<D, F>(surface: &WlSurface, hook: F) -> HookId
453where
454    F: Fn(&mut D, &DisplayHandle, &WlSurface) + Send + Sync + 'static,
455    D: 'static,
456{
457    let (user_state_type_id, user_state_type) = surface.data::<SurfaceUserData>().unwrap().user_state_type;
458    assert_eq!(
459        std::any::TypeId::of::<D>(),
460        user_state_type_id,
461        "D has to equal D used in CompositorState::new<D>(), {} != {}",
462        std::any::type_name::<D>(),
463        user_state_type,
464    );
465
466    let hook = move |state: &mut dyn Any, dh: &DisplayHandle, surface: &WlSurface| {
467        let state = state.downcast_mut::<D>().unwrap();
468        hook(state, dh, surface);
469    };
470    PrivateSurfaceData::add_pre_commit_hook(surface, hook)
471}
472
473/// Register a post-commit hook to be invoked on surface commit
474///
475/// It'll be invoked on surface commit, *after* the new state is merged into the current state,
476/// after all commit blockers complete.
477///
478/// Protocol implementations should apply state changes here, i.e. copy last acked state into
479/// current.
480pub fn add_post_commit_hook<D, F>(surface: &WlSurface, hook: F) -> HookId
481where
482    F: Fn(&mut D, &DisplayHandle, &WlSurface) + Send + Sync + 'static,
483    D: 'static,
484{
485    let (user_state_type_id, user_state_type) = surface.data::<SurfaceUserData>().unwrap().user_state_type;
486    assert_eq!(
487        std::any::TypeId::of::<D>(),
488        user_state_type_id,
489        "D has to equal D used in CompositorState::new<D>(), {} != {}",
490        std::any::type_name::<D>(),
491        user_state_type,
492    );
493
494    let hook = move |state: &mut dyn Any, dh: &DisplayHandle, surface: &WlSurface| {
495        let state = state.downcast_mut::<D>().unwrap();
496        hook(state, dh, surface);
497    };
498    PrivateSurfaceData::add_post_commit_hook(surface, hook)
499}
500
501/// Register a destruction hook to be invoked on surface destruction
502///
503/// It'll be invoked when the surface is destroyed (either explicitly by the client or on
504/// client disconnect).
505///
506/// D generic is the compositor state, same as used in `CompositorState::new<D>()`
507pub fn add_destruction_hook<D, F>(surface: &WlSurface, hook: F) -> HookId
508where
509    F: Fn(&mut D, &WlSurface) + Send + Sync + 'static,
510    D: 'static,
511{
512    let (user_state_type_id, user_state_type) = surface.data::<SurfaceUserData>().unwrap().user_state_type;
513    assert_eq!(
514        std::any::TypeId::of::<D>(),
515        user_state_type_id,
516        "D has to equal D used in CompositorState::new<D>(), {} != {}",
517        std::any::type_name::<D>(),
518        user_state_type,
519    );
520
521    let hook = move |state: &mut dyn Any, surface: &WlSurface| {
522        let state = state.downcast_mut::<D>().unwrap();
523        hook(state, surface);
524    };
525    PrivateSurfaceData::add_destruction_hook(surface, hook)
526}
527
528/// Unregister a pre-commit hook
529pub fn remove_pre_commit_hook(surface: &WlSurface, hook_id: HookId) {
530    PrivateSurfaceData::remove_pre_commit_hook(surface, hook_id)
531}
532
533/// Unregister a post-commit hook
534pub fn remove_post_commit_hook(surface: &WlSurface, hook_id: HookId) {
535    PrivateSurfaceData::remove_post_commit_hook(surface, hook_id)
536}
537
538/// Unregister a destruction hook
539pub fn remove_destruction_hook(surface: &WlSurface, hook_id: HookId) {
540    PrivateSurfaceData::remove_destruction_hook(surface, hook_id)
541}
542
543/// Adds a blocker for the currently queued up state changes of the given surface.
544///
545/// Blockers will delay the pending state to be applied on the next commit until
546/// all of them return the state `Released`. Any blocker returning `Cancelled` will
547/// discard all changes.
548///
549/// The module will only evaluate blocker states on commit. If a blocker
550/// becomes ready later, a call to [`CompositorClientState::blocker_cleared`] is necessary
551/// to trigger a re-evaluation.
552pub fn add_blocker(surface: &WlSurface, blocker: impl Blocker + Send + 'static) {
553    PrivateSurfaceData::add_blocker(surface, blocker)
554}
555
556/// Handler trait for compositor
557pub trait CompositorHandler {
558    /// [CompositorState] getter
559    fn compositor_state(&mut self) -> &mut CompositorState;
560    /// [CompositorClientState] getter
561    ///
562    /// The compositor implementation needs some state to be client specific.
563    /// Downstream is expected to store this inside its `ClientData` implementation(s)
564    /// to ensure automatic cleanup of the state, when the client disconnects.
565    fn client_compositor_state<'a>(&self, client: &'a Client) -> &'a CompositorClientState;
566
567    /// New surface handler.
568    ///
569    /// This handler can be used to setup hooks (see [`add_pre_commit_hook`]/[`add_post_commit_hook`]/[`add_destruction_hook`]),
570    /// but not much else. The surface has no role or attached data at this point and cannot be rendered.
571    fn new_surface(&mut self, surface: &WlSurface) {
572        let _ = surface;
573    }
574
575    /// New subsurface handler.
576    ///
577    /// This handler can be used to run extra logic when subsurface is getting created. This
578    /// is an addition to [`new_surface`], which will be run for the subsurface surface anyway.
579    ///
580    /// When your compositor knows beforehand where it'll position subsurfaces it can send
581    /// [`send_surface_state`] to them.
582    ///
583    /// [`new_surface`]: Self::new_surface
584    fn new_subsurface(&mut self, surface: &WlSurface, parent: &WlSurface) {
585        let _ = surface;
586        let _ = parent;
587    }
588
589    /// Surface commit handler
590    ///
591    /// This is called when any changed state from a commit actually becomes visible.
592    /// That might be some time after the actual commit has taken place, if the
593    /// state changes are delayed by an added blocker (see [`add_blocker`]).
594    ///
595    /// If you need to handle a commit as soon as it occurs, you might want to consider
596    /// using a pre-commit hook (see [`add_pre_commit_hook`]).
597    fn commit(&mut self, surface: &WlSurface);
598
599    /// The surface was destroyed.
600    ///
601    /// This allows the compositor to clean up any uses of the surface.
602    fn destroyed(&mut self, _surface: &WlSurface) {}
603}
604
605/// State of a compositor
606#[derive(Debug)]
607pub struct CompositorState {
608    compositor: GlobalId,
609    subcompositor: GlobalId,
610    surfaces: Vec<WlSurface>,
611}
612
613/// Per-client state of a compositor
614#[derive(Debug)]
615pub struct CompositorClientState {
616    queue: Mutex<Option<TransactionQueue>>,
617    scale_override: Arc<AtomicF64>,
618}
619
620impl Default for CompositorClientState {
621    fn default() -> Self {
622        CompositorClientState {
623            queue: Mutex::new(None),
624            scale_override: Arc::new(AtomicF64::new(1.)),
625        }
626    }
627}
628
629impl CompositorClientState {
630    /// To be called, when a previously added blocker (via [`add_blocker`])
631    /// got `Released` or `Cancelled` from being `Pending` previously for any
632    /// surface belonging to this client.
633    pub fn blocker_cleared<D: CompositorHandler + 'static>(&self, state: &mut D, dh: &DisplayHandle) {
634        let transactions = if let Some(queue) = self.queue.lock().unwrap().as_mut() {
635            queue.take_ready()
636        } else {
637            Vec::new()
638        };
639
640        for transaction in transactions {
641            transaction.apply(dh, state)
642        }
643    }
644
645    /// Set an additionally mapping between smithay's `Logical` coordinate space
646    /// and this clients logical coordinate space.
647    ///
648    /// This is used in the same way as if the client was setting the
649    /// surface.buffer_scale on every surface i.e a value of 2.0 will make
650    /// the windows appear smaller on a regular DPI monitor.
651    ///
652    /// Only the minimal set of protocols used by xwayland are guaranteed to be supported.
653    ///
654    /// Buffer sizes are unaffected.
655    pub fn set_client_scale(&self, new_scale: f64) {
656        self.scale_override.store(new_scale, Ordering::Release);
657    }
658
659    /// Get the scale factor of the additional mapping between smithay's `Logical`
660    /// coordinate space and this clients logical coordinate space.
661    ///
662    /// This is mainly intended to support out-of-tree protocol implementations.
663    pub fn client_scale(&self) -> f64 {
664        self.scale_override.load(Ordering::Acquire)
665    }
666
667    pub(crate) fn clone_client_scale(&self) -> Arc<AtomicF64> {
668        self.scale_override.clone()
669    }
670}
671
672impl CompositorState {
673    /// Create new [`wl_compositor`] version 5 and [`wl_subcompositor`] globals.
674    ///
675    /// It returns the two global handles, in case you wish to remove these globals from
676    /// the event loop in the future.
677    ///
678    /// [`wl_compositor`]: wayland_server::protocol::wl_compositor
679    /// [`wl_subcompositor`]: wayland_server::protocol::wl_subcompositor
680    pub fn new<D>(display: &DisplayHandle) -> Self
681    where
682        D: GlobalDispatch<WlCompositor, ()> + GlobalDispatch<WlSubcompositor, ()> + 'static,
683    {
684        Self::new_with_version::<D>(display, 5)
685    }
686
687    /// The same as [`new`], but binds at least version 6 of [`wl_compositor`].
688    ///
689    /// This means that for clients to scale and apply transformation with
690    /// non-default values [`send_surface_state`] must be used.
691    ///
692    /// [`new`]: Self::new
693    /// [`wl_compositor`]: wayland_server::protocol::wl_compositor
694    pub fn new_v6<D>(display: &DisplayHandle) -> Self
695    where
696        D: GlobalDispatch<WlCompositor, ()> + GlobalDispatch<WlSubcompositor, ()> + 'static,
697    {
698        Self::new_with_version::<D>(display, 6)
699    }
700
701    fn new_with_version<D>(display: &DisplayHandle, version: u32) -> Self
702    where
703        D: GlobalDispatch<WlCompositor, ()> + GlobalDispatch<WlSubcompositor, ()> + 'static,
704    {
705        let compositor = display.create_global::<D, WlCompositor, ()>(version, ());
706        let subcompositor = display.create_global::<D, WlSubcompositor, ()>(1, ());
707
708        CompositorState {
709            compositor,
710            subcompositor,
711            surfaces: Vec::new(),
712        }
713    }
714
715    /// Get id of compositor global
716    pub fn compositor_global(&self) -> GlobalId {
717        self.compositor.clone()
718    }
719
720    /// Get id of subcompositor global
721    pub fn subcompositor_global(&self) -> GlobalId {
722        self.subcompositor.clone()
723    }
724}
725
726#[allow(missing_docs)] // TODO
727#[macro_export]
728macro_rules! delegate_compositor {
729    ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
730        const _: () = {
731            use $crate::{
732                reexports::wayland_server::{
733                    delegate_dispatch, delegate_global_dispatch,
734                    protocol::{
735                        wl_callback::WlCallback, wl_compositor::WlCompositor, wl_region::WlRegion,
736                        wl_subcompositor::WlSubcompositor, wl_subsurface::WlSubsurface,
737                        wl_surface::WlSurface,
738                    },
739                },
740                wayland::compositor::{CompositorState, RegionUserData, SubsurfaceUserData, SurfaceUserData},
741            };
742
743            delegate_global_dispatch!(
744                $(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)?
745                $ty: [WlCompositor: ()] => CompositorState
746            );
747            delegate_global_dispatch!(
748                $(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)?
749                $ty: [WlSubcompositor: ()] => CompositorState
750            );
751
752            delegate_dispatch!(
753                $(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)?
754                $ty: [WlCompositor: ()] => CompositorState
755            );
756            delegate_dispatch!(
757                $(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)?
758                $ty: [WlSurface: SurfaceUserData] => CompositorState
759            );
760            delegate_dispatch!(
761                $(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)?
762                $ty: [WlRegion: RegionUserData] => CompositorState
763            );
764            delegate_dispatch!(
765                $(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)?
766                $ty: [WlCallback: ()] => CompositorState
767            );
768
769            delegate_dispatch!(
770                $(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)?
771                $ty: [WlSubcompositor: ()] => CompositorState
772            );
773            delegate_dispatch!(
774                $(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)?
775                $ty: [WlSubsurface: SubsurfaceUserData] => CompositorState
776            );
777        };
778    };
779}
780
781#[cfg(test)]
782mod tests {
783    use super::*;
784
785    #[test]
786    fn region_attributes_empty() {
787        let region = RegionAttributes { rects: vec![] };
788        assert!(!region.contains((0, 0)));
789    }
790
791    #[test]
792    fn region_attributes_add() {
793        let region = RegionAttributes {
794            rects: vec![(RectangleKind::Add, Rectangle::from_size((10, 10).into()))],
795        };
796
797        assert!(region.contains((0, 0)));
798    }
799
800    #[test]
801    fn region_attributes_add_subtract() {
802        let region = RegionAttributes {
803            rects: vec![
804                (RectangleKind::Add, Rectangle::from_size((10, 10).into())),
805                (RectangleKind::Subtract, Rectangle::from_size((5, 5).into())),
806            ],
807        };
808
809        assert!(!region.contains((0, 0)));
810        assert!(region.contains((5, 5)));
811    }
812
813    #[test]
814    fn region_attributes_add_subtract_add() {
815        let region = RegionAttributes {
816            rects: vec![
817                (RectangleKind::Add, Rectangle::from_size((10, 10).into())),
818                (RectangleKind::Subtract, Rectangle::from_size((5, 5).into())),
819                (RectangleKind::Add, Rectangle::new((2, 2).into(), (2, 2).into())),
820            ],
821        };
822
823        assert!(!region.contains((0, 0)));
824        assert!(region.contains((5, 5)));
825        assert!(region.contains((2, 2)));
826    }
827}