wayland_backend/rs/server_impl/
registry.rs

1use std::{
2    ffi::{CStr, CString},
3    sync::Arc,
4};
5
6use crate::protocol::{Argument, Interface};
7use crate::types::server::{GlobalInfo, InvalidId};
8
9use super::{
10    client::{Client, ClientStore},
11    ClientId, GlobalHandler, GlobalId, InnerGlobalId, InnerObjectId, ObjectId,
12};
13
14/*
15    GlobalId.id is the global protocol name (starting at 1), hence
16    we must subtract 1 to it before indexing the vec
17*/
18
19#[derive(Debug)]
20struct Global<D: 'static> {
21    id: InnerGlobalId,
22    interface: &'static Interface,
23    version: u32,
24    handler: Arc<dyn GlobalHandler<D>>,
25    disabled: bool,
26}
27
28#[derive(Debug)]
29
30pub struct Registry<D: 'static> {
31    globals: Vec<Option<Global<D>>>,
32    known_registries: Vec<InnerObjectId>,
33    last_serial: u32,
34}
35
36impl<D> Registry<D> {
37    pub(crate) fn new() -> Self {
38        Self { globals: Vec::new(), known_registries: Vec::new(), last_serial: 0 }
39    }
40
41    fn next_serial(&mut self) -> u32 {
42        self.last_serial = self.last_serial.wrapping_add(1);
43        self.last_serial
44    }
45
46    pub(crate) fn create_global(
47        &mut self,
48        interface: &'static Interface,
49        version: u32,
50        handler: Arc<dyn GlobalHandler<D>>,
51        clients: &mut ClientStore<D>,
52    ) -> InnerGlobalId {
53        if version > interface.version {
54            panic!(
55                "Cannot create global {} version {}: maximum supported version is {}",
56                interface.name, version, interface.version
57            );
58        }
59        let serial = self.next_serial();
60        let (id, place) = match self.globals.iter_mut().enumerate().find(|(_, g)| g.is_none()) {
61            Some((id, place)) => (id, place),
62            None => {
63                self.globals.push(None);
64                (self.globals.len() - 1, self.globals.last_mut().unwrap())
65            }
66        };
67
68        let id = InnerGlobalId { id: id as u32 + 1, serial };
69
70        *place = Some(Global { id: id.clone(), interface, version, handler, disabled: false });
71
72        self.send_global_to_all(id.clone(), clients).unwrap();
73
74        id
75    }
76
77    fn get_global(&self, id: InnerGlobalId) -> Result<&Global<D>, InvalidId> {
78        self.globals
79            .get(id.id as usize - 1)
80            .and_then(|o| o.as_ref())
81            .filter(|o| o.id == id)
82            .ok_or(InvalidId)
83    }
84
85    pub(crate) fn get_info(&self, id: InnerGlobalId) -> Result<GlobalInfo, InvalidId> {
86        let global = self.get_global(id)?;
87        Ok(GlobalInfo {
88            interface: global.interface,
89            version: global.version,
90            disabled: global.disabled,
91        })
92    }
93
94    pub(crate) fn get_handler(
95        &self,
96        id: InnerGlobalId,
97    ) -> Result<Arc<dyn GlobalHandler<D>>, InvalidId> {
98        let global = self.get_global(id)?;
99        Ok(global.handler.clone())
100    }
101
102    pub(crate) fn check_bind(
103        &self,
104        client: &Client<D>,
105        name: u32,
106        interface_name: &CStr,
107        version: u32,
108    ) -> Option<(&'static Interface, InnerGlobalId, Arc<dyn GlobalHandler<D>>)> {
109        if name == 0 || version == 0 {
110            return None;
111        }
112        let target_global = self.globals.get((name - 1) as usize).and_then(|o| o.as_ref())?;
113        if target_global.interface.name.as_bytes() != interface_name.to_bytes() {
114            return None;
115        }
116        if target_global.version < version {
117            return None;
118        }
119        if !target_global.handler.can_view(
120            ClientId { id: client.id.clone() },
121            &client.data,
122            GlobalId { id: target_global.id.clone() },
123        ) {
124            return None;
125        }
126
127        Some((target_global.interface, target_global.id.clone(), target_global.handler.clone()))
128    }
129
130    pub(crate) fn cleanup(&mut self, dead_clients: &[Client<D>]) {
131        self.known_registries
132            .retain(|obj_id| !dead_clients.iter().any(|cid| cid.id == obj_id.client_id))
133    }
134
135    pub(crate) fn disable_global(&mut self, id: InnerGlobalId, clients: &mut ClientStore<D>) {
136        let global = match self.globals.get_mut(id.id as usize - 1) {
137            Some(&mut Some(ref mut g)) if g.id == id => g,
138            _ => return,
139        };
140
141        // Do nothing if the global is already disabled
142        if !global.disabled {
143            global.disabled = true;
144            // send the global_remove
145            for registry in self.known_registries.iter().cloned() {
146                if let Ok(client) = clients.get_client_mut(registry.client_id.clone()) {
147                    let _ =
148                        send_global_remove_to(client, global, ObjectId { id: registry.clone() });
149                }
150            }
151        }
152    }
153
154    pub(crate) fn remove_global(&mut self, id: InnerGlobalId, clients: &mut ClientStore<D>) {
155        // disable the global if not already disabled
156        self.disable_global(id.clone(), clients);
157        // now remove it if the id is still valid
158        if let Some(place) = self.globals.get_mut(id.id as usize - 1) {
159            if place.as_ref().map(|g| g.id == id).unwrap_or(false) {
160                *place = None;
161            }
162        }
163    }
164
165    pub(crate) fn new_registry(
166        &mut self,
167        registry: InnerObjectId,
168        client: &mut Client<D>,
169    ) -> Result<(), InvalidId> {
170        self.send_all_globals_to(registry.clone(), client)?;
171        self.known_registries.push(registry);
172        Ok(())
173    }
174
175    pub(crate) fn send_all_globals_to(
176        &self,
177        registry: InnerObjectId,
178        client: &mut Client<D>,
179    ) -> Result<(), InvalidId> {
180        for global in self.globals.iter().flat_map(|opt| opt.as_ref()) {
181            if !global.disabled
182                && global.handler.can_view(
183                    ClientId { id: client.id.clone() },
184                    &client.data,
185                    GlobalId { id: global.id.clone() },
186                )
187            {
188                // fail the whole send on error, there is no point in trying further on a failing client
189                send_global_to(client, global, ObjectId { id: registry.clone() })?;
190            }
191        }
192        Ok(())
193    }
194
195    pub(crate) fn send_global_to_all(
196        &self,
197        global_id: InnerGlobalId,
198        clients: &mut ClientStore<D>,
199    ) -> Result<(), InvalidId> {
200        let global = self.get_global(global_id)?;
201        if global.disabled {
202            return Err(InvalidId);
203        }
204        for registry in self.known_registries.iter().cloned() {
205            if let Ok(client) = clients.get_client_mut(registry.client_id.clone()) {
206                if !global.disabled
207                    && global.handler.can_view(
208                        ClientId { id: client.id.clone() },
209                        &client.data,
210                        GlobalId { id: global.id.clone() },
211                    )
212                {
213                    // don't fail the whole send for a single erroring client
214                    let _ = send_global_to(client, global, ObjectId { id: registry.clone() });
215                }
216            }
217        }
218        Ok(())
219    }
220}
221
222#[inline]
223fn send_global_to<D>(
224    client: &mut Client<D>,
225    global: &Global<D>,
226    registry: ObjectId,
227) -> Result<(), InvalidId> {
228    client.send_event(
229        message!(
230            registry,
231            0, // wl_registry.global
232            [
233                Argument::Uint(global.id.id),
234                Argument::Str(Some(Box::new(CString::new(global.interface.name).unwrap()))),
235                Argument::Uint(global.version),
236            ],
237        ),
238        // This is not a destructor event
239        None,
240    )
241}
242
243#[inline]
244fn send_global_remove_to<D>(
245    client: &mut Client<D>,
246    global: &Global<D>,
247    registry: ObjectId,
248) -> Result<(), InvalidId> {
249    client.send_event(
250        message!(
251            registry,
252            1, // wl_registry.global_remove
253            [Argument::Uint(global.id.id)],
254        ),
255        // This is not a destructor event
256        None,
257    )
258}