wayland_csd_frame/
lib.rs

1#![deny(rust_2018_idioms)]
2#![deny(rustdoc::broken_intra_doc_links)]
3#![deny(unsafe_op_in_unsafe_fn)]
4#![deny(improper_ctypes, improper_ctypes_definitions)]
5#![deny(clippy::all)]
6#![deny(missing_debug_implementations)]
7#![deny(missing_docs)]
8#![forbid(unsafe_code)]
9#![cfg_attr(feature = "cargo-clippy", deny(warnings))]
10#![cfg_attr(docsrs, feature(doc_auto_cfg))]
11
12//! The interface for wayland client side decorations (CSD).
13//!
14//! The crate is intended to be used by libraries providing client
15//! side decorations for the xdg-shell protocol.
16//!
17//! Examples could be found in [`client toolkit`] and [`sctk-adwaita`].
18//!
19//! [`client toolkit`]: https://github.com/smithay/client-toolkit
20//! [`sctk-adwaita`]: https://github.com/PolyMeilex/sctk-adwaita
21
22use std::num::NonZeroU32;
23use std::time::Duration;
24
25use bitflags::bitflags;
26use wayland_backend::client::ObjectId;
27
28#[doc(inline)]
29pub use cursor_icon::{CursorIcon, ParseError as CursorIconParseError};
30
31/// The interface for the client side decorations.
32pub trait DecorationsFrame: Sized {
33    /// Emulate click on the decorations.
34    ///
35    /// The `click` is a variant of click to use, see [`FrameClick`] for more
36    /// information. `timestamp` is the time when event happened.
37    ///
38    /// The return value is a [`FrameAction`] you should apply, this action
39    /// could be ignored.
40    ///
41    /// The location of the click is the one passed to
42    /// [`Self::click_point_moved`].
43    fn on_click(
44        &mut self,
45        timestamp: Duration,
46        click: FrameClick,
47        pressed: bool,
48    ) -> Option<FrameAction>;
49
50    /// Emulate pointer moved event on the decorations frame.
51    ///
52    /// The `x` and `y` are location in the surface local coordinates relative
53    /// to the `surface`. `timestamp` is the time when event happened.
54    ///
55    /// The return value is the new cursor icon you should apply to provide
56    /// better visual feedback for the user. However, you might want to
57    /// ignore it, if you're using touch events to drive the movements.
58    fn click_point_moved(
59        &mut self,
60        timestamp: Duration,
61        surface_id: &ObjectId,
62        x: f64,
63        y: f64,
64    ) -> Option<CursorIcon>;
65
66    /// All clicks left the decorations.
67    ///
68    /// This function should be called when input leaves the decorations.
69    fn click_point_left(&mut self);
70
71    /// Update the state of the frame.
72    ///
73    /// The state is usually obtained from the `xdg_toplevel::configure` event.
74    fn update_state(&mut self, state: WindowState);
75
76    /// Update the window manager capabilites.
77    ///
78    /// The capabilites are usually obtained from the
79    /// `xdg_toplevel::wm_capabilities` event.
80    fn update_wm_capabilities(&mut self, wm_capabilities: WindowManagerCapabilities);
81
82    /// Resize the window to the new size.
83    ///
84    /// The size must be without the borders, as in [`Self::subtract_borders]`
85    /// were used on it.
86    ///
87    /// **Note:** The [`Self::update_state`] and
88    /// [`Self::update_wm_capabilities`] **must be** applied before calling
89    /// this function.
90    ///
91    /// # Panics
92    ///
93    /// Panics when resizing the hidden frame.
94    fn resize(&mut self, width: NonZeroU32, height: NonZeroU32);
95
96    /// Set the scaling of the decorations frame.
97    ///
98    /// If the decorations frame is not supporting fractional scaling it'll
99    /// `ceil` the scaling factor.
100    fn set_scaling_factor(&mut self, scale_factor: f64);
101
102    /// Return the coordinates of the top-left corner of the borders relative to
103    /// the content.
104    ///
105    /// Values **must** thus be non-positive.
106    fn location(&self) -> (i32, i32);
107
108    /// Subtract the borders from the given `width` and `height`.
109    ///
110    /// `None` will be returned for the particular dimension when the given
111    /// value for it was too small.
112    fn subtract_borders(
113        &self,
114        width: NonZeroU32,
115        height: NonZeroU32,
116    ) -> (Option<NonZeroU32>, Option<NonZeroU32>);
117
118    /// Add the borders to the given `width` and `height`.
119    ///
120    /// Passing zero for both width and height could be used to get the size
121    /// of the decorations frame.
122    fn add_borders(&self, width: u32, height: u32) -> (u32, u32);
123
124    /// Whether the given frame is dirty and should be redrawn.
125    fn is_dirty(&self) -> bool;
126
127    /// Set the frame as hidden.
128    ///
129    /// The frame **must be** visible by default.
130    fn set_hidden(&mut self, hidden: bool);
131
132    /// Get the frame hidden state.
133    ///
134    /// Get the state of the last [`DecorationsFrame::set_hidden`].
135    fn is_hidden(&self) -> bool;
136
137    /// Mark the frame as resizable.
138    ///
139    /// By default the frame is resizable.
140    fn set_resizable(&mut self, resizable: bool);
141
142    /// Draw the decorations frame.
143    ///
144    /// Return `true` when the main surface must be redrawn as well. This
145    /// usually happens when `sync` is being set on the internal subsurfaces and
146    /// they've changed their size.
147    ///
148    /// The user of the frame **must** commit the base surface afterwards.
149    fn draw(&mut self) -> bool;
150
151    /// Set the frames title.
152    fn set_title(&mut self, title: impl Into<String>);
153}
154
155/// The Frame action user should perform in responce to mouse click events.
156#[non_exhaustive]
157#[derive(Debug, Clone, Copy)]
158pub enum FrameAction {
159    /// The window should be minimized.
160    Minimize,
161    /// The window should be maximized.
162    Maximize,
163    /// The window should be unmaximized.
164    UnMaximize,
165    /// The window should be closed.
166    Close,
167    /// An interactive move should be started.
168    Move,
169    /// An interactive resize should be started with the provided edge.
170    Resize(ResizeEdge),
171    /// Show window menu.
172    ///
173    /// The coordinates are relative to the base surface, as in should be
174    /// directly passed to the `xdg_toplevel::show_window_menu`.
175    ShowMenu(i32, i32),
176}
177
178/// The user clicked or touched the decoractions frame.
179#[non_exhaustive]
180#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
181pub enum FrameClick {
182    /// The user done normal click, likely with left mouse button or single
183    /// finger touch.
184    Normal,
185
186    /// The user done right mouse click or some touch sequence that was treated
187    /// as alternate click.
188    ///
189    /// The alternate click exists solely to provide alternative action, like
190    /// show window menu when doing right mouse button cilck on the header
191    /// decorations, nothing more.
192    Alternate,
193}
194
195bitflags! {
196    /// The configured state of the window.
197    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
198    pub struct WindowState: u16 {
199        /// The surface is maximized. The window geometry specified in the
200        /// configure event must be obeyed by the client. The client should
201        /// draw without shadow or other decoration outside of the window
202        /// geometry.
203        const MAXIMIZED    = 0b0000_0000_0000_0001;
204        /// The surface is fullscreen. The window geometry specified in the
205        /// configure event is a maximum; the client cannot resize beyond it.
206        /// For a surface to cover the whole fullscreened area, the geometry
207        /// dimensions must be obeyed by the client. For more details, see
208        /// xdg_toplevel.set_fullscreen.
209        const FULLSCREEN   = 0b0000_0000_0000_0010;
210        /// The surface is being resized. The window geometry specified in the
211        /// configure event is a maximum; the client cannot resize beyond it.
212        /// Clients that have aspect ratio or cell sizing configuration can use
213        /// a smaller size, however.
214        const RESIZING     = 0b0000_0000_0000_0100;
215        /// Client window decorations should be painted as if the window is
216        /// active. Do not assume this means that the window actually has
217        /// keyboard or pointer focus.
218        const ACTIVATED    = 0b0000_0000_0000_1000;
219        /// The window is currently in a tiled layout and the left edge is
220        /// considered to be adjacent to another part of the tiling grid.
221        const TILED_LEFT   = 0b0000_0000_0001_0000;
222        /// The window is currently in a tiled layout and the right edge is
223        /// considered to be adjacent to another part of the tiling grid.
224        const TILED_RIGHT  = 0b0000_0000_0010_0000;
225        /// The window is currently in a tiled layout and the top edge is
226        /// considered to be adjacent to another part of the tiling grid.
227        const TILED_TOP    = 0b0000_0000_0100_0000;
228        /// The window is currently in a tiled layout and the bottom edge is
229        /// considered to be adjacent to another part of the tiling grid.
230        const TILED_BOTTOM = 0b0000_0000_1000_0000;
231        /// An alias for all tiled bits set.
232        const TILED        = Self::TILED_TOP.bits() | Self::TILED_LEFT.bits() | Self::TILED_RIGHT.bits() | Self::TILED_BOTTOM.bits();
233        /// The surface is currently not ordinarily being repainted; for example
234        /// because its content is occluded by another window, or its outputs are
235        /// switched off due to screen locking.
236        const SUSPENDED    = 0b0000_0001_0000_0000;
237    }
238}
239
240bitflags! {
241    /// The capabilities of the window manager.
242    ///
243    /// This is a hint to hide UI elements which provide functionality
244    /// not supported by compositor.
245    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
246    pub struct WindowManagerCapabilities : u16 {
247        /// `show_window_menu` is available.
248        const WINDOW_MENU = 0b0000_0000_0000_0001;
249        /// Window can be maximized and unmaximized.
250        const MAXIMIZE = 0b0000_0000_0000_0010;
251        /// Window can be fullscreened and unfullscreened.
252        const FULLSCREEN = 0b0000_0000_0000_0100;
253        /// Window could be minimized.
254        const MINIMIZE = 0b0000_0000_0000_1000;
255    }
256}
257
258/// Which edge or corner is being dragged.
259#[non_exhaustive]
260#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
261pub enum ResizeEdge {
262    /// Nothing is being dragged.
263    None,
264    /// The top edge is being dragged.
265    Top,
266    /// The bottom edge is being dragged.
267    Bottom,
268    /// The left edge is being dragged.
269    Left,
270    /// The top left corner is being dragged.
271    TopLeft,
272    /// The bottom left corner is being dragged.
273    BottomLeft,
274    /// The right edge is being dragged.
275    Right,
276    /// The top right corner is being dragged.
277    TopRight,
278    /// The bottom right corner is being dragged.
279    BottomRight,
280}