smithay/wayland/shell/xdg/handlers/surface/
popup.rs
1use std::sync::atomic::Ordering;
2
3use crate::{
4 input::SeatHandler,
5 utils::Serial,
6 wayland::{
7 compositor,
8 shell::xdg::{SurfaceCachedState, XdgPopupSurfaceData, XdgPositionerUserData},
9 },
10};
11
12use wayland_protocols::xdg::shell::server::xdg_popup::{self, XdgPopup};
13
14use wayland_server::{backend::ClientId, DataInit, Dispatch, DisplayHandle, Resource};
15
16use super::{PopupConfigure, XdgShellHandler, XdgShellState, XdgShellSurfaceUserData, XdgSurfaceUserData};
17
18impl<D> Dispatch<XdgPopup, XdgShellSurfaceUserData, D> for XdgShellState
19where
20 D: Dispatch<XdgPopup, XdgShellSurfaceUserData>,
21 D: XdgShellHandler,
22 D: SeatHandler,
23 D: 'static,
24{
25 fn request(
26 state: &mut D,
27 _client: &wayland_server::Client,
28 popup: &XdgPopup,
29 request: xdg_popup::Request,
30 data: &XdgShellSurfaceUserData,
31 _dh: &DisplayHandle,
32 _data_init: &mut DataInit<'_, D>,
33 ) {
34 match request {
35 xdg_popup::Request::Destroy => {
36 if let Some(surface_data) = data.xdg_surface.data::<XdgSurfaceUserData>() {
37 surface_data.has_active_role.store(false, Ordering::Release);
38 }
39 }
40 xdg_popup::Request::Grab { seat, serial } => {
41 let handle = crate::wayland::shell::xdg::PopupSurface {
42 wl_surface: data.wl_surface.clone(),
43 shell_surface: popup.clone(),
44 };
45
46 let serial = Serial::from(serial);
47
48 XdgShellHandler::grab(state, handle, seat, serial);
49 }
50 xdg_popup::Request::Reposition { positioner, token } => {
51 let handle = crate::wayland::shell::xdg::PopupSurface {
52 wl_surface: data.wl_surface.clone(),
53 shell_surface: popup.clone(),
54 };
55
56 let positioner_data = *positioner
57 .data::<XdgPositionerUserData>()
58 .unwrap()
59 .inner
60 .lock()
61 .unwrap();
62
63 XdgShellHandler::reposition_request(state, handle, positioner_data, token);
64 }
65 _ => unreachable!(),
66 }
67 }
68
69 fn destroyed(state: &mut D, _client_id: ClientId, xdg_popup: &XdgPopup, data: &XdgShellSurfaceUserData) {
70 data.alive_tracker.destroy_notify();
71
72 if let Some(index) = state
74 .xdg_shell_state()
75 .known_popups
76 .iter()
77 .position(|pop| pop.shell_surface.id() == xdg_popup.id())
78 {
79 let popup = state.xdg_shell_state().known_popups.remove(index);
80 let surface = popup.wl_surface().clone();
81 XdgShellHandler::popup_destroyed(state, popup);
82 compositor::with_states(&surface, |states| {
83 *states
84 .data_map
85 .get::<XdgPopupSurfaceData>()
86 .unwrap()
87 .lock()
88 .unwrap() = Default::default();
89
90 let mut guard = states.cached_state.get::<SurfaceCachedState>();
91 *guard.pending() = Default::default();
92 *guard.current() = Default::default();
93 })
94 }
95 }
96}
97
98pub fn send_popup_configure(resource: &XdgPopup, configure: PopupConfigure) {
99 let data = resource.data::<XdgShellSurfaceUserData>().unwrap();
100
101 let serial = configure.serial;
102 let geometry = configure.state.geometry;
103
104 if let Some(token) = configure.reposition_token {
106 resource.repositioned(token);
107 }
108
109 resource.configure(geometry.loc.x, geometry.loc.y, geometry.size.w, geometry.size.h);
111
112 data.xdg_surface.configure(serial.into());
115}
116
117pub fn make_popup_handle(resource: &XdgPopup) -> crate::wayland::shell::xdg::PopupSurface {
118 let data = resource.data::<XdgShellSurfaceUserData>().unwrap();
119 crate::wayland::shell::xdg::PopupSurface {
120 wl_surface: data.wl_surface.clone(),
121 shell_surface: resource.clone(),
122 }
123}