simple_window/common/protocols_data/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    type Data: 'static;
332
333    /// configure the popup surface
334    ///
335    /// This event asks the popup surface to configure itself given the
336    /// configuration. The configured state should not be applied immediately.
337    /// See xdg_surface.configure for details.
338    ///
339    /// The x and y arguments represent the position the popup was placed at
340    /// given the xdg_positioner rule, relative to the upper left corner of the
341    /// window geometry of the parent surface.
342    ///
343    /// For version 2 or older, the configure event for an xdg_popup is only
344    /// ever sent once for the initial configuration. Starting with version 3,
345    /// it may be sent again if the popup is setup with an xdg_positioner with
346    /// set_reactive requested, or in response to xdg_popup.reposition requests.
347    ///
348    /// # Arguments
349    ///
350    /// - `x`: x position relative to parent surface window geometry
351    /// - `y`: y position relative to parent surface window geometry
352    /// - `width`: window geometry width
353    /// - `height`: window geometry height
354    #[inline]
355    fn configure(
356        &self,
357        _data: &mut Self::Data,
358        _slf: &XdgPopupRef,
359        x: i32,
360        y: i32,
361        width: i32,
362        height: i32,
363    ) {
364        let _ = x;
365        let _ = y;
366        let _ = width;
367        let _ = height;
368    }
369
370    /// popup interaction is done
371    ///
372    /// The popup_done event is sent out when a popup is dismissed by the
373    /// compositor. The client should destroy the xdg_popup object at this
374    /// point.
375    #[inline]
376    fn popup_done(&self, _data: &mut Self::Data, _slf: &XdgPopupRef) {}
377
378    /// signal the completion of a repositioned request
379    ///
380    /// The repositioned event is sent as part of a popup configuration
381    /// sequence, together with xdg_popup.configure and lastly
382    /// xdg_surface.configure to notify the completion of a reposition request.
383    ///
384    /// The repositioned event is to notify about the completion of a
385    /// xdg_popup.reposition request. The token argument is the token passed
386    /// in the xdg_popup.reposition request.
387    ///
388    /// Immediately after this event is emitted, xdg_popup.configure and
389    /// xdg_surface.configure will be sent with the updated size and position,
390    /// as well as a new configure serial.
391    ///
392    /// The client should optionally update the content of the popup, but must
393    /// acknowledge the new popup configuration for the new position to take
394    /// effect. See xdg_surface.ack_configure for details.
395    ///
396    /// # Arguments
397    ///
398    /// - `token`: reposition request token
399    #[inline]
400    fn repositioned(&self, _data: &mut Self::Data, _slf: &XdgPopupRef, token: u32) {
401        let _ = token;
402    }
403}
404
405impl XdgPopupEventHandler for private::NoOpEventHandler {
406    type Data = ();
407}
408
409// SAFETY: - INTERFACE is a valid wl_interface
410//         - mutable_type always returns the same value
411unsafe impl<H> EventHandler for private::EventHandler<H>
412where
413    H: XdgPopupEventHandler,
414{
415    const WL_INTERFACE: &'static wl_interface = &INTERFACE;
416
417    #[inline]
418    fn mutable_type() -> Option<(TypeId, &'static str)> {
419        let id = TypeId::of::<H::Data>();
420        let name = std::any::type_name::<H::Data>();
421        Some((id, name))
422    }
423
424    #[allow(unused_variables)]
425    unsafe fn handle_event(
426        &self,
427        queue: &Queue,
428        data: *mut u8,
429        slf: &UntypedBorrowedProxy,
430        opcode: u32,
431        args: *mut wl_argument,
432    ) {
433        // SAFETY: This function requires that slf has the interface INTERFACE
434        let slf = unsafe { proxy::low_level::from_untyped_borrowed::<XdgPopupRef>(slf) };
435        // SAFETY: This function requires that data is `&mut T` where `T`
436        //         has the type id returned by `Self::mutable_type`, i.e.,
437        //         `T = H::Data`.
438        let data: &mut H::Data = unsafe { &mut *data.cast() };
439        match opcode {
440            0 => {
441                // SAFETY: INTERFACE requires that there are 4 arguments
442                let args = unsafe { &*args.cast::<[wl_argument; 4]>() };
443                // SAFETY: - INTERFACE requires that args[0] contains an int
444                let arg0 = unsafe { args[0].i };
445                // SAFETY: - INTERFACE requires that args[1] contains an int
446                let arg1 = unsafe { args[1].i };
447                // SAFETY: - INTERFACE requires that args[2] contains an int
448                let arg2 = unsafe { args[2].i };
449                // SAFETY: - INTERFACE requires that args[3] contains an int
450                let arg3 = unsafe { args[3].i };
451                self.0.configure(data, slf, arg0, arg1, arg2, arg3);
452            }
453            1 => {
454                self.0.popup_done(data, slf);
455            }
456            2 => {
457                // SAFETY: INTERFACE requires that there are 1 arguments
458                let args = unsafe { &*args.cast::<[wl_argument; 1]>() };
459                // SAFETY: - INTERFACE requires that args[0] contains a uint
460                let arg0 = unsafe { args[0].u };
461                self.0.repositioned(data, slf, arg0);
462            }
463            _ => {
464                invalid_opcode("xdg_popup", opcode);
465            }
466        }
467    }
468}
469
470impl<H> CreateEventHandler<H> for private::ProxyApi
471where
472    H: XdgPopupEventHandler,
473{
474    type EventHandler = private::EventHandler<H>;
475
476    #[inline]
477    fn create_event_handler(handler: H) -> Self::EventHandler {
478        private::EventHandler(handler)
479    }
480}
481
482impl XdgPopup {
483    /// Since when the error.invalid_grab enum variant is available.
484    #[allow(dead_code)]
485    pub const ENM__ERROR_INVALID_GRAB__SINCE: u32 = 1;
486}
487
488#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
489#[allow(dead_code)]
490pub struct XdgPopupError(pub u32);
491
492impl XdgPopupError {
493    /// tried to grab after being mapped
494    #[allow(dead_code)]
495    pub const INVALID_GRAB: Self = Self(0);
496}
497
498impl Debug for XdgPopupError {
499    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
500        let name = match *self {
501            Self::INVALID_GRAB => "INVALID_GRAB",
502            _ => return Debug::fmt(&self.0, f),
503        };
504        f.write_str(name)
505    }
506}
507
508/// Functional event handlers.
509pub mod event_handlers {
510    use super::*;
511
512    /// Event handler for configure events.
513    pub struct Configure<T, F>(F, PhantomData<fn(&mut T)>);
514    impl<T, F> XdgPopupEventHandler for Configure<T, F>
515    where
516        T: 'static,
517        F: Fn(&mut T, &XdgPopupRef, i32, i32, i32, i32),
518    {
519        type Data = T;
520
521        #[inline]
522        fn configure(
523            &self,
524            _data: &mut T,
525            _slf: &XdgPopupRef,
526            x: i32,
527            y: i32,
528            width: i32,
529            height: i32,
530        ) {
531            self.0(_data, _slf, x, y, width, height)
532        }
533    }
534
535    /// Event handler for popup_done events.
536    pub struct PopupDone<T, F>(F, PhantomData<fn(&mut T)>);
537    impl<T, F> XdgPopupEventHandler for PopupDone<T, F>
538    where
539        T: 'static,
540        F: Fn(&mut T, &XdgPopupRef),
541    {
542        type Data = T;
543
544        #[inline]
545        fn popup_done(&self, _data: &mut T, _slf: &XdgPopupRef) {
546            self.0(_data, _slf)
547        }
548    }
549
550    /// Event handler for repositioned events.
551    pub struct Repositioned<T, F>(F, PhantomData<fn(&mut T)>);
552    impl<T, F> XdgPopupEventHandler for Repositioned<T, F>
553    where
554        T: 'static,
555        F: Fn(&mut T, &XdgPopupRef, u32),
556    {
557        type Data = T;
558
559        #[inline]
560        fn repositioned(&self, _data: &mut T, _slf: &XdgPopupRef, token: u32) {
561            self.0(_data, _slf, token)
562        }
563    }
564
565    impl XdgPopup {
566        /// Creates an event handler for configure events.
567        ///
568        /// The event handler ignores all other events.
569        #[allow(dead_code)]
570        pub fn on_configure<T, F>(f: F) -> Configure<T, F>
571        where
572            T: 'static,
573            F: Fn(&mut T, &XdgPopupRef, i32, i32, i32, i32),
574        {
575            Configure(f, PhantomData)
576        }
577
578        /// Creates an event handler for popup_done events.
579        ///
580        /// The event handler ignores all other events.
581        #[allow(dead_code)]
582        pub fn on_popup_done<T, F>(f: F) -> PopupDone<T, F>
583        where
584            T: 'static,
585            F: Fn(&mut T, &XdgPopupRef),
586        {
587            PopupDone(f, PhantomData)
588        }
589
590        /// Creates an event handler for repositioned events.
591        ///
592        /// The event handler ignores all other events.
593        #[allow(dead_code)]
594        pub fn on_repositioned<T, F>(f: F) -> Repositioned<T, F>
595        where
596            T: 'static,
597            F: Fn(&mut T, &XdgPopupRef, u32),
598        {
599            Repositioned(f, PhantomData)
600        }
601    }
602}