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)]
21struct 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(&mut self, id: InnerGlobalId, clients: &mut ClientStore<D>) {
164 self.disable_global(id.clone(), clients);
166 if let Some(place) = self.globals.get_mut(id.id as usize - 1) {
168 if place.as_ref().map(|g| g.id == id).unwrap_or(false) {
169 *place = None;
170 }
171 }
172 }
173
174 pub(crate) fn new_registry(
175 &mut self,
176 registry: InnerObjectId,
177 client: &mut Client<D>,
178 ) -> Result<(), InvalidId> {
179 self.send_all_globals_to(registry.clone(), client)?;
180 self.known_registries.push(registry);
181 Ok(())
182 }
183
184 pub(crate) fn send_all_globals_to(
185 &self,
186 registry: InnerObjectId,
187 client: &mut Client<D>,
188 ) -> Result<(), InvalidId> {
189 for global in self.globals.iter().flat_map(|opt| opt.as_ref()) {
190 if !global.disabled
191 && global.handler.can_view(
192 ClientId { id: client.id.clone() },
193 &client.data,
194 GlobalId { id: global.id.clone() },
195 )
196 {
197 send_global_to(client, global, ObjectId { id: registry.clone() })?;
199 }
200 }
201 Ok(())
202 }
203
204 pub(crate) fn send_global_to_all(
205 &self,
206 global_id: InnerGlobalId,
207 clients: &mut ClientStore<D>,
208 ) -> Result<(), InvalidId> {
209 let global = self.get_global(global_id)?;
210 if global.disabled {
211 return Err(InvalidId);
212 }
213 for registry in self.known_registries.iter().cloned() {
214 if let Ok(client) = clients.get_client_mut(registry.client_id.clone()) {
215 if !global.disabled
216 && global.handler.can_view(
217 ClientId { id: client.id.clone() },
218 &client.data,
219 GlobalId { id: global.id.clone() },
220 )
221 {
222 let _ = send_global_to(client, global, ObjectId { id: registry.clone() });
224 }
225 }
226 }
227 Ok(())
228 }
229}
230
231#[inline]
232fn send_global_to<D>(
233 client: &mut Client<D>,
234 global: &Global<D>,
235 registry: ObjectId,
236) -> Result<(), InvalidId> {
237 client.send_event(
238 message!(
239 registry,
240 0, [
242 Argument::Uint(global.id.id),
243 Argument::Str(Some(Box::new(CString::new(global.interface.name).unwrap()))),
244 Argument::Uint(global.version),
245 ],
246 ),
247 None,
249 )
250}
251
252#[inline]
253fn send_global_remove_to<D>(
254 client: &mut Client<D>,
255 global: &Global<D>,
256 registry: ObjectId,
257) -> Result<(), InvalidId> {
258 client.send_event(
259 message!(
260 registry,
261 1, [Argument::Uint(global.id.id)],
263 ),
264 None,
266 )
267}