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: &[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]
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 pending_destructors: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 pending_destructors:None,
257 )
258}
259