1 | use std::{ |
2 | ffi::{CStr, CString}, |
3 | sync::Arc, |
4 | }; |
5 | |
6 | use crate::protocol::{Argument, Interface}; |
7 | use crate::types::server::{GlobalInfo, InvalidId}; |
8 | |
9 | use 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)] |
20 | struct 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 | |
30 | pub struct Registry<D: 'static> { |
31 | globals: Vec<Option<Global<D>>>, |
32 | known_registries: Vec<InnerObjectId>, |
33 | last_serial: u32, |
34 | } |
35 | |
36 | impl<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: &[ClientId]) { |
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 ] |
223 | fn 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 | pending_destructors:None, |
240 | ) |
241 | } |
242 | |
243 | #[inline ] |
244 | fn 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 | pending_destructors:None, |
257 | ) |
258 | } |
259 | |