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