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                // Do not assign a role to the surface here
66                // xdg_surface is not role, only xdg_toplevel and
67                // xdg_popup are defined as roles
68                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/*
124 * xdg_shell
125 */
126
127/// User data for Xdg Wm Base
128#[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}