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}