simple_window/common/protocols/xdg_shell/
xdg_popup.rs

1//! short-lived, popup surfaces for menus
2//!
3//! A popup surface is a short-lived, temporary surface. It can be used to
4//! implement for example menus, popovers, tooltips and other similar user
5//! interface concepts.
6//!
7//! A popup can be made to take an explicit grab. See xdg_popup.grab for
8//! details.
9//!
10//! When the popup is dismissed, a popup_done event will be sent out, and at
11//! the same time the surface will be unmapped. See the xdg_popup.popup_done
12//! event for details.
13//!
14//! Explicitly destroying the xdg_popup object will also dismiss the popup and
15//! unmap the surface. Clients that want to dismiss the popup when another
16//! surface of their own is clicked should dismiss the popup using the destroy
17//! request.
18//!
19//! A newly created xdg_popup will be stacked on top of all previously created
20//! xdg_popup surfaces associated with the same xdg_toplevel.
21//!
22//! The parent of an xdg_popup must be mapped (see the xdg_surface
23//! description) before the xdg_popup itself.
24//!
25//! The client must call wl_surface.commit on the corresponding wl_surface
26//! for the xdg_popup state to take effect.
27
28use {super::super::all_types::*, ::wl_client::builder::prelude::*};
29
30static INTERFACE: wl_interface = wl_interface {
31    name: c"xdg_popup".as_ptr(),
32    version: 6,
33    method_count: 3,
34    methods: {
35        static MESSAGES: [wl_message; 3] = [
36            wl_message {
37                name: c"destroy".as_ptr(),
38                signature: c"".as_ptr(),
39                types: {
40                    static TYPES: [Option<&'static wl_interface>; 0] = [];
41                    TYPES.as_ptr().cast()
42                },
43            },
44            wl_message {
45                name: c"grab".as_ptr(),
46                signature: c"ou".as_ptr(),
47                types: {
48                    static TYPES: [Option<&'static wl_interface>; 2] =
49                        [Some(WlSeat::WL_INTERFACE), None];
50                    TYPES.as_ptr().cast()
51                },
52            },
53            wl_message {
54                name: c"reposition".as_ptr(),
55                signature: c"ou".as_ptr(),
56                types: {
57                    static TYPES: [Option<&'static wl_interface>; 2] =
58                        [Some(XdgPositioner::WL_INTERFACE), None];
59                    TYPES.as_ptr().cast()
60                },
61            },
62        ];
63        MESSAGES.as_ptr()
64    },
65    event_count: 3,
66    events: {
67        static MESSAGES: [wl_message; 3] = [
68            wl_message {
69                name: c"configure".as_ptr(),
70                signature: c"iiii".as_ptr(),
71                types: {
72                    static TYPES: [Option<&'static wl_interface>; 4] = [None, None, None, None];
73                    TYPES.as_ptr().cast()
74                },
75            },
76            wl_message {
77                name: c"popup_done".as_ptr(),
78                signature: c"".as_ptr(),
79                types: {
80                    static TYPES: [Option<&'static wl_interface>; 0] = [];
81                    TYPES.as_ptr().cast()
82                },
83            },
84            wl_message {
85                name: c"repositioned".as_ptr(),
86                signature: c"u".as_ptr(),
87                types: {
88                    static TYPES: [Option<&'static wl_interface>; 1] = [None];
89                    TYPES.as_ptr().cast()
90                },
91            },
92        ];
93        MESSAGES.as_ptr()
94    },
95};
96
97/// An owned xdg_popup proxy.
98///
99/// See the documentation of [the module][self] for the interface description.
100#[derive(Clone, Eq, PartialEq)]
101#[repr(transparent)]
102pub struct XdgPopup {
103    /// This proxy has the interface INTERFACE.
104    proxy: UntypedOwnedProxy,
105}
106
107/// A borrowed xdg_popup proxy.
108///
109/// See the documentation of [the module][self] for the interface description.
110#[derive(Eq, PartialEq)]
111#[repr(transparent)]
112pub struct XdgPopupRef {
113    /// This proxy has the interface INTERFACE.
114    proxy: UntypedBorrowedProxy,
115}
116
117// SAFETY: XdgPopup is a transparent wrapper around UntypedOwnedProxy
118unsafe impl UntypedOwnedProxyWrapper for XdgPopup {}
119
120// SAFETY: - INTERFACE is a valid wl_interface
121//         - The only invariant is that self.proxy has a compatible interface
122unsafe impl OwnedProxy for XdgPopup {
123    const INTERFACE: &'static str = "xdg_popup";
124    const WL_INTERFACE: &'static wl_interface = &INTERFACE;
125    const NO_OP_EVENT_HANDLER: Self::NoOpEventHandler =
126        private::EventHandler(private::NoOpEventHandler);
127    const MAX_VERSION: u32 = 6;
128
129    type Borrowed = XdgPopupRef;
130    type Api = private::ProxyApi;
131    type NoOpEventHandler = private::EventHandler<private::NoOpEventHandler>;
132}
133
134// SAFETY: XdgPopupRef is a transparent wrapper around UntypedBorrowedProxy
135unsafe impl UntypedBorrowedProxyWrapper for XdgPopupRef {}
136
137// SAFETY: - The only invariant is that self.proxy has a compatible interface
138unsafe impl BorrowedProxy for XdgPopupRef {
139    type Owned = XdgPopup;
140}
141
142impl Deref for XdgPopup {
143    type Target = XdgPopupRef;
144
145    fn deref(&self) -> &Self::Target {
146        proxy::low_level::deref(self)
147    }
148}
149
150mod private {
151    pub struct ProxyApi;
152
153    #[allow(dead_code)]
154    pub struct EventHandler<H>(pub(super) H);
155
156    #[allow(dead_code)]
157    pub struct NoOpEventHandler;
158}
159
160impl Debug for XdgPopup {
161    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
162        write!(f, "xdg_popup#{}", self.proxy.id())
163    }
164}
165
166impl Debug for XdgPopupRef {
167    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
168        write!(f, "xdg_popup#{}", self.proxy.id())
169    }
170}
171
172impl PartialEq<XdgPopupRef> for XdgPopup {
173    fn eq(&self, other: &XdgPopupRef) -> bool {
174        self.proxy == other.proxy
175    }
176}
177
178impl PartialEq<XdgPopup> for XdgPopupRef {
179    fn eq(&self, other: &XdgPopup) -> bool {
180        self.proxy == other.proxy
181    }
182}
183
184#[allow(dead_code)]
185impl XdgPopup {
186    /// Since when the destroy request is available.
187    #[allow(dead_code)]
188    pub const REQ__DESTROY__SINCE: u32 = 1;
189
190    /// remove xdg_popup interface
191    ///
192    /// This destroys the popup. Explicitly destroying the xdg_popup
193    /// object will also dismiss the popup, and unmap the surface.
194    ///
195    /// If this xdg_popup is not the "topmost" popup, the
196    /// xdg_wm_base.not_the_topmost_popup protocol error will be sent.
197    #[inline]
198    pub fn destroy(&self) {
199        let mut args = [];
200        // SAFETY: - self.proxy has the interface INTERFACE
201        //         - 0 < INTERFACE.method_count = 3
202        //         - the request signature is ``
203        unsafe {
204            self.proxy.send_destructor(0, &mut args);
205        }
206    }
207}
208
209#[allow(dead_code)]
210impl XdgPopupRef {
211    /// make the popup take an explicit grab
212    ///
213    /// This request makes the created popup take an explicit grab. An explicit
214    /// grab will be dismissed when the user dismisses the popup, or when the
215    /// client destroys the xdg_popup. This can be done by the user clicking
216    /// outside the surface, using the keyboard, or even locking the screen
217    /// through closing the lid or a timeout.
218    ///
219    /// If the compositor denies the grab, the popup will be immediately
220    /// dismissed.
221    ///
222    /// This request must be used in response to some sort of user action like a
223    /// button press, key press, or touch down event. The serial number of the
224    /// event should be passed as 'serial'.
225    ///
226    /// The parent of a grabbing popup must either be an xdg_toplevel surface or
227    /// another xdg_popup with an explicit grab. If the parent is another
228    /// xdg_popup it means that the popups are nested, with this popup now being
229    /// the topmost popup.
230    ///
231    /// Nested popups must be destroyed in the reverse order they were created
232    /// in, e.g. the only popup you are allowed to destroy at all times is the
233    /// topmost one.
234    ///
235    /// When compositors choose to dismiss a popup, they may dismiss every
236    /// nested grabbing popup as well. When a compositor dismisses popups, it
237    /// will follow the same dismissing order as required from the client.
238    ///
239    /// If the topmost grabbing popup is destroyed, the grab will be returned to
240    /// the parent of the popup, if that parent previously had an explicit grab.
241    ///
242    /// If the parent is a grabbing popup which has already been dismissed, this
243    /// popup will be immediately dismissed. If the parent is a popup that did
244    /// not take an explicit grab, an error will be raised.
245    ///
246    /// During a popup grab, the client owning the grab will receive pointer
247    /// and touch events for all their surfaces as normal (similar to an
248    /// "owner-events" grab in X11 parlance), while the top most grabbing popup
249    /// will always have keyboard focus.
250    ///
251    /// # Arguments
252    ///
253    /// - `seat`: the wl_seat of the user event
254    /// - `serial`: the serial of the user event
255    #[inline]
256    pub fn grab(&self, seat: &WlSeatRef, serial: u32) {
257        let (arg0, arg1) = (seat, serial);
258        let obj0_lock = proxy::lock(arg0);
259        let obj0 = check_argument_proxy("seat", obj0_lock.wl_proxy());
260        let mut args = [wl_argument { o: obj0 }, wl_argument { u: arg1 }];
261        // SAFETY: - self.proxy has the interface INTERFACE
262        //         - 1 < INTERFACE.method_count = 3
263        //         - the request signature is `ou`
264        unsafe {
265            self.proxy.send_request(1, &mut args);
266        }
267    }
268
269    /// recalculate the popup's location
270    ///
271    /// Reposition an already-mapped popup. The popup will be placed given the
272    /// details in the passed xdg_positioner object, and a
273    /// xdg_popup.repositioned followed by xdg_popup.configure and
274    /// xdg_surface.configure will be emitted in response. Any parameters set
275    /// by the previous positioner will be discarded.
276    ///
277    /// The passed token will be sent in the corresponding
278    /// xdg_popup.repositioned event. The new popup position will not take
279    /// effect until the corresponding configure event is acknowledged by the
280    /// client. See xdg_popup.repositioned for details. The token itself is
281    /// opaque, and has no other special meaning.
282    ///
283    /// If multiple reposition requests are sent, the compositor may skip all
284    /// but the last one.
285    ///
286    /// If the popup is repositioned in response to a configure event for its
287    /// parent, the client should send an xdg_positioner.set_parent_configure
288    /// and possibly an xdg_positioner.set_parent_size request to allow the
289    /// compositor to properly constrain the popup.
290    ///
291    /// If the popup is repositioned together with a parent that is being
292    /// resized, but not in response to a configure event, the client should
293    /// send an xdg_positioner.set_parent_size request.
294    ///
295    /// # Arguments
296    ///
297    /// - `positioner`:
298    /// - `token`: reposition request token
299    #[inline]
300    pub fn reposition(&self, positioner: &XdgPositionerRef, token: u32) {
301        let (arg0, arg1) = (positioner, token);
302        let obj0_lock = proxy::lock(arg0);
303        let obj0 = check_argument_proxy("positioner", obj0_lock.wl_proxy());
304        let mut args = [wl_argument { o: obj0 }, wl_argument { u: arg1 }];
305        // SAFETY: - self.proxy has the interface INTERFACE
306        //         - 2 < INTERFACE.method_count = 3
307        //         - the request signature is `ou`
308        unsafe {
309            self.proxy.send_request(2, &mut args);
310        }
311    }
312}
313
314impl XdgPopup {
315    /// Since when the configure event is available.
316    #[allow(dead_code)]
317    pub const EVT__CONFIGURE__SINCE: u32 = 1;
318
319    /// Since when the popup_done event is available.
320    #[allow(dead_code)]
321    pub const EVT__POPUP_DONE__SINCE: u32 = 1;
322
323    /// Since when the repositioned event is available.
324    #[allow(dead_code)]
325    pub const EVT__REPOSITIONED__SINCE: u32 = 3;
326}
327
328/// An event handler for [XdgPopup] proxies.
329#[allow(dead_code)]
330pub trait XdgPopupEventHandler {
331    /// configure the popup surface
332    ///
333    /// This event asks the popup surface to configure itself given the
334    /// configuration. The configured state should not be applied immediately.
335    /// See xdg_surface.configure for details.
336    ///
337    /// The x and y arguments represent the position the popup was placed at
338    /// given the xdg_positioner rule, relative to the upper left corner of the
339    /// window geometry of the parent surface.
340    ///
341    /// For version 2 or older, the configure event for an xdg_popup is only
342    /// ever sent once for the initial configuration. Starting with version 3,
343    /// it may be sent again if the popup is setup with an xdg_positioner with
344    /// set_reactive requested, or in response to xdg_popup.reposition requests.
345    ///
346    /// # Arguments
347    ///
348    /// - `x`: x position relative to parent surface window geometry
349    /// - `y`: y position relative to parent surface window geometry
350    /// - `width`: window geometry width
351    /// - `height`: window geometry height
352    #[inline]
353    fn configure(&self, _slf: &XdgPopupRef, x: i32, y: i32, width: i32, height: i32) {
354        let _ = x;
355        let _ = y;
356        let _ = width;
357        let _ = height;
358    }
359
360    /// popup interaction is done
361    ///
362    /// The popup_done event is sent out when a popup is dismissed by the
363    /// compositor. The client should destroy the xdg_popup object at this
364    /// point.
365    #[inline]
366    fn popup_done(&self, _slf: &XdgPopupRef) {}
367
368    /// signal the completion of a repositioned request
369    ///
370    /// The repositioned event is sent as part of a popup configuration
371    /// sequence, together with xdg_popup.configure and lastly
372    /// xdg_surface.configure to notify the completion of a reposition request.
373    ///
374    /// The repositioned event is to notify about the completion of a
375    /// xdg_popup.reposition request. The token argument is the token passed
376    /// in the xdg_popup.reposition request.
377    ///
378    /// Immediately after this event is emitted, xdg_popup.configure and
379    /// xdg_surface.configure will be sent with the updated size and position,
380    /// as well as a new configure serial.
381    ///
382    /// The client should optionally update the content of the popup, but must
383    /// acknowledge the new popup configuration for the new position to take
384    /// effect. See xdg_surface.ack_configure for details.
385    ///
386    /// # Arguments
387    ///
388    /// - `token`: reposition request token
389    #[inline]
390    fn repositioned(&self, _slf: &XdgPopupRef, token: u32) {
391        let _ = token;
392    }
393}
394
395impl XdgPopupEventHandler for private::NoOpEventHandler {}
396
397// SAFETY: - INTERFACE is a valid wl_interface
398unsafe impl<H> EventHandler for private::EventHandler<H>
399where
400    H: XdgPopupEventHandler,
401{
402    const WL_INTERFACE: &'static wl_interface = &INTERFACE;
403
404    #[allow(unused_variables)]
405    unsafe fn handle_event(
406        &self,
407        queue: &Queue,
408        data: *mut u8,
409        slf: &UntypedBorrowedProxy,
410        opcode: u32,
411        args: *mut wl_argument,
412    ) {
413        // SAFETY: This function requires that slf has the interface INTERFACE
414        let slf = unsafe { proxy::low_level::from_untyped_borrowed::<XdgPopupRef>(slf) };
415        match opcode {
416            0 => {
417                // SAFETY: INTERFACE requires that there are 4 arguments
418                let args = unsafe { &*args.cast::<[wl_argument; 4]>() };
419                // SAFETY: - INTERFACE requires that args[0] contains an int
420                let arg0 = unsafe { args[0].i };
421                // SAFETY: - INTERFACE requires that args[1] contains an int
422                let arg1 = unsafe { args[1].i };
423                // SAFETY: - INTERFACE requires that args[2] contains an int
424                let arg2 = unsafe { args[2].i };
425                // SAFETY: - INTERFACE requires that args[3] contains an int
426                let arg3 = unsafe { args[3].i };
427                self.0.configure(slf, arg0, arg1, arg2, arg3);
428            }
429            1 => {
430                self.0.popup_done(slf);
431            }
432            2 => {
433                // SAFETY: INTERFACE requires that there are 1 arguments
434                let args = unsafe { &*args.cast::<[wl_argument; 1]>() };
435                // SAFETY: - INTERFACE requires that args[0] contains a uint
436                let arg0 = unsafe { args[0].u };
437                self.0.repositioned(slf, arg0);
438            }
439            _ => {
440                invalid_opcode("xdg_popup", opcode);
441            }
442        }
443    }
444}
445
446impl<H> CreateEventHandler<H> for private::ProxyApi
447where
448    H: XdgPopupEventHandler,
449{
450    type EventHandler = private::EventHandler<H>;
451
452    #[inline]
453    fn create_event_handler(handler: H) -> Self::EventHandler {
454        private::EventHandler(handler)
455    }
456}
457
458impl XdgPopup {
459    /// Since when the error.invalid_grab enum variant is available.
460    #[allow(dead_code)]
461    pub const ENM__ERROR_INVALID_GRAB__SINCE: u32 = 1;
462}
463
464#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
465#[allow(dead_code)]
466pub struct XdgPopupError(pub u32);
467
468impl XdgPopupError {
469    /// tried to grab after being mapped
470    #[allow(dead_code)]
471    pub const INVALID_GRAB: Self = Self(0);
472}
473
474impl Debug for XdgPopupError {
475    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
476        let name = match *self {
477            Self::INVALID_GRAB => "INVALID_GRAB",
478            _ => return Debug::fmt(&self.0, f),
479        };
480        f.write_str(name)
481    }
482}
483
484/// Functional event handlers.
485pub mod event_handlers {
486    use super::*;
487
488    /// Event handler for configure events.
489    pub struct Configure<F>(F);
490    impl<F> XdgPopupEventHandler for Configure<F>
491    where
492        F: Fn(&XdgPopupRef, i32, i32, i32, i32),
493    {
494        #[inline]
495        fn configure(&self, _slf: &XdgPopupRef, x: i32, y: i32, width: i32, height: i32) {
496            self.0(_slf, x, y, width, height)
497        }
498    }
499
500    /// Event handler for popup_done events.
501    pub struct PopupDone<F>(F);
502    impl<F> XdgPopupEventHandler for PopupDone<F>
503    where
504        F: Fn(&XdgPopupRef),
505    {
506        #[inline]
507        fn popup_done(&self, _slf: &XdgPopupRef) {
508            self.0(_slf)
509        }
510    }
511
512    /// Event handler for repositioned events.
513    pub struct Repositioned<F>(F);
514    impl<F> XdgPopupEventHandler for Repositioned<F>
515    where
516        F: Fn(&XdgPopupRef, u32),
517    {
518        #[inline]
519        fn repositioned(&self, _slf: &XdgPopupRef, token: u32) {
520            self.0(_slf, token)
521        }
522    }
523
524    impl XdgPopup {
525        /// Creates an event handler for configure events.
526        ///
527        /// The event handler ignores all other events.
528        #[allow(dead_code)]
529        pub fn on_configure<F>(f: F) -> Configure<F>
530        where
531            F: Fn(&XdgPopupRef, i32, i32, i32, i32),
532        {
533            Configure(f)
534        }
535
536        /// Creates an event handler for popup_done events.
537        ///
538        /// The event handler ignores all other events.
539        #[allow(dead_code)]
540        pub fn on_popup_done<F>(f: F) -> PopupDone<F>
541        where
542            F: Fn(&XdgPopupRef),
543        {
544            PopupDone(f)
545        }
546
547        /// Creates an event handler for repositioned events.
548        ///
549        /// The event handler ignores all other events.
550        #[allow(dead_code)]
551        pub fn on_repositioned<F>(f: F) -> Repositioned<F>
552        where
553            F: Fn(&XdgPopupRef, u32),
554        {
555            Repositioned(f)
556        }
557    }
558}