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}