1//! XDG shell windows.
23use std::{
4 num::NonZeroU32,
5 sync::{Arc, Weak},
6};
78use crate::reexports::client::{
9 protocol::{wl_output, wl_seat, wl_surface},
10 Connection, Proxy, QueueHandle,
11};
12use crate::reexports::csd_frame::{WindowManagerCapabilities, WindowState};
13use crate::reexports::protocols::{
14 xdg::decoration::zv1::client::zxdg_toplevel_decoration_v1::{self, Mode},
15 xdg::shell::client::{xdg_surface, xdg_toplevel},
16};
1718use crate::shell::WaylandSurface;
1920use self::inner::WindowInner;
2122use super::XdgSurface;
2324pub(super) mod inner;
2526/// Handler for toplevel operations on a [`Window`].
27pub trait WindowHandler: Sized {
28/// Request to close a window.
29 ///
30 /// This request does not destroy the window. You must drop all [`Window`] handles to destroy the window.
31 /// This request may be sent either by the compositor or by some other mechanism (such as client side decorations).
32fn request_close(&mut self, conn: &Connection, qh: &QueueHandle<Self>, window: &Window);
3334/// Apply a suggested surface change.
35 ///
36 /// When this function is called, the compositor is requesting the window's size or state to change.
37 ///
38 /// Internally this function is called when the underlying `xdg_surface` is configured. Any extension
39 /// protocols that interface with xdg-shell are able to be notified that the surface's configure sequence
40 /// is complete by using this function.
41 ///
42 /// # Double buffering
43 ///
44 /// Configure events in Wayland are considered to be double buffered and the state of the window does not
45 /// change until committed.
46fn configure(
47&mut self,
48 conn: &Connection,
49 qh: &QueueHandle<Self>,
50 window: &Window,
51 configure: WindowConfigure,
52 serial: u32,
53 );
54}
5556/// Decoration mode of a window.
57#[derive(Debug, Clone, Copy, PartialEq, Eq)]
58pub enum DecorationMode {
59/// The window should draw client side decorations.
60Client,
6162/// The server will draw window decorations.
63Server,
64}
6566/// A window configure.
67///
68/// A configure describes a compositor request to resize the window or change it's state.
69#[non_exhaustive]
70#[derive(Debug, Clone)]
71pub struct WindowConfigure {
72/// The compositor suggested new size of the window in window geometry coordinates.
73 ///
74 /// If this value is [`None`], you may set the size of the window as you wish.
75pub new_size: (Option<NonZeroU32>, Option<NonZeroU32>),
7677/// Compositor suggested maximum bounds for a window.
78 ///
79 /// This may be used to ensure a window is not created in a way where it will not fit.
80 ///
81 /// If xdg-shell is version 3 or lower, this will always be [`None`].
82pub suggested_bounds: Option<(u32, u32)>,
8384/// The compositor set decoration mode of the window.
85 ///
86 /// This will always be [`DecorationMode::Client`] if server side decorations are not enabled or
87 /// supported.
88pub decoration_mode: DecorationMode,
8990/// The current state of the window.
91 ///
92 /// For more see [`WindowState`] documentation on the flag values.
93pub state: WindowState,
9495/// The capabilities supported by the compositor.
96 ///
97 /// For more see [`WindowManagerCapabilities`] documentation on the flag values.
98pub capabilities: WindowManagerCapabilities,
99}
100101impl WindowConfigure {
102/// Is [`WindowState::MAXIMIZED`] state is set.
103#[inline]
104pub fn is_maximized(&self) -> bool {
105self.state.contains(WindowState::MAXIMIZED)
106 }
107108/// Is [`WindowState::FULLSCREEN`] state is set.
109#[inline]
110pub fn is_fullscreen(&self) -> bool {
111self.state.contains(WindowState::FULLSCREEN)
112 }
113114/// Is [`WindowState::RESIZING`] state is set.
115#[inline]
116pub fn is_resizing(&self) -> bool {
117self.state.contains(WindowState::RESIZING)
118 }
119120/// Is [`WindowState::TILED`] state is set.
121#[inline]
122pub fn is_tiled(&self) -> bool {
123self.state.contains(WindowState::TILED)
124 }
125126/// Is [`WindowState::ACTIVATED`] state is set.
127#[inline]
128pub fn is_activated(&self) -> bool {
129self.state.contains(WindowState::ACTIVATED)
130 }
131132/// Is [`WindowState::TILED_LEFT`] state is set.
133#[inline]
134pub fn is_tiled_left(&self) -> bool {
135self.state.contains(WindowState::TILED_LEFT)
136 }
137138/// Is [`WindowState::TILED_RIGHT`] state is set.
139#[inline]
140pub fn is_tiled_right(&self) -> bool {
141self.state.contains(WindowState::TILED_RIGHT)
142 }
143144/// Is [`WindowState::TILED_TOP`] state is set.
145#[inline]
146pub fn is_tiled_top(&self) -> bool {
147self.state.contains(WindowState::TILED_TOP)
148 }
149150/// Is [`WindowState::TILED_BOTTOM`] state is set.
151#[inline]
152pub fn is_tiled_bottom(&self) -> bool {
153self.state.contains(WindowState::TILED_BOTTOM)
154 }
155}
156157/// Decorations a window is created with.
158#[derive(Debug, Clone, Copy, PartialEq, Eq)]
159pub enum WindowDecorations {
160/// The window should use the decoration mode the server asks for.
161 ///
162 /// The server may ask the client to render with or without client side decorations. If server side
163 /// decorations are not available, client side decorations are drawn instead.
164ServerDefault,
165166/// The window should request server side decorations.
167 ///
168 /// The server may ignore this request and ask the client to render with client side decorations. If
169 /// server side decorations are not available, client side decorations are drawn instead.
170RequestServer,
171172/// The window should request client side decorations.
173 ///
174 /// The server may ignore this request and render server side decorations. If server side decorations are
175 /// not available, client side decorations are drawn.
176RequestClient,
177178/// The window should always draw it's own client side decorations.
179ClientOnly,
180181/// The window should use server side decorations or draw any client side decorations.
182None,
183}
184185#[derive(Debug, Clone)]
186pub struct Window(pub(super) Arc<WindowInner>);
187188impl Window {
189pub fn from_xdg_toplevel(toplevel: &xdg_toplevel::XdgToplevel) -> Option<Window> {
190 toplevel.data::<WindowData>().and_then(|data| data.0.upgrade()).map(Window)
191 }
192193pub fn from_xdg_surface(surface: &xdg_surface::XdgSurface) -> Option<Window> {
194 surface.data::<WindowData>().and_then(|data| data.0.upgrade()).map(Window)
195 }
196197pub fn from_toplevel_decoration(
198 decoration: &zxdg_toplevel_decoration_v1::ZxdgToplevelDecorationV1,
199 ) -> Option<Window> {
200 decoration.data::<WindowData>().and_then(|data| data.0.upgrade()).map(Window)
201 }
202203pub fn show_window_menu(&self, seat: &wl_seat::WlSeat, serial: u32, position: (i32, i32)) {
204self.xdg_toplevel().show_window_menu(seat, serial, position.0, position.1);
205 }
206207pub fn set_title(&self, title: impl Into<String>) {
208self.xdg_toplevel().set_title(title.into());
209 }
210211pub fn set_app_id(&self, app_id: impl Into<String>) {
212self.xdg_toplevel().set_app_id(app_id.into());
213 }
214215pub fn set_parent(&self, parent: Option<&Window>) {
216self.xdg_toplevel().set_parent(parent.map(Window::xdg_toplevel));
217 }
218219pub fn set_maximized(&self) {
220self.xdg_toplevel().set_maximized()
221 }
222223pub fn unset_maximized(&self) {
224self.xdg_toplevel().unset_maximized()
225 }
226227pub fn set_minimized(&self) {
228self.xdg_toplevel().set_minimized()
229 }
230231pub fn set_fullscreen(&self, output: Option<&wl_output::WlOutput>) {
232self.xdg_toplevel().set_fullscreen(output)
233 }
234235pub fn unset_fullscreen(&self) {
236self.xdg_toplevel().unset_fullscreen()
237 }
238239/// Requests the window should use the specified decoration mode.
240 ///
241 /// A mode of [`None`] indicates that the window does not care what type of decorations are used.
242 ///
243 /// The compositor will respond with a [`configure`](WindowHandler::configure). The configure will
244 /// indicate whether the window's decoration mode has changed.
245 ///
246 /// # Configure loops
247 ///
248 /// You should avoid sending multiple decoration mode requests to ensure you do not enter a configure loop.
249pub fn request_decoration_mode(&self, mode: Option<DecorationMode>) {
250if let Some(toplevel_decoration) = &self.0.toplevel_decoration {
251match mode {
252Some(DecorationMode::Client) => toplevel_decoration.set_mode(Mode::ClientSide),
253Some(DecorationMode::Server) => toplevel_decoration.set_mode(Mode::ServerSide),
254None => toplevel_decoration.unset_mode(),
255 }
256 }
257 }
258259pub fn move_(&self, seat: &wl_seat::WlSeat, serial: u32) {
260self.xdg_toplevel()._move(seat, serial)
261 }
262263pub fn resize(&self, seat: &wl_seat::WlSeat, serial: u32, edges: xdg_toplevel::ResizeEdge) {
264self.xdg_toplevel().resize(seat, serial, edges)
265 }
266267// Double buffered window state
268269pub fn set_min_size(&self, min_size: Option<(u32, u32)>) {
270let min_size = min_size.unwrap_or_default();
271self.xdg_toplevel().set_min_size(min_size.0 as i32, min_size.1 as i32);
272 }
273274/// # Protocol errors
275 ///
276 /// The maximum size of the window may not be smaller than the minimum size.
277pub fn set_max_size(&self, max_size: Option<(u32, u32)>) {
278let max_size = max_size.unwrap_or_default();
279self.xdg_toplevel().set_max_size(max_size.0 as i32, max_size.1 as i32);
280 }
281282// Other
283284/// Returns the underlying xdg toplevel wrapped by this window.
285pub fn xdg_toplevel(&self) -> &xdg_toplevel::XdgToplevel {
286&self.0.xdg_toplevel
287 }
288}
289290impl WaylandSurface for Window {
291fn wl_surface(&self) -> &wl_surface::WlSurface {
292self.0.xdg_surface.wl_surface()
293 }
294}
295296impl XdgSurface for Window {
297fn xdg_surface(&self) -> &xdg_surface::XdgSurface {
298self.0.xdg_surface.xdg_surface()
299 }
300}
301302impl PartialEq for Window {
303fn eq(&self, other: &Self) -> bool {
304 Arc::ptr_eq(&self.0, &other.0)
305 }
306}
307308#[derive(Debug, Clone)]
309pub struct WindowData(pub(crate) Weak<WindowInner>);
310311#[macro_export]
312macro_rules! delegate_xdg_window {
313 ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
314$crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
315$crate::reexports::protocols::xdg::shell::client::xdg_surface::XdgSurface: $crate::shell::xdg::window::WindowData
316] => $crate::shell::xdg::XdgShell);
317$crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
318$crate::reexports::protocols::xdg::shell::client::xdg_toplevel::XdgToplevel: $crate::shell::xdg::window::WindowData
319] => $crate::shell::xdg::XdgShell);
320 };
321}