smithay/wayland/xdg_activation/
dispatch.rs

1use std::sync::{
2    atomic::{AtomicBool, Ordering},
3    Mutex,
4};
5
6use wayland_protocols::xdg::activation::v1::server::{xdg_activation_token_v1, xdg_activation_v1};
7use wayland_server::{
8    backend::ClientId, Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource,
9};
10
11use super::{
12    ActivationTokenData, TokenBuilder, XdgActivationHandler, XdgActivationState, XdgActivationTokenData,
13};
14
15impl<D> Dispatch<xdg_activation_v1::XdgActivationV1, (), D> for XdgActivationState
16where
17    D: Dispatch<xdg_activation_v1::XdgActivationV1, ()>
18        + Dispatch<xdg_activation_token_v1::XdgActivationTokenV1, ActivationTokenData>
19        + XdgActivationHandler
20        + 'static,
21{
22    fn request(
23        state: &mut D,
24        _: &Client,
25        _: &xdg_activation_v1::XdgActivationV1,
26        request: xdg_activation_v1::Request,
27        _: &(),
28        _dh: &DisplayHandle,
29        data_init: &mut DataInit<'_, D>,
30    ) {
31        match request {
32            xdg_activation_v1::Request::Destroy => {}
33
34            xdg_activation_v1::Request::GetActivationToken { id } => {
35                data_init.init(
36                    id,
37                    ActivationTokenData {
38                        constructed: AtomicBool::new(false),
39                        build: Mutex::new(TokenBuilder {
40                            serial: None,
41                            app_id: None,
42                            surface: None,
43                        }),
44                        token: Mutex::new(None),
45                    },
46                );
47            }
48
49            xdg_activation_v1::Request::Activate { token, surface } => {
50                let token = token.into();
51
52                let activation_state = state.activation_state();
53
54                if let Some(token_data) = activation_state.known_tokens.get(&token).cloned() {
55                    state.request_activation(token, token_data, surface);
56                }
57            }
58
59            _ => unreachable!(),
60        }
61    }
62}
63
64impl<D> GlobalDispatch<xdg_activation_v1::XdgActivationV1, (), D> for XdgActivationState
65where
66    D: GlobalDispatch<xdg_activation_v1::XdgActivationV1, ()>
67        + Dispatch<xdg_activation_v1::XdgActivationV1, ()>
68        + Dispatch<xdg_activation_token_v1::XdgActivationTokenV1, ActivationTokenData>
69        + XdgActivationHandler
70        + 'static,
71{
72    fn bind(
73        _: &mut D,
74        _: &DisplayHandle,
75        _: &Client,
76        resource: New<xdg_activation_v1::XdgActivationV1>,
77        _: &(),
78        data_init: &mut DataInit<'_, D>,
79    ) {
80        data_init.init(resource, ());
81    }
82}
83
84impl<D> Dispatch<xdg_activation_token_v1::XdgActivationTokenV1, ActivationTokenData, D> for XdgActivationState
85where
86    D: Dispatch<xdg_activation_token_v1::XdgActivationTokenV1, ActivationTokenData> + XdgActivationHandler,
87{
88    fn request(
89        state: &mut D,
90        client: &Client,
91        token: &xdg_activation_token_v1::XdgActivationTokenV1,
92        request: xdg_activation_token_v1::Request,
93        data: &ActivationTokenData,
94        _dh: &DisplayHandle,
95        _: &mut DataInit<'_, D>,
96    ) {
97        match request {
98            xdg_activation_token_v1::Request::SetSerial { serial, seat } => {
99                if data.constructed.load(Ordering::Relaxed) {
100                    token.post_error(
101                        xdg_activation_token_v1::Error::AlreadyUsed,
102                        "The activation token has already been constructed",
103                    );
104                    return;
105                }
106
107                data.build.lock().unwrap().serial = Some((serial.into(), seat));
108            }
109
110            xdg_activation_token_v1::Request::SetAppId { app_id } => {
111                if data.constructed.load(Ordering::Relaxed) {
112                    token.post_error(
113                        xdg_activation_token_v1::Error::AlreadyUsed,
114                        "The activation token has already been constructed",
115                    );
116                    return;
117                }
118
119                data.build.lock().unwrap().app_id = Some(app_id);
120            }
121
122            xdg_activation_token_v1::Request::SetSurface { surface } => {
123                if data.constructed.load(Ordering::Relaxed) {
124                    token.post_error(
125                        xdg_activation_token_v1::Error::AlreadyUsed,
126                        "The activation token has already been constructed",
127                    );
128                    return;
129                }
130
131                data.build.lock().unwrap().surface = Some(surface);
132            }
133
134            xdg_activation_token_v1::Request::Commit => {
135                if data.constructed.load(Ordering::Relaxed) {
136                    token.post_error(
137                        xdg_activation_token_v1::Error::AlreadyUsed,
138                        "The activation token has already been constructed",
139                    );
140                    return;
141                }
142
143                data.constructed.store(true, Ordering::Relaxed);
144
145                let (activation_token, token_data) = {
146                    let mut guard = data.build.lock().unwrap();
147
148                    XdgActivationTokenData::new(
149                        Some(client.id()),
150                        guard.serial.take(),
151                        guard.app_id.take(),
152                        guard.surface.take(),
153                    )
154                };
155
156                let valid = state.token_created(activation_token.clone(), token_data.clone());
157
158                *data.token.lock().unwrap() = Some(activation_token.clone());
159                if valid {
160                    state
161                        .activation_state()
162                        .known_tokens
163                        .insert(activation_token.clone(), token_data);
164                }
165                token.done(activation_token.to_string());
166            }
167
168            xdg_activation_token_v1::Request::Destroy => {}
169
170            _ => unreachable!(),
171        }
172    }
173
174    fn destroyed(
175        _: &mut D,
176        _: ClientId,
177        _: &xdg_activation_token_v1::XdgActivationTokenV1,
178        _: &ActivationTokenData,
179    ) {
180    }
181}