1use crate::base::ResolveWireError;
2use crate::ext::{Extension, ExtensionData};
3use crate::x;
4use crate::{ffi::*, BaseError, Raw};
5use std::mem;
6
7#[cfg(feature = "damage")]
8use crate::damage;
9
10#[cfg(feature = "glx")]
11use crate::glx;
12
13#[cfg(feature = "randr")]
14use crate::randr;
15
16#[cfg(feature = "render")]
17use crate::render;
18
19#[cfg(feature = "shm")]
20use crate::shm;
21
22#[cfg(feature = "sync")]
23use crate::sync;
24
25#[cfg(feature = "xf86vidmode")]
26use crate::xf86vidmode;
27
28#[cfg(feature = "xfixes")]
29use crate::xfixes;
30
31#[cfg(feature = "xinput")]
32use crate::xinput;
33
34#[cfg(feature = "xkb")]
35use crate::xkb;
36
37#[cfg(feature = "xprint")]
38use crate::xprint;
39
40#[cfg(feature = "xv")]
41use crate::xv;
42
43#[derive(Debug)]
47pub enum ProtocolError {
48 X(x::Error, Option<&'static str>),
50
51 #[cfg(feature = "damage")]
52 Damage(damage::Error, Option<&'static str>),
54
55 #[cfg(feature = "glx")]
56 Glx(glx::Error, Option<&'static str>),
58
59 #[cfg(feature = "randr")]
60 RandR(randr::Error, Option<&'static str>),
62
63 #[cfg(feature = "render")]
64 Render(render::Error, Option<&'static str>),
66
67 #[cfg(feature = "shm")]
68 Shm(shm::Error, Option<&'static str>),
70
71 #[cfg(feature = "sync")]
72 Sync(sync::Error, Option<&'static str>),
74
75 #[cfg(feature = "xf86vidmode")]
76 Xf86VidMode(xf86vidmode::Error, Option<&'static str>),
78
79 #[cfg(feature = "xfixes")]
80 XFixes(xfixes::Error, Option<&'static str>),
82
83 #[cfg(feature = "xinput")]
84 Input(xinput::Error, Option<&'static str>),
86
87 #[cfg(feature = "xkb")]
88 Xkb(xkb::Error, Option<&'static str>),
90
91 #[cfg(feature = "xprint")]
92 XPrint(xprint::Error, Option<&'static str>),
94
95 #[cfg(feature = "xv")]
96 Xv(xv::Error, Option<&'static str>),
98
99 Unknown(UnknownError, Option<&'static str>),
101}
102
103impl ProtocolError {
104 pub fn as_raw(&self) -> *mut xcb_generic_error_t {
105 match self {
106 ProtocolError::X(e, _) => e.as_raw(),
107 #[cfg(feature = "damage")]
108 ProtocolError::Damage(e, _) => e.as_raw(),
109 #[cfg(feature = "glx")]
110 ProtocolError::Glx(e, _) => e.as_raw(),
111 #[cfg(feature = "randr")]
112 ProtocolError::RandR(e, _) => e.as_raw(),
113 #[cfg(feature = "render")]
114 ProtocolError::Render(e, _) => e.as_raw(),
115 #[cfg(feature = "shm")]
116 ProtocolError::Shm(e, _) => e.as_raw(),
117 #[cfg(feature = "sync")]
118 ProtocolError::Sync(e, _) => e.as_raw(),
119 #[cfg(feature = "xf86vidmode")]
120 ProtocolError::Xf86VidMode(e, _) => e.as_raw(),
121 #[cfg(feature = "xfixes")]
122 ProtocolError::XFixes(e, _) => e.as_raw(),
123 #[cfg(feature = "xinput")]
124 ProtocolError::Input(e, _) => e.as_raw(),
125 #[cfg(feature = "xkb")]
126 ProtocolError::Xkb(e, _) => e.as_raw(),
127 #[cfg(feature = "xprint")]
128 ProtocolError::XPrint(e, _) => e.as_raw(),
129 #[cfg(feature = "xv")]
130 ProtocolError::Xv(e, _) => e.as_raw(),
131 ProtocolError::Unknown(e, _) => e.as_raw(),
132 }
133 }
134}
135
136impl std::fmt::Display for ProtocolError {
137 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
138 std::fmt::Debug::fmt(self, f)
139 }
140}
141
142impl std::error::Error for ProtocolError {}
143
144pub struct UnknownError {
146 raw: *mut xcb_generic_error_t,
147}
148
149impl Raw<xcb_generic_error_t> for UnknownError {
150 unsafe fn from_raw(raw: *mut xcb_generic_error_t) -> Self {
151 UnknownError { raw }
152 }
153
154 fn as_raw(&self) -> *mut xcb_generic_error_t {
155 self.raw
156 }
157}
158
159impl BaseError for UnknownError {
160 const EXTENSION: Option<Extension> = None;
161 const NUMBER: u32 = u32::MAX;
162}
163
164impl UnknownError {
165 pub fn response_type(&self) -> u8 {
166 unsafe { (*self.raw).response_type }
167 }
168 pub fn sequence(&self) -> u16 {
169 unsafe { (*self.raw).sequence }
170 }
171 pub fn resource_id(&self) -> u32 {
172 unsafe { (*self.raw).resource_id }
173 }
174 pub fn minor_code(&self) -> u16 {
175 unsafe { (*self.raw).minor_code }
176 }
177 pub fn major_code(&self) -> u8 {
178 unsafe { (*self.raw).major_code }
179 }
180 pub fn full_sequence(&self) -> u32 {
181 unsafe { (*self.raw).full_sequence }
182 }
183}
184
185unsafe impl Send for UnknownError {}
186unsafe impl Sync for UnknownError {}
187
188impl std::fmt::Debug for UnknownError {
189 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
190 f.debug_tuple("UnknownError").finish()
191 }
192}
193
194impl Drop for UnknownError {
195 fn drop(&mut self) {
196 unsafe { libc::free(self.raw as *mut _) }
197 }
198}
199
200pub unsafe fn resolve_error(
209 error: *mut xcb_generic_error_t,
210 extension_data: &[ExtensionData],
211) -> ProtocolError {
212 debug_assert!(!error.is_null());
213
214 let error_code = (*error).error_code;
215 let major_code = (*error).major_code;
216 let minor_code = (*error).minor_code;
217
218 let (best, emitting_ext) = {
219 let mut best: Option<&ExtensionData> = None;
220 let mut emitting_ext = None;
221 for data in extension_data {
222 if data.major_opcode == major_code {
223 emitting_ext = Some(data.ext);
224 }
225 if data.first_error > 0 && error_code >= data.first_error {
226 if let Some(ed) = best {
227 if data.first_error > ed.first_error {
228 best = Some(data);
229 }
230 } else {
231 best = Some(data);
232 }
233 }
234 }
235 (best, emitting_ext)
236 };
237
238 let emitted_by = if let Some(ext) = emitting_ext {
239 match ext {
240 Extension::BigRequests => crate::bigreq::request_name(minor_code),
241 Extension::XcMisc => crate::xc_misc::request_name(minor_code),
242
243 #[cfg(feature = "composite")]
244 Extension::Composite => crate::composite::request_name(minor_code),
245
246 #[cfg(feature = "damage")]
247 Extension::Damage => crate::damage::request_name(minor_code),
248
249 #[cfg(feature = "dpms")]
250 Extension::Dpms => crate::dpms::request_name(minor_code),
251
252 #[cfg(feature = "dri2")]
253 Extension::Dri2 => crate::dri2::request_name(minor_code),
254
255 #[cfg(feature = "dri3")]
256 Extension::Dri3 => crate::dri3::request_name(minor_code),
257
258 #[cfg(feature = "ge")]
259 Extension::GenericEvent => crate::ge::request_name(minor_code),
260
261 #[cfg(feature = "glx")]
262 Extension::Glx => crate::glx::request_name(minor_code),
263
264 #[cfg(feature = "present")]
265 Extension::Present => crate::present::request_name(minor_code),
266
267 #[cfg(feature = "randr")]
268 Extension::RandR => crate::randr::request_name(minor_code),
269
270 #[cfg(feature = "record")]
271 Extension::Record => crate::record::request_name(minor_code),
272
273 #[cfg(feature = "render")]
274 Extension::Render => crate::render::request_name(minor_code),
275
276 #[cfg(feature = "res")]
277 Extension::Res => crate::res::request_name(minor_code),
278
279 #[cfg(feature = "screensaver")]
280 Extension::ScreenSaver => crate::screensaver::request_name(minor_code),
281
282 #[cfg(feature = "shape")]
283 Extension::Shape => crate::shape::request_name(minor_code),
284
285 #[cfg(feature = "shm")]
286 Extension::Shm => crate::shm::request_name(minor_code),
287
288 #[cfg(feature = "sync")]
289 Extension::Sync => crate::sync::request_name(minor_code),
290
291 #[cfg(feature = "xevie")]
292 Extension::Xevie => crate::xevie::request_name(minor_code),
293
294 #[cfg(feature = "xf86dri")]
295 Extension::Xf86Dri => crate::xf86dri::request_name(minor_code),
296
297 #[cfg(feature = "xf86vidmode")]
298 Extension::Xf86VidMode => crate::xf86vidmode::request_name(minor_code),
299
300 #[cfg(feature = "xfixes")]
301 Extension::XFixes => crate::xfixes::request_name(minor_code),
302
303 #[cfg(feature = "xinerama")]
304 Extension::Xinerama => crate::xinerama::request_name(minor_code),
305
306 #[cfg(feature = "xinput")]
307 Extension::Input => crate::xinput::request_name(minor_code),
308
309 #[cfg(feature = "xkb")]
310 Extension::Xkb => crate::xkb::request_name(minor_code),
311
312 #[cfg(feature = "xprint")]
313 Extension::XPrint => crate::xprint::request_name(minor_code),
314
315 #[cfg(feature = "xselinux")]
316 Extension::SeLinux => crate::xselinux::request_name(minor_code),
317
318 #[cfg(feature = "xtest")]
319 Extension::Test => crate::xtest::request_name(minor_code),
320
321 #[cfg(feature = "xv")]
322 Extension::Xv => crate::xv::request_name(minor_code),
323
324 #[cfg(feature = "xvmc")]
325 Extension::XvMc => crate::xvmc::request_name(minor_code),
326 }
327 } else {
328 crate::x::request_name(major_code as u16)
329 };
330
331 let resolved: Option<ProtocolError> = if let Some(ext_data) = best {
332 match ext_data.ext {
333 #[cfg(feature = "damage")]
334 Extension::Damage => damage::Error::resolve_wire_error(ext_data.first_error, error)
335 .map(|e| ProtocolError::Damage(e, emitted_by)),
336
337 #[cfg(feature = "glx")]
338 Extension::Glx => glx::Error::resolve_wire_error(ext_data.first_error, error)
339 .map(|e| ProtocolError::Glx(e, emitted_by)),
340
341 #[cfg(feature = "randr")]
342 Extension::RandR => randr::Error::resolve_wire_error(ext_data.first_error, error)
343 .map(|e| ProtocolError::RandR(e, emitted_by)),
344
345 #[cfg(feature = "render")]
346 Extension::Render => render::Error::resolve_wire_error(ext_data.first_error, error)
347 .map(|e| ProtocolError::Render(e, emitted_by)),
348
349 #[cfg(feature = "shm")]
350 Extension::Shm => shm::Error::resolve_wire_error(ext_data.first_error, error)
351 .map(|e| ProtocolError::Shm(e, emitted_by)),
352
353 #[cfg(feature = "sync")]
354 Extension::Sync => sync::Error::resolve_wire_error(ext_data.first_error, error)
355 .map(|e| ProtocolError::Sync(e, emitted_by)),
356
357 #[cfg(feature = "xf86vidmode")]
358 Extension::Xf86VidMode => {
359 xf86vidmode::Error::resolve_wire_error(ext_data.first_error, error)
360 .map(|e| ProtocolError::Xf86VidMode(e, emitted_by))
361 }
362
363 #[cfg(feature = "xfixes")]
364 Extension::XFixes => xfixes::Error::resolve_wire_error(ext_data.first_error, error)
365 .map(|e| ProtocolError::XFixes(e, emitted_by)),
366
367 #[cfg(feature = "xinput")]
368 Extension::Input => xinput::Error::resolve_wire_error(ext_data.first_error, error)
369 .map(|e| ProtocolError::Input(e, emitted_by)),
370
371 #[cfg(feature = "xkb")]
372 Extension::Xkb => xkb::Error::resolve_wire_error(ext_data.first_error, error)
373 .map(|e| ProtocolError::Xkb(e, emitted_by)),
374
375 #[cfg(feature = "xprint")]
376 Extension::XPrint => xprint::Error::resolve_wire_error(ext_data.first_error, error)
377 .map(|e| ProtocolError::XPrint(e, emitted_by)),
378
379 #[cfg(feature = "xv")]
380 Extension::Xv => xv::Error::resolve_wire_error(ext_data.first_error, error)
381 .map(|e| ProtocolError::Xv(e, emitted_by)),
382
383 _ => None,
384 }
385 } else {
386 x::Error::resolve_wire_error(0, error).map(|e| ProtocolError::X(e, emitted_by))
387 };
388 resolved.unwrap_or_else(|| ProtocolError::Unknown(UnknownError::from_raw(error), emitted_by))
389}
390
391#[cfg(all(feature = "xinput", feature = "xkb", feature = "screensaver"))]
392#[test]
393fn test_resolve_error() {
394 let mut error = xcb_generic_error_t {
396 response_type: 0,
397 error_code: 2,
398 sequence: 12000,
399 resource_id: 12,
400 minor_code: 0,
401 major_code: 4,
402 pad0: 0,
403 pad: [0; 5],
404 full_sequence: 12000,
405 };
406 let extension_data = [];
407 let err = unsafe { resolve_error(&mut error as *mut _, &extension_data) };
408 assert!(
409 matches!(err, ProtocolError::X(x::Error::Value(_), Some(req_name)) if req_name == "x::DestroyWindow")
410 );
411 mem::forget(err);
412
413 let mut error = xcb_generic_error_t {
415 response_type: 0,
416 error_code: 2,
417 sequence: 12000,
418 resource_id: 12,
419 minor_code: 4,
420 major_code: 100,
421 pad0: 0,
422 pad: [0; 5],
423 full_sequence: 12000,
424 };
425 let extension_data = [
426 ExtensionData {
427 ext: Extension::Input,
428 major_opcode: 100,
429 first_event: 50,
430 first_error: 20,
431 },
432 ExtensionData {
433 ext: Extension::Xkb,
434 major_opcode: 200,
435 first_event: 80,
436 first_error: 40,
437 },
438 ];
439 let err = unsafe { resolve_error(&mut error as *mut _, &extension_data) };
440 assert!(
441 matches!(err, ProtocolError::X(x::Error::Value(_), Some(req_name)) if req_name == "xinput::CloseDevice")
442 );
443 mem::forget(err);
444
445 let mut error = xcb_generic_error_t {
447 response_type: 0,
448 error_code: 22,
449 sequence: 12000,
450 resource_id: 12,
451 minor_code: 4,
452 major_code: 100,
453 pad0: 0,
454 pad: [0; 5],
455 full_sequence: 12000,
456 };
457 let extension_data = [
458 ExtensionData {
459 ext: Extension::Input,
460 major_opcode: 100,
461 first_event: 50,
462 first_error: 20,
463 },
464 ExtensionData {
465 ext: Extension::Xkb,
466 major_opcode: 200,
467 first_event: 80,
468 first_error: 40,
469 },
470 ];
471 let err = unsafe { resolve_error(&mut error as *mut _, &extension_data) };
472 assert!(
473 matches!(err, ProtocolError::Input(xinput::Error::Mode(_), Some(req_name)) if req_name == "xinput::CloseDevice")
474 );
475 mem::forget(err);
476
477 let mut error = xcb_generic_error_t {
479 response_type: 0,
480 error_code: 22,
481 sequence: 12000,
482 resource_id: 12,
483 minor_code: 4,
484 major_code: 100,
485 pad0: 0,
486 pad: [0; 5],
487 full_sequence: 12000,
488 };
489 let extension_data = [
490 ExtensionData {
491 ext: Extension::Input,
492 major_opcode: 100,
493 first_event: 50,
494 first_error: 20,
495 },
496 ExtensionData {
497 ext: Extension::Xkb,
498 major_opcode: 200,
499 first_event: 80,
500 first_error: 40,
501 },
502 ];
503 let err = unsafe { resolve_error(&mut error as *mut _, &extension_data) };
504 assert!(
505 matches!(err, ProtocolError::Input(xinput::Error::Mode(_), Some(req_name)) if req_name == "xinput::CloseDevice")
506 );
507 mem::forget(err);
508
509 let mut error = xcb_generic_error_t {
511 response_type: 0,
512 error_code: 2,
513 sequence: 12000,
514 resource_id: 12,
515 minor_code: 0,
516 major_code: 1,
517 pad0: 0,
518 pad: [0; 5],
519 full_sequence: 12000,
520 };
521 let extension_data = [ExtensionData {
522 ext: Extension::ScreenSaver,
523 major_opcode: 144,
524 first_event: 92,
525 first_error: 0,
526 }];
527 let err = unsafe { resolve_error(&mut error as *mut _, &extension_data) };
528 assert!(
529 matches!(err, ProtocolError::X(x::Error::Value(_), Some(req_name)) if req_name == "x::CreateWindow")
530 );
531 mem::forget(err);
532}