smithay/wayland/shell/xdg/handlers/
wm_base.rs
1use std::sync::{atomic::AtomicBool, Arc, Mutex};
2
3use indexmap::IndexSet;
4
5use crate::{
6 utils::{alive_tracker::AliveTracker, IsAlive, Serial},
7 wayland::shell::xdg::XdgShellState,
8};
9
10use wayland_protocols::xdg::shell::server::{
11 xdg_positioner::XdgPositioner, xdg_surface, xdg_surface::XdgSurface, xdg_wm_base, xdg_wm_base::XdgWmBase,
12};
13
14use wayland_server::{
15 backend::ClientId, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource, Weak,
16};
17
18use super::{ShellClient, ShellClientData, XdgPositionerUserData, XdgShellHandler, XdgSurfaceUserData};
19
20impl<D> GlobalDispatch<XdgWmBase, (), D> for XdgShellState
21where
22 D: GlobalDispatch<XdgWmBase, ()>,
23 D: Dispatch<XdgWmBase, XdgWmBaseUserData>,
24 D: Dispatch<XdgSurface, XdgSurfaceUserData>,
25 D: Dispatch<XdgPositioner, XdgPositionerUserData>,
26 D: XdgShellHandler,
27 D: 'static,
28{
29 fn bind(
30 state: &mut D,
31 _dh: &DisplayHandle,
32 _client: &wayland_server::Client,
33 resource: New<XdgWmBase>,
34 _global_data: &(),
35 data_init: &mut DataInit<'_, D>,
36 ) {
37 let shell = data_init.init(resource, XdgWmBaseUserData::default());
38
39 XdgShellHandler::new_client(state, ShellClient::new(&shell));
40 }
41}
42
43impl<D> Dispatch<XdgWmBase, XdgWmBaseUserData, D> for XdgShellState
44where
45 D: Dispatch<XdgWmBase, XdgWmBaseUserData>,
46 D: Dispatch<XdgSurface, XdgSurfaceUserData>,
47 D: Dispatch<XdgPositioner, XdgPositionerUserData>,
48 D: XdgShellHandler,
49 D: 'static,
50{
51 fn request(
52 state: &mut D,
53 _client: &wayland_server::Client,
54 wm_base: &XdgWmBase,
55 request: xdg_wm_base::Request,
56 data: &XdgWmBaseUserData,
57 _dh: &DisplayHandle,
58 data_init: &mut DataInit<'_, D>,
59 ) {
60 match request {
61 xdg_wm_base::Request::CreatePositioner { id } => {
62 data_init.init(id, XdgPositionerUserData::default());
63 }
64 xdg_wm_base::Request::GetXdgSurface { id, surface } => {
65 let xdg_surface = data_init.init(
69 id,
70 XdgSurfaceUserData {
71 known_surfaces: data.known_surfaces.clone(),
72 wl_surface: surface,
73 wm_base: wm_base.clone(),
74 has_active_role: AtomicBool::new(false),
75 },
76 );
77 data.known_surfaces
78 .lock()
79 .unwrap()
80 .insert(xdg_surface.downgrade());
81 }
82 xdg_wm_base::Request::Pong { serial } => {
83 let serial = Serial::from(serial);
84 let valid = {
85 let mut guard = data.client_data.lock().unwrap();
86 if guard.pending_ping == Some(serial) {
87 guard.pending_ping = None;
88 true
89 } else {
90 false
91 }
92 };
93 if valid {
94 XdgShellHandler::client_pong(state, ShellClient::new(wm_base));
95 }
96 }
97 xdg_wm_base::Request::Destroy => {
98 if !data.known_surfaces.lock().unwrap().is_empty() {
99 wm_base.post_error(
100 xdg_wm_base::Error::DefunctSurfaces,
101 "xdg_wm_base was destroyed before children",
102 );
103 }
104 }
105 _ => unreachable!(),
106 }
107 }
108
109 fn destroyed(state: &mut D, _client_id: ClientId, wm_base: &XdgWmBase, data: &XdgWmBaseUserData) {
110 XdgShellHandler::client_destroyed(state, ShellClient::new(wm_base));
111 data.alive_tracker.destroy_notify();
112 }
113}
114
115impl IsAlive for XdgWmBase {
116 #[inline]
117 fn alive(&self) -> bool {
118 let data: &XdgWmBaseUserData = self.data().unwrap();
119 data.alive_tracker.alive()
120 }
121}
122
123#[derive(Default, Debug)]
129pub struct XdgWmBaseUserData {
130 pub(crate) client_data: Mutex<ShellClientData>,
131 known_surfaces: Arc<Mutex<IndexSet<Weak<xdg_surface::XdgSurface>>>>,
132 alive_tracker: AliveTracker,
133}