simple_window/common/protocols/xdg_shell/
xdg_wm_base.rs

1//! create desktop-style surfaces
2//!
3//! The xdg_wm_base interface is exposed as a global object enabling clients
4//! to turn their wl_surfaces into windows in a desktop environment. It
5//! defines the basic functionality needed for clients and the compositor to
6//! create windows that can be dragged, resized, maximized, etc, as well as
7//! creating transient windows such as popup menus.
8
9use {super::super::all_types::*, ::wl_client::builder::prelude::*};
10
11static INTERFACE: wl_interface = wl_interface {
12    name: c"xdg_wm_base".as_ptr(),
13    version: 6,
14    method_count: 4,
15    methods: {
16        static MESSAGES: [wl_message; 4] = [
17            wl_message {
18                name: c"destroy".as_ptr(),
19                signature: c"".as_ptr(),
20                types: {
21                    static TYPES: [Option<&'static wl_interface>; 0] = [];
22                    TYPES.as_ptr().cast()
23                },
24            },
25            wl_message {
26                name: c"create_positioner".as_ptr(),
27                signature: c"n".as_ptr(),
28                types: {
29                    static TYPES: [Option<&'static wl_interface>; 1] =
30                        [Some(XdgPositioner::WL_INTERFACE)];
31                    TYPES.as_ptr().cast()
32                },
33            },
34            wl_message {
35                name: c"get_xdg_surface".as_ptr(),
36                signature: c"no".as_ptr(),
37                types: {
38                    static TYPES: [Option<&'static wl_interface>; 2] = [
39                        Some(XdgSurface::WL_INTERFACE),
40                        Some(WlSurface::WL_INTERFACE),
41                    ];
42                    TYPES.as_ptr().cast()
43                },
44            },
45            wl_message {
46                name: c"pong".as_ptr(),
47                signature: c"u".as_ptr(),
48                types: {
49                    static TYPES: [Option<&'static wl_interface>; 1] = [None];
50                    TYPES.as_ptr().cast()
51                },
52            },
53        ];
54        MESSAGES.as_ptr()
55    },
56    event_count: 1,
57    events: {
58        static MESSAGES: [wl_message; 1] = [wl_message {
59            name: c"ping".as_ptr(),
60            signature: c"u".as_ptr(),
61            types: {
62                static TYPES: [Option<&'static wl_interface>; 1] = [None];
63                TYPES.as_ptr().cast()
64            },
65        }];
66        MESSAGES.as_ptr()
67    },
68};
69
70/// An owned xdg_wm_base proxy.
71///
72/// See the documentation of [the module][self] for the interface description.
73#[derive(Clone, Eq, PartialEq)]
74#[repr(transparent)]
75pub struct XdgWmBase {
76    /// This proxy has the interface INTERFACE.
77    proxy: UntypedOwnedProxy,
78}
79
80/// A borrowed xdg_wm_base proxy.
81///
82/// See the documentation of [the module][self] for the interface description.
83#[derive(Eq, PartialEq)]
84#[repr(transparent)]
85pub struct XdgWmBaseRef {
86    /// This proxy has the interface INTERFACE.
87    proxy: UntypedBorrowedProxy,
88}
89
90// SAFETY: XdgWmBase is a transparent wrapper around UntypedOwnedProxy
91unsafe impl UntypedOwnedProxyWrapper for XdgWmBase {}
92
93// SAFETY: - INTERFACE is a valid wl_interface
94//         - The only invariant is that self.proxy has a compatible interface
95unsafe impl OwnedProxy for XdgWmBase {
96    const INTERFACE: &'static str = "xdg_wm_base";
97    const WL_INTERFACE: &'static wl_interface = &INTERFACE;
98    const NO_OP_EVENT_HANDLER: Self::NoOpEventHandler =
99        private::EventHandler(private::NoOpEventHandler);
100    const MAX_VERSION: u32 = 6;
101
102    type Borrowed = XdgWmBaseRef;
103    type Api = private::ProxyApi;
104    type NoOpEventHandler = private::EventHandler<private::NoOpEventHandler>;
105}
106
107// SAFETY: XdgWmBaseRef is a transparent wrapper around UntypedBorrowedProxy
108unsafe impl UntypedBorrowedProxyWrapper for XdgWmBaseRef {}
109
110// SAFETY: - The only invariant is that self.proxy has a compatible interface
111unsafe impl BorrowedProxy for XdgWmBaseRef {
112    type Owned = XdgWmBase;
113}
114
115impl Deref for XdgWmBase {
116    type Target = XdgWmBaseRef;
117
118    fn deref(&self) -> &Self::Target {
119        proxy::low_level::deref(self)
120    }
121}
122
123mod private {
124    pub struct ProxyApi;
125
126    #[allow(dead_code)]
127    pub struct EventHandler<H>(pub(super) H);
128
129    #[allow(dead_code)]
130    pub struct NoOpEventHandler;
131}
132
133impl Debug for XdgWmBase {
134    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
135        write!(f, "xdg_wm_base#{}", self.proxy.id())
136    }
137}
138
139impl Debug for XdgWmBaseRef {
140    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
141        write!(f, "xdg_wm_base#{}", self.proxy.id())
142    }
143}
144
145impl PartialEq<XdgWmBaseRef> for XdgWmBase {
146    fn eq(&self, other: &XdgWmBaseRef) -> bool {
147        self.proxy == other.proxy
148    }
149}
150
151impl PartialEq<XdgWmBase> for XdgWmBaseRef {
152    fn eq(&self, other: &XdgWmBase) -> bool {
153        self.proxy == other.proxy
154    }
155}
156
157#[allow(dead_code)]
158impl XdgWmBase {
159    /// Since when the destroy request is available.
160    #[allow(dead_code)]
161    pub const REQ__DESTROY__SINCE: u32 = 1;
162
163    /// destroy xdg_wm_base
164    ///
165    /// Destroy this xdg_wm_base object.
166    ///
167    /// Destroying a bound xdg_wm_base object while there are surfaces
168    /// still alive created by this xdg_wm_base object instance is illegal
169    /// and will result in a defunct_surfaces error.
170    #[inline]
171    pub fn destroy(&self) {
172        let mut args = [];
173        // SAFETY: - self.proxy has the interface INTERFACE
174        //         - 0 < INTERFACE.method_count = 4
175        //         - the request signature is ``
176        unsafe {
177            self.proxy.send_destructor(0, &mut args);
178        }
179    }
180
181    /// Since when the create_positioner request is available.
182    #[allow(dead_code)]
183    pub const REQ__CREATE_POSITIONER__SINCE: u32 = 1;
184
185    /// create a positioner object
186    ///
187    /// Create a positioner object. A positioner object is used to position
188    /// surfaces relative to some parent surface. See the interface description
189    /// and xdg_surface.get_popup for details.
190    #[inline]
191    pub fn create_positioner(&self) -> XdgPositioner {
192        let mut args = [wl_argument { n: 0 }];
193        // SAFETY: - self.proxy has the interface INTERFACE
194        //         - 1 < INTERFACE.method_count = 4
195        //         - the request signature is `n`
196        //         - OwnedProxy::WL_INTERFACE is always a valid interface
197        let data = unsafe {
198            self.proxy
199                .send_constructor::<false>(1, &mut args, XdgPositioner::WL_INTERFACE, None)
200        };
201        // SAFETY: data has the interface XdgPositioner::WL_INTERFACE
202        unsafe { proxy::low_level::from_untyped_owned(data) }
203    }
204
205    /// Since when the get_xdg_surface request is available.
206    #[allow(dead_code)]
207    pub const REQ__GET_XDG_SURFACE__SINCE: u32 = 1;
208
209    /// create a shell surface from a surface
210    ///
211    /// This creates an xdg_surface for the given surface. While xdg_surface
212    /// itself is not a role, the corresponding surface may only be assigned
213    /// a role extending xdg_surface, such as xdg_toplevel or xdg_popup. It is
214    /// illegal to create an xdg_surface for a wl_surface which already has an
215    /// assigned role and this will result in a role error.
216    ///
217    /// This creates an xdg_surface for the given surface. An xdg_surface is
218    /// used as basis to define a role to a given surface, such as xdg_toplevel
219    /// or xdg_popup. It also manages functionality shared between xdg_surface
220    /// based surface roles.
221    ///
222    /// See the documentation of xdg_surface for more details about what an
223    /// xdg_surface is and how it is used.
224    ///
225    /// # Arguments
226    ///
227    /// - `surface`:
228    #[inline]
229    pub fn get_xdg_surface(&self, surface: &WlSurfaceRef) -> XdgSurface {
230        let (arg1,) = (surface,);
231        let obj1_lock = proxy::lock(arg1);
232        let obj1 = check_argument_proxy("surface", obj1_lock.wl_proxy());
233        let mut args = [wl_argument { n: 0 }, wl_argument { o: obj1 }];
234        // SAFETY: - self.proxy has the interface INTERFACE
235        //         - 2 < INTERFACE.method_count = 4
236        //         - the request signature is `no`
237        //         - OwnedProxy::WL_INTERFACE is always a valid interface
238        let data = unsafe {
239            self.proxy
240                .send_constructor::<false>(2, &mut args, XdgSurface::WL_INTERFACE, None)
241        };
242        // SAFETY: data has the interface XdgSurface::WL_INTERFACE
243        unsafe { proxy::low_level::from_untyped_owned(data) }
244    }
245}
246
247#[allow(dead_code)]
248impl XdgWmBaseRef {
249    /// create a positioner object
250    ///
251    /// Create a positioner object. A positioner object is used to position
252    /// surfaces relative to some parent surface. See the interface description
253    /// and xdg_surface.get_popup for details.
254    ///
255    /// # Arguments
256    ///
257    /// - `_queue`: The queue that the returned proxy is assigned to.
258    #[inline]
259    pub fn create_positioner(&self, _queue: &Queue) -> XdgPositioner {
260        let mut args = [wl_argument { n: 0 }];
261        // SAFETY: - self.proxy has the interface INTERFACE
262        //         - 1 < INTERFACE.method_count = 4
263        //         - the request signature is `n`
264        //         - OwnedProxy::WL_INTERFACE is always a valid interface
265        let data = unsafe {
266            self.proxy
267                .send_constructor(_queue, 1, &mut args, XdgPositioner::WL_INTERFACE, None)
268        };
269        // SAFETY: data has the interface XdgPositioner::WL_INTERFACE
270        unsafe { proxy::low_level::from_untyped_owned(data) }
271    }
272
273    /// create a shell surface from a surface
274    ///
275    /// This creates an xdg_surface for the given surface. While xdg_surface
276    /// itself is not a role, the corresponding surface may only be assigned
277    /// a role extending xdg_surface, such as xdg_toplevel or xdg_popup. It is
278    /// illegal to create an xdg_surface for a wl_surface which already has an
279    /// assigned role and this will result in a role error.
280    ///
281    /// This creates an xdg_surface for the given surface. An xdg_surface is
282    /// used as basis to define a role to a given surface, such as xdg_toplevel
283    /// or xdg_popup. It also manages functionality shared between xdg_surface
284    /// based surface roles.
285    ///
286    /// See the documentation of xdg_surface for more details about what an
287    /// xdg_surface is and how it is used.
288    ///
289    /// # Arguments
290    ///
291    /// - `_queue`: The queue that the returned proxy is assigned to.
292    /// - `surface`:
293    #[inline]
294    pub fn get_xdg_surface(&self, _queue: &Queue, surface: &WlSurfaceRef) -> XdgSurface {
295        let (arg1,) = (surface,);
296        let obj1_lock = proxy::lock(arg1);
297        let obj1 = check_argument_proxy("surface", obj1_lock.wl_proxy());
298        let mut args = [wl_argument { n: 0 }, wl_argument { o: obj1 }];
299        // SAFETY: - self.proxy has the interface INTERFACE
300        //         - 2 < INTERFACE.method_count = 4
301        //         - the request signature is `no`
302        //         - OwnedProxy::WL_INTERFACE is always a valid interface
303        let data = unsafe {
304            self.proxy
305                .send_constructor(_queue, 2, &mut args, XdgSurface::WL_INTERFACE, None)
306        };
307        // SAFETY: data has the interface XdgSurface::WL_INTERFACE
308        unsafe { proxy::low_level::from_untyped_owned(data) }
309    }
310
311    /// respond to a ping event
312    ///
313    /// A client must respond to a ping event with a pong request or
314    /// the client may be deemed unresponsive. See xdg_wm_base.ping
315    /// and xdg_wm_base.error.unresponsive.
316    ///
317    /// # Arguments
318    ///
319    /// - `serial`: serial of the ping event
320    #[inline]
321    pub fn pong(&self, serial: u32) {
322        let (arg0,) = (serial,);
323        let mut args = [wl_argument { u: arg0 }];
324        // SAFETY: - self.proxy has the interface INTERFACE
325        //         - 3 < INTERFACE.method_count = 4
326        //         - the request signature is `u`
327        unsafe {
328            self.proxy.send_request(3, &mut args);
329        }
330    }
331}
332
333impl XdgWmBase {
334    /// Since when the ping event is available.
335    #[allow(dead_code)]
336    pub const EVT__PING__SINCE: u32 = 1;
337}
338
339/// An event handler for [XdgWmBase] proxies.
340#[allow(dead_code)]
341pub trait XdgWmBaseEventHandler {
342    /// check if the client is alive
343    ///
344    /// The ping event asks the client if it's still alive. Pass the
345    /// serial specified in the event back to the compositor by sending
346    /// a "pong" request back with the specified serial. See xdg_wm_base.pong.
347    ///
348    /// Compositors can use this to determine if the client is still
349    /// alive. It's unspecified what will happen if the client doesn't
350    /// respond to the ping request, or in what timeframe. Clients should
351    /// try to respond in a reasonable amount of time. The “unresponsive”
352    /// error is provided for compositors that wish to disconnect unresponsive
353    /// clients.
354    ///
355    /// A compositor is free to ping in any way it wants, but a client must
356    /// always respond to any xdg_wm_base object it created.
357    ///
358    /// # Arguments
359    ///
360    /// - `serial`: pass this to the pong request
361    #[inline]
362    fn ping(&self, _slf: &XdgWmBaseRef, serial: u32) {
363        let _ = serial;
364    }
365}
366
367impl XdgWmBaseEventHandler for private::NoOpEventHandler {}
368
369// SAFETY: - INTERFACE is a valid wl_interface
370unsafe impl<H> EventHandler for private::EventHandler<H>
371where
372    H: XdgWmBaseEventHandler,
373{
374    const WL_INTERFACE: &'static wl_interface = &INTERFACE;
375
376    #[allow(unused_variables)]
377    unsafe fn handle_event(
378        &self,
379        queue: &Queue,
380        data: *mut u8,
381        slf: &UntypedBorrowedProxy,
382        opcode: u32,
383        args: *mut wl_argument,
384    ) {
385        // SAFETY: This function requires that slf has the interface INTERFACE
386        let slf = unsafe { proxy::low_level::from_untyped_borrowed::<XdgWmBaseRef>(slf) };
387        match opcode {
388            0 => {
389                // SAFETY: INTERFACE requires that there are 1 arguments
390                let args = unsafe { &*args.cast::<[wl_argument; 1]>() };
391                // SAFETY: - INTERFACE requires that args[0] contains a uint
392                let arg0 = unsafe { args[0].u };
393                self.0.ping(slf, arg0);
394            }
395            _ => {
396                invalid_opcode("xdg_wm_base", opcode);
397            }
398        }
399    }
400}
401
402impl<H> CreateEventHandler<H> for private::ProxyApi
403where
404    H: XdgWmBaseEventHandler,
405{
406    type EventHandler = private::EventHandler<H>;
407
408    #[inline]
409    fn create_event_handler(handler: H) -> Self::EventHandler {
410        private::EventHandler(handler)
411    }
412}
413
414impl XdgWmBase {
415    /// Since when the error.role enum variant is available.
416    #[allow(dead_code)]
417    pub const ENM__ERROR_ROLE__SINCE: u32 = 1;
418    /// Since when the error.defunct_surfaces enum variant is available.
419    #[allow(dead_code)]
420    pub const ENM__ERROR_DEFUNCT_SURFACES__SINCE: u32 = 1;
421    /// Since when the error.not_the_topmost_popup enum variant is available.
422    #[allow(dead_code)]
423    pub const ENM__ERROR_NOT_THE_TOPMOST_POPUP__SINCE: u32 = 1;
424    /// Since when the error.invalid_popup_parent enum variant is available.
425    #[allow(dead_code)]
426    pub const ENM__ERROR_INVALID_POPUP_PARENT__SINCE: u32 = 1;
427    /// Since when the error.invalid_surface_state enum variant is available.
428    #[allow(dead_code)]
429    pub const ENM__ERROR_INVALID_SURFACE_STATE__SINCE: u32 = 1;
430    /// Since when the error.invalid_positioner enum variant is available.
431    #[allow(dead_code)]
432    pub const ENM__ERROR_INVALID_POSITIONER__SINCE: u32 = 1;
433    /// Since when the error.unresponsive enum variant is available.
434    #[allow(dead_code)]
435    pub const ENM__ERROR_UNRESPONSIVE__SINCE: u32 = 1;
436}
437
438#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
439#[allow(dead_code)]
440pub struct XdgWmBaseError(pub u32);
441
442impl XdgWmBaseError {
443    /// given wl_surface has another role
444    #[allow(dead_code)]
445    pub const ROLE: Self = Self(0);
446
447    /// xdg_wm_base was destroyed before children
448    #[allow(dead_code)]
449    pub const DEFUNCT_SURFACES: Self = Self(1);
450
451    /// the client tried to map or destroy a non-topmost popup
452    #[allow(dead_code)]
453    pub const NOT_THE_TOPMOST_POPUP: Self = Self(2);
454
455    /// the client specified an invalid popup parent surface
456    #[allow(dead_code)]
457    pub const INVALID_POPUP_PARENT: Self = Self(3);
458
459    /// the client provided an invalid surface state
460    #[allow(dead_code)]
461    pub const INVALID_SURFACE_STATE: Self = Self(4);
462
463    /// the client provided an invalid positioner
464    #[allow(dead_code)]
465    pub const INVALID_POSITIONER: Self = Self(5);
466
467    /// the client didn’t respond to a ping event in time
468    #[allow(dead_code)]
469    pub const UNRESPONSIVE: Self = Self(6);
470}
471
472impl Debug for XdgWmBaseError {
473    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
474        let name = match *self {
475            Self::ROLE => "ROLE",
476            Self::DEFUNCT_SURFACES => "DEFUNCT_SURFACES",
477            Self::NOT_THE_TOPMOST_POPUP => "NOT_THE_TOPMOST_POPUP",
478            Self::INVALID_POPUP_PARENT => "INVALID_POPUP_PARENT",
479            Self::INVALID_SURFACE_STATE => "INVALID_SURFACE_STATE",
480            Self::INVALID_POSITIONER => "INVALID_POSITIONER",
481            Self::UNRESPONSIVE => "UNRESPONSIVE",
482            _ => return Debug::fmt(&self.0, f),
483        };
484        f.write_str(name)
485    }
486}
487
488/// Functional event handlers.
489pub mod event_handlers {
490    use super::*;
491
492    /// Event handler for ping events.
493    pub struct Ping<F>(F);
494    impl<F> XdgWmBaseEventHandler for Ping<F>
495    where
496        F: Fn(&XdgWmBaseRef, u32),
497    {
498        #[inline]
499        fn ping(&self, _slf: &XdgWmBaseRef, serial: u32) {
500            self.0(_slf, serial)
501        }
502    }
503
504    impl XdgWmBase {
505        /// Creates an event handler for ping events.
506        ///
507        /// The event handler ignores all other events.
508        #[allow(dead_code)]
509        pub fn on_ping<F>(f: F) -> Ping<F>
510        where
511            F: Fn(&XdgWmBaseRef, u32),
512        {
513            Ping(f)
514        }
515    }
516}