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 | |
22 | use std::num::NonZeroU32; |
23 | use std::time::Duration; |
24 | |
25 | use bitflags::bitflags; |
26 | use wayland_backend::client::ObjectId; |
27 | |
28 | #[doc (inline)] |
29 | pub use cursor_icon::{CursorIcon, ParseError as CursorIconParseError}; |
30 | |
31 | /// The interface for the client side decorations. |
32 | pub 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)] |
158 | pub 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)] |
181 | pub 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 | |
195 | bitflags! { |
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 | |
240 | bitflags! { |
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)] |
261 | pub 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 | } |
281 | |