wayland_server/
global.rs

1use std::os::unix::io::OwnedFd;
2use std::sync::Arc;
3
4use wayland_backend::server::{
5    ClientData, ClientId, GlobalHandler, GlobalId, Handle, ObjectData, ObjectId,
6};
7
8use crate::{Client, DataInit, DisplayHandle, New, Resource};
9
10pub(crate) struct GlobalData<I, U, D> {
11    pub(crate) data: U,
12    pub(crate) _types: std::marker::PhantomData<(I, D)>,
13}
14
15unsafe impl<I, D, U: Send + Sync> Send for GlobalData<I, U, D> {}
16unsafe impl<I, D, U: Send + Sync> Sync for GlobalData<I, U, D> {}
17
18impl<I: Resource + 'static, U: Send + Sync + 'static, D: GlobalDispatch<I, U> + 'static>
19    GlobalHandler<D> for GlobalData<I, U, D>
20{
21    fn can_view(&self, id: ClientId, data: &Arc<dyn ClientData>, _: GlobalId) -> bool {
22        let client = Client { id, data: data.clone() };
23        <D as GlobalDispatch<I, U>>::can_view(client, &self.data)
24    }
25
26    fn bind(
27        self: Arc<Self>,
28        handle: &Handle,
29        data: &mut D,
30        client_id: ClientId,
31        _: GlobalId,
32        object_id: ObjectId,
33    ) -> Arc<dyn ObjectData<D>> {
34        let handle = DisplayHandle::from(handle.clone());
35        let client = Client::from_id(&handle, client_id).expect("Dead client in bind ?!");
36        let resource = <I as Resource>::from_id(&handle, object_id)
37            .expect("Wrong object_id in GlobalHandler ?!");
38
39        let mut new_data = None;
40        let mut protocol_error = None;
41
42        <D as GlobalDispatch<I, U>>::bind(
43            data,
44            &handle,
45            &client,
46            New::wrap(resource.clone()),
47            &self.data,
48            &mut DataInit { store: &mut new_data, error: &mut protocol_error },
49        );
50
51        match new_data {
52            Some(data) => data,
53            None => match protocol_error {
54                Some((code, msg)) => {
55                    resource.post_error(code, msg);
56                    Arc::new(ProtocolErrorData)
57                }
58
59                None => panic!(
60                    "Bind callback for interface {} did not init new instance.",
61                    I::interface().name
62                ),
63            },
64        }
65    }
66}
67
68struct ProtocolErrorData;
69
70impl<D> ObjectData<D> for ProtocolErrorData {
71    fn request(
72        self: Arc<Self>,
73        _handle: &Handle,
74        _data: &mut D,
75        _client_id: ClientId,
76        _msg: wayland_backend::protocol::Message<ObjectId, OwnedFd>,
77    ) -> Option<Arc<dyn ObjectData<D>>> {
78        None
79    }
80
81    fn destroyed(
82        self: Arc<Self>,
83        _handle: &Handle,
84        _data: &mut D,
85        _client_id: ClientId,
86        _object_id: ObjectId,
87    ) {
88    }
89}
90
91/// A trait which provides an implementation for handling advertisement of a global to clients with some type
92/// of associated user data.
93///
94/// Its behavior is similar to the [`Dispatch`][crate::Dispatch] trait.
95pub trait GlobalDispatch<I: Resource, GlobalData, State = Self>: Sized {
96    /// Called when a client has bound this global.
97    ///
98    /// The return value of this function should contain user data to associate the object created by the
99    /// client.
100    fn bind(
101        state: &mut State,
102        handle: &DisplayHandle,
103        client: &Client,
104        resource: New<I>,
105        global_data: &GlobalData,
106        data_init: &mut DataInit<'_, State>,
107    );
108
109    /// Checks if the global should be advertised to some client.
110    ///
111    /// The implementation of this function determines whether a client may see and bind some global. If this
112    /// function returns false, the client will not be told the global exists and attempts to bind the global
113    /// will raise a protocol error.
114    ///
115    /// One use of this function is implementing privileged protocols such as XWayland keyboard grabbing
116    /// which must only be used by XWayland.
117    ///
118    /// The default implementation allows all clients to see the global.
119    fn can_view(_client: Client, _global_data: &GlobalData) -> bool {
120        true
121    }
122}
123
124/*
125 * Dispatch delegation helpers
126 */
127
128/// A helper macro which delegates a set of [`GlobalDispatch`] implementations for a resource to some other type which
129/// provdes a generic [`GlobalDispatch`] implementation.
130///
131/// Its usage is similar to the [`delegate_dispatch!()`] macro.
132///
133/// [`delegate_dispatch!()`]: crate::delegate_dispatch!()
134#[macro_export]
135macro_rules! delegate_global_dispatch {
136    ($(@< $( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+ >)? $dispatch_from:ty : [$interface: ty: $udata: ty] => $dispatch_to: ty) => {
137        impl$(< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $crate::GlobalDispatch<$interface, $udata> for $dispatch_from {
138            fn bind(
139                state: &mut Self,
140                dhandle: &$crate::DisplayHandle,
141                client: &$crate::Client,
142                resource: $crate::New<$interface>,
143                global_data: &$udata,
144                data_init: &mut $crate::DataInit<'_, Self>,
145            ) {
146                <$dispatch_to as $crate::GlobalDispatch<$interface, $udata, Self>>::bind(state, dhandle, client, resource, global_data, data_init)
147            }
148
149            fn can_view(client: $crate::Client, global_data: &$udata) -> bool {
150                <$dispatch_to as $crate::GlobalDispatch<$interface, $udata, Self>>::can_view(client, global_data)
151            }
152        }
153    };
154}
155
156#[cfg(test)]
157mod tests {
158    #[test]
159    fn smoke_test_dispatch_global_dispatch() {
160        use crate::{
161            delegate_dispatch, protocol::wl_output, Client, DataInit, Dispatch, DisplayHandle,
162            GlobalDispatch, New,
163        };
164
165        struct DelegateToMe;
166
167        impl<D> Dispatch<wl_output::WlOutput, (), D> for DelegateToMe
168        where
169            D: Dispatch<wl_output::WlOutput, ()> + AsMut<DelegateToMe>,
170        {
171            fn request(
172                _state: &mut D,
173                _client: &Client,
174                _resource: &wl_output::WlOutput,
175                _request: wl_output::Request,
176                _data: &(),
177                _dhandle: &DisplayHandle,
178                _data_init: &mut DataInit<'_, D>,
179            ) {
180            }
181        }
182        impl<D> GlobalDispatch<wl_output::WlOutput, (), D> for DelegateToMe
183        where
184            D: GlobalDispatch<wl_output::WlOutput, ()>,
185            D: Dispatch<wl_output::WlOutput, ()>,
186            D: AsMut<DelegateToMe>,
187        {
188            fn bind(
189                _state: &mut D,
190                _handle: &DisplayHandle,
191                _client: &Client,
192                _resource: New<wl_output::WlOutput>,
193                _global_data: &(),
194                _data_init: &mut DataInit<'_, D>,
195            ) {
196            }
197        }
198
199        struct ExampleApp {
200            delegate: DelegateToMe,
201        }
202
203        delegate_dispatch!(ExampleApp: [wl_output::WlOutput: ()] => DelegateToMe);
204        delegate_global_dispatch!(ExampleApp: [wl_output::WlOutput: ()] => DelegateToMe);
205
206        impl AsMut<DelegateToMe> for ExampleApp {
207            fn as_mut(&mut self) -> &mut DelegateToMe {
208                &mut self.delegate
209            }
210        }
211    }
212
213    #[test]
214    fn smoke_test_dispatch_global_dispatch_generics() {
215        use crate::{
216            delegate_dispatch, protocol::wl_output, Client, DataInit, Dispatch, DisplayHandle,
217            GlobalDispatch, New,
218        };
219
220        struct DelegateToMe<A>(A);
221
222        impl<A, D> Dispatch<wl_output::WlOutput, (), D> for DelegateToMe<A>
223        where
224            A: 'static,
225            D: Dispatch<wl_output::WlOutput, ()> + AsMut<DelegateToMe<A>>,
226        {
227            fn request(
228                _state: &mut D,
229                _client: &Client,
230                _resource: &wl_output::WlOutput,
231                _request: wl_output::Request,
232                _data: &(),
233                _dhandle: &DisplayHandle,
234                _data_init: &mut DataInit<'_, D>,
235            ) {
236            }
237        }
238        impl<A, D> GlobalDispatch<wl_output::WlOutput, (), D> for DelegateToMe<A>
239        where
240            A: 'static,
241            D: GlobalDispatch<wl_output::WlOutput, ()>,
242            D: Dispatch<wl_output::WlOutput, ()>,
243            D: AsMut<DelegateToMe<A>>,
244        {
245            fn bind(
246                _state: &mut D,
247                _handle: &DisplayHandle,
248                _client: &Client,
249                _resource: New<wl_output::WlOutput>,
250                _global_data: &(),
251                _data_init: &mut DataInit<'_, D>,
252            ) {
253            }
254        }
255
256        struct ExampleApp<A> {
257            delegate: DelegateToMe<A>,
258        }
259
260        delegate_dispatch!(@<A: 'static> ExampleApp<A>: [wl_output::WlOutput: ()] => DelegateToMe<A>);
261        delegate_global_dispatch!(@<A: 'static> ExampleApp<A>: [wl_output::WlOutput: ()] => DelegateToMe<A>);
262
263        impl<A> AsMut<DelegateToMe<A>> for ExampleApp<A> {
264            fn as_mut(&mut self) -> &mut DelegateToMe<A> {
265                &mut self.delegate
266            }
267        }
268    }
269}