wayland_backend/rs/server_impl/
registry.rs1use 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 handle::PendingDestructor,
12 ClientId, GlobalHandler, GlobalId, InnerGlobalId, InnerObjectId, ObjectId,
13};
14
15#[derive(Debug)]
21pub(crate) struct Global<D: 'static> {
22 id: InnerGlobalId,
23 interface: &'static Interface,
24 version: u32,
25 handler: Arc<dyn GlobalHandler<D>>,
26 disabled: bool,
27}
28
29#[derive(Debug)]
30
31pub struct Registry<D: 'static> {
32 globals: Vec<Option<Global<D>>>,
33 known_registries: Vec<InnerObjectId>,
34 last_serial: u32,
35}
36
37impl<D> Registry<D> {
38 pub(crate) fn new() -> Self {
39 Self { globals: Vec::new(), known_registries: Vec::new(), last_serial: 0 }
40 }
41
42 fn next_serial(&mut self) -> u32 {
43 self.last_serial = self.last_serial.wrapping_add(1);
44 self.last_serial
45 }
46
47 pub(crate) fn create_global(
48 &mut self,
49 interface: &'static Interface,
50 version: u32,
51 handler: Arc<dyn GlobalHandler<D>>,
52 clients: &mut ClientStore<D>,
53 ) -> InnerGlobalId {
54 if version > interface.version {
55 panic!(
56 "Cannot create global {} version {}: maximum supported version is {}",
57 interface.name, version, interface.version
58 );
59 }
60 let serial = self.next_serial();
61 let (id, place) = match self.globals.iter_mut().enumerate().find(|(_, g)| g.is_none()) {
62 Some((id, place)) => (id, place),
63 None => {
64 self.globals.push(None);
65 (self.globals.len() - 1, self.globals.last_mut().unwrap())
66 }
67 };
68
69 let id = InnerGlobalId { id: id as u32 + 1, serial };
70
71 *place = Some(Global { id: id.clone(), interface, version, handler, disabled: false });
72
73 self.send_global_to_all(id.clone(), clients).unwrap();
74
75 id
76 }
77
78 fn get_global(&self, id: InnerGlobalId) -> Result<&Global<D>, InvalidId> {
79 self.globals
80 .get(id.id as usize - 1)
81 .and_then(|o| o.as_ref())
82 .filter(|o| o.id == id)
83 .ok_or(InvalidId)
84 }
85
86 pub(crate) fn get_info(&self, id: InnerGlobalId) -> Result<GlobalInfo, InvalidId> {
87 let global = self.get_global(id)?;
88 Ok(GlobalInfo {
89 interface: global.interface,
90 version: global.version,
91 disabled: global.disabled,
92 })
93 }
94
95 pub(crate) fn get_handler(
96 &self,
97 id: InnerGlobalId,
98 ) -> Result<Arc<dyn GlobalHandler<D>>, InvalidId> {
99 let global = self.get_global(id)?;
100 Ok(global.handler.clone())
101 }
102
103 pub(crate) fn check_bind(
104 &self,
105 client: &Client<D>,
106 name: u32,
107 interface_name: &CStr,
108 version: u32,
109 ) -> Option<(&'static Interface, InnerGlobalId, Arc<dyn GlobalHandler<D>>)> {
110 if name == 0 || version == 0 {
111 return None;
112 }
113 let target_global = self.globals.get((name - 1) as usize).and_then(|o| o.as_ref())?;
114 if target_global.interface.name.as_bytes() != interface_name.to_bytes() {
115 return None;
116 }
117 if target_global.version < version {
118 return None;
119 }
120 if !target_global.handler.can_view(
121 ClientId { id: client.id.clone() },
122 &client.data,
123 GlobalId { id: target_global.id.clone() },
124 ) {
125 return None;
126 }
127
128 Some((target_global.interface, target_global.id.clone(), target_global.handler.clone()))
129 }
130
131 pub(crate) fn cleanup(
132 &mut self,
133 dead_clients: &[Client<D>],
134 pending_destructors: &[PendingDestructor<D>],
135 ) {
136 self.known_registries.retain(|obj_id| {
139 !dead_clients.iter().any(|cid| cid.id == obj_id.client_id)
140 && !pending_destructors.iter().any(|(_, _, id)| id == obj_id)
141 })
142 }
143
144 pub(crate) fn disable_global(&mut self, id: InnerGlobalId, clients: &mut ClientStore<D>) {
145 let global = match self.globals.get_mut(id.id as usize - 1) {
146 Some(&mut Some(ref mut g)) if g.id == id => g,
147 _ => return,
148 };
149
150 if !global.disabled {
152 global.disabled = true;
153 for registry in self.known_registries.iter().cloned() {
155 if let Ok(client) = clients.get_client_mut(registry.client_id.clone()) {
156 let _ =
157 send_global_remove_to(client, global, ObjectId { id: registry.clone() });
158 }
159 }
160 }
161 }
162
163 pub(crate) fn remove_global(
164 &mut self,
165 id: InnerGlobalId,
166 clients: &mut ClientStore<D>,
167 ) -> Option<Global<D>> {
168 self.disable_global(id.clone(), clients);
170 if let Some(place) = self.globals.get_mut(id.id as usize - 1) {
172 if place.as_ref().map(|g| g.id == id).unwrap_or(false) {
173 place.take()
174 } else {
175 None
176 }
177 } else {
178 None
179 }
180 }
181
182 pub(crate) fn new_registry(
183 &mut self,
184 registry: InnerObjectId,
185 client: &mut Client<D>,
186 ) -> Result<(), InvalidId> {
187 self.send_all_globals_to(registry.clone(), client)?;
188 self.known_registries.push(registry);
189 Ok(())
190 }
191
192 pub(crate) fn send_all_globals_to(
193 &self,
194 registry: InnerObjectId,
195 client: &mut Client<D>,
196 ) -> Result<(), InvalidId> {
197 for global in self.globals.iter().flat_map(|opt| opt.as_ref()) {
198 if !global.disabled
199 && global.handler.can_view(
200 ClientId { id: client.id.clone() },
201 &client.data,
202 GlobalId { id: global.id.clone() },
203 )
204 {
205 send_global_to(client, global, ObjectId { id: registry.clone() })?;
207 }
208 }
209 Ok(())
210 }
211
212 pub(crate) fn send_global_to_all(
213 &self,
214 global_id: InnerGlobalId,
215 clients: &mut ClientStore<D>,
216 ) -> Result<(), InvalidId> {
217 let global = self.get_global(global_id)?;
218 if global.disabled {
219 return Err(InvalidId);
220 }
221 for registry in self.known_registries.iter().cloned() {
222 if let Ok(client) = clients.get_client_mut(registry.client_id.clone()) {
223 if !global.disabled
224 && global.handler.can_view(
225 ClientId { id: client.id.clone() },
226 &client.data,
227 GlobalId { id: global.id.clone() },
228 )
229 {
230 let _ = send_global_to(client, global, ObjectId { id: registry.clone() });
232 }
233 }
234 }
235 Ok(())
236 }
237}
238
239#[inline]
240fn send_global_to<D>(
241 client: &mut Client<D>,
242 global: &Global<D>,
243 registry: ObjectId,
244) -> Result<(), InvalidId> {
245 client.send_event(
246 message!(
247 registry,
248 0, [
250 Argument::Uint(global.id.id),
251 Argument::Str(Some(Box::new(CString::new(global.interface.name).unwrap()))),
252 Argument::Uint(global.version),
253 ],
254 ),
255 None,
257 )
258}
259
260#[inline]
261fn send_global_remove_to<D>(
262 client: &mut Client<D>,
263 global: &Global<D>,
264 registry: ObjectId,
265) -> Result<(), InvalidId> {
266 client.send_event(
267 message!(
268 registry,
269 1, [Argument::Uint(global.id.id)],
271 ),
272 None,
274 )
275}