Skip to main content

xcb_dl_util/
error.rs

1#![allow(non_camel_case_types)]
2
3use crate::xcb_box::XcbBox;
4use bstr::ByteSlice;
5use std::collections::HashMap;
6use std::error::Error;
7use std::fmt::{Debug, Display, Formatter};
8use std::os::raw::c_int;
9use std::{ptr, slice};
10use thiserror::Error;
11use xcb_dl::ffi::*;
12use xcb_dl::Xcb;
13
14#[derive(Clone, Debug)]
15pub struct XcbError {
16    pub error_code: u8,
17    pub sequence: u32,
18    pub major: u8,
19    pub minor: u16,
20    pub ty: XcbErrorType,
21}
22
23impl Display for XcbError {
24    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
25        Display::fmt(&self.ty, f)
26    }
27}
28
29impl Error for XcbError {}
30
31impl From<XcbErrorType> for XcbError {
32    fn from(e: XcbErrorType) -> Self {
33        Self {
34            error_code: 0,
35            sequence: 0,
36            major: 0,
37            minor: 0,
38            ty: e,
39        }
40    }
41}
42
43#[derive(Clone, Error, Debug)]
44#[non_exhaustive]
45pub enum XcbConnectionError {
46    #[error("An unknown error occurred: {0}")]
47    Unknown(c_int),
48    #[error("An IO error occurred")]
49    Io,
50    #[error("The user tried to send a request with an unsupported extension")]
51    UnsupportedExtension,
52    #[error("Out of memory")]
53    OutOfMemory,
54    #[error("The user tried to send a request that is too large for the X server")]
55    MessageLength,
56    #[error("libxcb was unable to parse the DISPLAY string")]
57    DisplayString,
58    #[error("The requested screen is not available")]
59    InvalidScreen,
60    #[error("An error occurred while handling file descriptors passed to and from the X server")]
61    FileDescriptors,
62}
63
64impl From<c_int> for XcbConnectionError {
65    fn from(e: c_int) -> Self {
66        match e {
67            XCB_CONN_ERROR => XcbConnectionError::Io,
68            XCB_CONN_CLOSED_EXT_NOTSUPPORTED => XcbConnectionError::UnsupportedExtension,
69            XCB_CONN_CLOSED_MEM_INSUFFICIENT => XcbConnectionError::OutOfMemory,
70            XCB_CONN_CLOSED_REQ_LEN_EXCEED => XcbConnectionError::MessageLength,
71            XCB_CONN_CLOSED_PARSE_ERR => XcbConnectionError::DisplayString,
72            XCB_CONN_CLOSED_INVALID_SCREEN => XcbConnectionError::InvalidScreen,
73            XCB_CONN_CLOSED_FDPASSING_FAILED => XcbConnectionError::FileDescriptors,
74            _ => XcbConnectionError::Unknown(e),
75        }
76    }
77}
78
79#[derive(Clone, Error, Debug)]
80#[non_exhaustive]
81pub enum XcbErrorType {
82    #[error("An unknown error occurred: {0:?}")]
83    Unknown(xcb_generic_error_t),
84    #[error("The X server did not send a reply to a request")]
85    MissingReply,
86    #[error("The connection was terminated due to an error: {0}")]
87    Connection(XcbConnectionError),
88    #[error(transparent)]
89    Core(core::CoreError),
90    #[error("XVideo extension error: {0}")]
91    Xv(xv::XvError),
92    #[error("XFIXES extension error: {0}")]
93    Xfixes(xfixes::XfixesError),
94    #[error("SHM extension error: {0}")]
95    Shm(shm::ShmError),
96    #[error("DAMAGE extension error: {0}")]
97    Damage(damage::DamageError),
98    #[error("Print extension error: {0}")]
99    XPrint(x_print::XPrintError),
100    #[error("RANDR extension error: {0}")]
101    Randr(randr::RandrError),
102    #[error("RENDER extension error: {0}")]
103    Render(render::RenderError),
104    #[error("SYNC extension error: {0}")]
105    Sync(sync::SyncError),
106    #[error("RECORD extension error: {0}")]
107    Record(record::RecordError),
108    #[error("XKEYBOARD extension error: {0}")]
109    Xkb(xkb::XkbError),
110    #[error("GLX extension error: {0}")]
111    Glx(glx::GlxError),
112    #[error("XInput extension error: {0}")]
113    Input(input::InputError),
114}
115
116#[derive(Debug)]
117pub struct XcbErrorParser {
118    pub(crate) c: *mut xcb_connection_t,
119    parsers: Vec<ErrorParser>,
120}
121
122unsafe fn check_core_error(err: *mut xcb_generic_error_t) -> Result<(), XcbErrorType> {
123    if err.is_null() {
124        return Ok(());
125    }
126    let err = XcbBox::new(err);
127    let mut error_code = err.error_code;
128    assert!(error_code > 0);
129    error_code -= 1;
130    assert!(error_code < core::CONFIG.num_errors);
131    Err((core::CONFIG.parse)(error_code, &*err))
132}
133
134impl XcbErrorParser {
135    pub unsafe fn new(xcb: &Xcb, c: *mut xcb_connection_t) -> Self {
136        let mut bases = HashMap::new();
137        loop {
138            let mut err = ptr::null_mut();
139            let extensions = xcb.xcb_list_extensions_reply(c, xcb.xcb_list_extensions(c), &mut err);
140            if let Err(e) = check_core_error(err) {
141                log::error!("Could not list extensions: {}", e);
142                break;
143            }
144            let extensions = XcbBox::new(extensions);
145            let mut names_iter = xcb.xcb_list_extensions_names_iterator(&*extensions);
146            while names_iter.rem > 0 {
147                let name = xcb.xcb_str_name(names_iter.data);
148                let len = (*names_iter.data).name_len;
149                let ext = xcb.xcb_query_extension_reply(
150                    c,
151                    xcb.xcb_query_extension(c, len as _, name),
152                    &mut err,
153                );
154                if let Err(e) = check_core_error(err) {
155                    log::error!("Could not query extension: {}", e);
156                    continue;
157                }
158                let ext = XcbBox::new(ext);
159                let name = slice::from_raw_parts(name as *const u8, len as _);
160                bases.insert(name, ext.first_error);
161                xcb.xcb_str_next(&mut names_iter);
162            }
163            break;
164        }
165
166        let mut parsers = vec![];
167        for config in CONFIGS {
168            let min = match config.name {
169                Some(name) => bases.get(name).cloned(),
170                _ => Some(1),
171            };
172            if let Some(min) = min {
173                parsers.push(ErrorParser {
174                    min,
175                    max_plus_1: min + config.num_errors,
176                    config: *config,
177                });
178            }
179        }
180        parsers.sort_by_key(|p| p.min);
181        for w in parsers.windows(2) {
182            assert!(w[0].max_plus_1 <= w[1].min);
183        }
184        Self { c, parsers }
185    }
186
187    pub unsafe fn parse(&self, e: &xcb_generic_error_t) -> XcbError {
188        let ty = 'outer: loop {
189            for p in &self.parsers {
190                if p.min <= e.error_code && e.error_code < p.max_plus_1 {
191                    break 'outer (p.config.parse)(e.error_code - p.min, e);
192                }
193            }
194            break XcbErrorType::Unknown(*e);
195        };
196        XcbError {
197            error_code: e.error_code,
198            sequence: e.full_sequence,
199            major: e.major_code,
200            minor: e.minor_code,
201            ty,
202        }
203    }
204
205    #[inline]
206    pub unsafe fn check<T>(
207        &self,
208        xcb: &Xcb,
209        t: *mut T,
210        e: *mut xcb_generic_error_t,
211    ) -> Result<XcbBox<T>, XcbError> {
212        if !e.is_null() {
213            let e = XcbBox::new(e);
214            Err(self.parse(&e))
215        } else {
216            self.check_val(xcb, t)
217        }
218    }
219
220    #[inline]
221    pub unsafe fn check_val<T>(&self, xcb: &Xcb, t: *mut T) -> Result<XcbBox<T>, XcbError> {
222        if t.is_null() {
223            self.check_connection(xcb)
224                .and(Err(XcbErrorType::MissingReply.into()))
225        } else {
226            Ok(XcbBox::new(t))
227        }
228    }
229
230    #[inline]
231    pub unsafe fn check_connection(&self, xcb: &Xcb) -> Result<(), XcbError> {
232        let e = xcb.xcb_connection_has_error(self.c);
233        if e == 0 {
234            Ok(())
235        } else {
236            Err(XcbErrorType::Connection(e.into()).into())
237        }
238    }
239
240    #[inline]
241    pub unsafe fn check_err(&self, e: *mut xcb_generic_error_t) -> Result<(), XcbError> {
242        if !e.is_null() {
243            let e = XcbBox::new(e);
244            Err(self.parse(&e))
245        } else {
246            Ok(())
247        }
248    }
249
250    #[inline]
251    pub unsafe fn check_cookie(
252        &self,
253        xcb: &Xcb,
254        cookie: xcb_void_cookie_t,
255    ) -> Result<(), XcbError> {
256        let err = xcb.xcb_request_check(self.c, cookie);
257        self.check_err(err)
258    }
259}
260
261struct ErrorParser {
262    min: u8,
263    max_plus_1: u8,
264    config: &'static ErrorConfig,
265}
266
267impl Debug for ErrorParser {
268    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
269        let name = self.config.name.unwrap_or(b"Core");
270        write!(
271            f,
272            "{}([{}, {}])",
273            name.as_bstr(),
274            self.min,
275            self.max_plus_1 - 1
276        )
277    }
278}
279
280struct ErrorConfig {
281    name: Option<&'static [u8]>,
282    num_errors: u8,
283    parse: unsafe fn(error_code: u8, e: *const xcb_generic_error_t) -> XcbErrorType,
284}
285
286const CONFIGS: &[&ErrorConfig] = &[
287    &core::CONFIG,
288    &xv::CONFIG,
289    &xfixes::CONFIG,
290    &shm::CONFIG,
291    &damage::CONFIG,
292    &x_print::CONFIG,
293    &randr::CONFIG,
294    &render::CONFIG,
295    &sync::CONFIG,
296    &record::CONFIG,
297    &xkb::CONFIG,
298    &glx::CONFIG,
299    &input::CONFIG,
300];
301
302pub mod core {
303    use super::*;
304
305    #[derive(Clone, Debug, Error)]
306    #[error("{ty} (major: {major_opcode}, minor: {minor_opcode})")]
307    pub struct CoreError {
308        pub major_opcode: u8,
309        pub minor_opcode: u16,
310        pub ty: CoreErrorType,
311    }
312
313    #[derive(Clone, Debug)]
314    pub struct RequestError {
315        pub bad_value: u32,
316    }
317
318    #[derive(Clone, Debug)]
319    pub struct ValueError {
320        pub bad_value: u32,
321    }
322
323    #[derive(Clone, Debug, Error)]
324    pub enum CoreErrorType {
325        #[error("Request error (bad value: {})", .0.bad_value)]
326        Request(RequestError),
327        #[error("Value error (bad value: {})", .0.bad_value)]
328        Value(ValueError),
329        #[error("Window error (bad value: {})", .0.bad_value)]
330        Window(ValueError),
331        #[error("Pixmap error (bad value: {})", .0.bad_value)]
332        Pixmap(ValueError),
333        #[error("Atom error (bad value: {})", .0.bad_value)]
334        Atom(ValueError),
335        #[error("Cursor error (bad value: {})", .0.bad_value)]
336        Cursor(ValueError),
337        #[error("Font error (bad value: {})", .0.bad_value)]
338        Font(ValueError),
339        #[error("Match error (bad value: {})", .0.bad_value)]
340        Match(RequestError),
341        #[error("Drawable error (bad value: {})", .0.bad_value)]
342        Drawable(ValueError),
343        #[error("Access error (bad value: {})", .0.bad_value)]
344        Access(RequestError),
345        #[error("Alloc error (bad value: {})", .0.bad_value)]
346        Alloc(RequestError),
347        #[error("Colormap error (bad value: {})", .0.bad_value)]
348        Colormap(ValueError),
349        #[error("GContext error (bad value: {})", .0.bad_value)]
350        GContext(ValueError),
351        #[error("IDChoice error (bad value: {})", .0.bad_value)]
352        IDChoice(ValueError),
353        #[error("Name error (bad value: {})", .0.bad_value)]
354        Name(RequestError),
355        #[error("Length error (bad value: {})", .0.bad_value)]
356        Length(RequestError),
357        #[error("Implementation error (bad value: {})", .0.bad_value)]
358        Implementation(RequestError),
359    }
360
361    pub(super) const CONFIG: ErrorConfig = ErrorConfig {
362        name: None,
363        num_errors: 17,
364        parse,
365    };
366
367    unsafe fn parse(error_code: u8, e: *const xcb_generic_error_t) -> XcbErrorType {
368        let e = &*(e as *const xcb_request_error_t);
369        let ty = match error_code {
370            0 => CoreErrorType::Request(RequestError {
371                bad_value: e.bad_value,
372            }),
373            1 => CoreErrorType::Value(ValueError {
374                bad_value: e.bad_value,
375            }),
376            2 => CoreErrorType::Window(ValueError {
377                bad_value: e.bad_value,
378            }),
379            3 => CoreErrorType::Pixmap(ValueError {
380                bad_value: e.bad_value,
381            }),
382            4 => CoreErrorType::Atom(ValueError {
383                bad_value: e.bad_value,
384            }),
385            5 => CoreErrorType::Cursor(ValueError {
386                bad_value: e.bad_value,
387            }),
388            6 => CoreErrorType::Font(ValueError {
389                bad_value: e.bad_value,
390            }),
391            7 => CoreErrorType::Match(RequestError {
392                bad_value: e.bad_value,
393            }),
394            8 => CoreErrorType::Drawable(ValueError {
395                bad_value: e.bad_value,
396            }),
397            9 => CoreErrorType::Access(RequestError {
398                bad_value: e.bad_value,
399            }),
400            10 => CoreErrorType::Alloc(RequestError {
401                bad_value: e.bad_value,
402            }),
403            11 => CoreErrorType::Colormap(ValueError {
404                bad_value: e.bad_value,
405            }),
406            12 => CoreErrorType::GContext(ValueError {
407                bad_value: e.bad_value,
408            }),
409            13 => CoreErrorType::IDChoice(ValueError {
410                bad_value: e.bad_value,
411            }),
412            14 => CoreErrorType::Name(RequestError {
413                bad_value: e.bad_value,
414            }),
415            15 => CoreErrorType::Length(RequestError {
416                bad_value: e.bad_value,
417            }),
418            16 => CoreErrorType::Implementation(RequestError {
419                bad_value: e.bad_value,
420            }),
421            _ => unreachable!(),
422        };
423        XcbErrorType::Core(CoreError {
424            major_opcode: e.major_opcode,
425            minor_opcode: e.minor_opcode,
426            ty,
427        })
428    }
429}
430
431pub mod xv {
432    use super::*;
433
434    #[derive(Clone, Debug, Error)]
435    pub enum XvError {
436        #[error("Bad port")]
437        BadPort,
438        #[error("Bad encoding")]
439        BadEncoding,
440        #[error("Bad control")]
441        BadControl,
442    }
443
444    const XCB_XV_NAME: &[u8] = b"XVideo";
445
446    pub(super) const CONFIG: ErrorConfig = ErrorConfig {
447        name: Some(XCB_XV_NAME),
448        num_errors: 3,
449        parse,
450    };
451
452    unsafe fn parse(error_code: u8, _e: *const xcb_generic_error_t) -> XcbErrorType {
453        let e = match error_code {
454            0 => XvError::BadPort,
455            1 => XvError::BadEncoding,
456            2 => XvError::BadControl,
457            _ => unreachable!(),
458        };
459        XcbErrorType::Xv(e)
460    }
461}
462
463pub mod xfixes {
464    use super::*;
465
466    const XCB_XFIXES_NAME: &[u8] = b"XFIXES";
467
468    #[derive(Clone, Debug, Error)]
469    pub enum XfixesError {
470        #[error("Bad region")]
471        BadRegion,
472    }
473
474    pub(super) const CONFIG: ErrorConfig = ErrorConfig {
475        name: Some(XCB_XFIXES_NAME),
476        num_errors: 1,
477        parse,
478    };
479
480    unsafe fn parse(_error_code: u8, _e: *const xcb_generic_error_t) -> XcbErrorType {
481        XcbErrorType::Xfixes(XfixesError::BadRegion)
482    }
483}
484
485pub mod shm {
486    use super::*;
487    use crate::error::core::ValueError;
488
489    const XCB_SHM_NAME: &[u8] = b"MIT-SHM";
490
491    #[repr(C)]
492    struct xcb_value_error_t {
493        pub response_type: u8,
494        pub error_code: u8,
495        pub sequence: u16,
496        pub bad_value: u32,
497        pub minor_opcode: u16,
498        pub major_opcode: u8,
499        pub pad0: u8,
500    }
501
502    type xcb_shm_bad_seg_error_t = xcb_value_error_t;
503
504    #[derive(Clone, Debug, Error)]
505    #[error("{ty} (major: {major_opcode}, minor: {minor_opcode})")]
506    pub struct ShmError {
507        pub major_opcode: u8,
508        pub minor_opcode: u16,
509        pub ty: ShmErrorType,
510    }
511
512    #[derive(Clone, Debug, Error)]
513    pub enum ShmErrorType {
514        #[error("Bad segment (bad value: {})", .0.bad_value)]
515        BadSeg(ValueError),
516    }
517
518    pub(super) const CONFIG: ErrorConfig = ErrorConfig {
519        name: Some(XCB_SHM_NAME),
520        num_errors: 1,
521        parse,
522    };
523
524    unsafe fn parse(_error_code: u8, e: *const xcb_generic_error_t) -> XcbErrorType {
525        let e = &*(e as *const xcb_shm_bad_seg_error_t);
526        XcbErrorType::Shm(ShmError {
527            major_opcode: e.major_opcode,
528            minor_opcode: e.minor_opcode,
529            ty: ShmErrorType::BadSeg(ValueError {
530                bad_value: e.bad_value,
531            }),
532        })
533    }
534}
535
536pub mod damage {
537    use super::*;
538
539    const XCB_DAMAGE_NAME: &[u8] = b"DAMAGE";
540
541    #[derive(Clone, Debug, Error)]
542    pub enum DamageError {
543        #[error("Bad damage")]
544        BadDamage,
545    }
546
547    pub(super) const CONFIG: ErrorConfig = ErrorConfig {
548        name: Some(XCB_DAMAGE_NAME),
549        num_errors: 1,
550        parse,
551    };
552
553    unsafe fn parse(_error_code: u8, _e: *const xcb_generic_error_t) -> XcbErrorType {
554        XcbErrorType::Damage(DamageError::BadDamage)
555    }
556}
557
558pub mod x_print {
559    use super::*;
560
561    const XCB_X_PRINT_NAME: &[u8] = b"XpExtension";
562
563    #[derive(Clone, Debug, Error)]
564    pub enum XPrintError {
565        #[error("Bad context")]
566        BadContext,
567        #[error("Bad sequence")]
568        BadSequence,
569    }
570
571    pub(super) const CONFIG: ErrorConfig = ErrorConfig {
572        name: Some(XCB_X_PRINT_NAME),
573        num_errors: 2,
574        parse,
575    };
576
577    unsafe fn parse(error_code: u8, _e: *const xcb_generic_error_t) -> XcbErrorType {
578        let e = match error_code {
579            0 => XPrintError::BadContext,
580            1 => XPrintError::BadSequence,
581            _ => unreachable!(),
582        };
583        XcbErrorType::XPrint(e)
584    }
585}
586
587pub mod randr {
588    use super::*;
589
590    const XCB_RANDR_NAME: &[u8] = b"RANDR";
591
592    #[derive(Clone, Debug, Error)]
593    pub enum RandrError {
594        #[error("Bad output")]
595        BadOutput,
596        #[error("Bad crtc")]
597        BadCrtc,
598        #[error("Bad mode")]
599        BadMode,
600        #[error("Bad provider")]
601        BadProvider,
602    }
603
604    pub(super) const CONFIG: ErrorConfig = ErrorConfig {
605        name: Some(XCB_RANDR_NAME),
606        num_errors: 4,
607        parse,
608    };
609
610    unsafe fn parse(error_code: u8, _e: *const xcb_generic_error_t) -> XcbErrorType {
611        let e = match error_code {
612            0 => RandrError::BadOutput,
613            1 => RandrError::BadCrtc,
614            2 => RandrError::BadMode,
615            3 => RandrError::BadProvider,
616            _ => unreachable!(),
617        };
618        XcbErrorType::Randr(e)
619    }
620}
621
622pub mod render {
623    use super::*;
624
625    const XCB_RENDER_NAME: &[u8] = b"RENDER";
626
627    #[derive(Clone, Debug, Error)]
628    pub enum RenderError {
629        #[error("Invalid picture format")]
630        PictFormat,
631        #[error("Invalid picture")]
632        Picture,
633        #[error("Invalid picture operation")]
634        PictOp,
635        #[error("Invalid glyph set")]
636        GlyphSet,
637        #[error("Invalid glyph")]
638        Glyph,
639    }
640
641    pub(super) const CONFIG: ErrorConfig = ErrorConfig {
642        name: Some(XCB_RENDER_NAME),
643        num_errors: 5,
644        parse,
645    };
646
647    unsafe fn parse(error_code: u8, _e: *const xcb_generic_error_t) -> XcbErrorType {
648        let e = match error_code {
649            0 => RenderError::PictFormat,
650            1 => RenderError::Picture,
651            2 => RenderError::PictOp,
652            3 => RenderError::GlyphSet,
653            4 => RenderError::Glyph,
654            _ => unreachable!(),
655        };
656        XcbErrorType::Render(e)
657    }
658}
659
660pub mod sync {
661    use super::*;
662
663    const XCB_SYNC_NAME: &[u8] = b"SYNC";
664
665    #[repr(C)]
666    struct xcb_sync_counter_error_t {
667        pub response_type: u8,
668        pub error_code: u8,
669        pub sequence: u16,
670        pub bad_counter: u32,
671        pub minor_opcode: u16,
672        pub major_opcode: u8,
673    }
674
675    #[derive(Clone, Debug)]
676    pub struct CounterError {
677        pub bad_counter: u32,
678    }
679
680    #[derive(Clone, Debug)]
681    pub struct AlarmError {
682        pub bad_alarm: u32,
683    }
684
685    #[derive(Clone, Debug, Error)]
686    #[error("{ty} (major: {major_opcode}, minor: {minor_opcode})")]
687    pub struct SyncError {
688        pub major_opcode: u8,
689        pub minor_opcode: u16,
690        pub ty: SyncErrorType,
691    }
692
693    #[derive(Clone, Debug, Error)]
694    pub enum SyncErrorType {
695        #[error("Bad counter {}", .0.bad_counter)]
696        Counter(CounterError),
697        #[error("Bad alarm {}", .0.bad_alarm)]
698        Alarm(AlarmError),
699    }
700
701    pub(super) const CONFIG: ErrorConfig = ErrorConfig {
702        name: Some(XCB_SYNC_NAME),
703        num_errors: 2,
704        parse,
705    };
706
707    unsafe fn parse(error_code: u8, e: *const xcb_generic_error_t) -> XcbErrorType {
708        let e = &*(e as *const xcb_sync_counter_error_t);
709        let ty = match error_code {
710            0 => SyncErrorType::Counter(CounterError {
711                bad_counter: e.bad_counter,
712            }),
713            1 => SyncErrorType::Alarm(AlarmError {
714                bad_alarm: e.bad_counter,
715            }),
716            _ => unreachable!(),
717        };
718        XcbErrorType::Sync(SyncError {
719            major_opcode: e.major_opcode,
720            minor_opcode: e.minor_opcode,
721            ty,
722        })
723    }
724}
725
726pub mod record {
727    use super::*;
728
729    const XCB_RECORD_NAME: &[u8] = b"RECORD";
730
731    #[repr(C)]
732    struct xcb_record_bad_context_error_t {
733        pub response_type: u8,
734        pub error_code: u8,
735        pub sequence: u16,
736        pub invalid_record: u32,
737    }
738
739    #[derive(Clone, Debug)]
740    pub struct BadContext {
741        pub invalid_record: u32,
742    }
743
744    #[derive(Clone, Debug, Error)]
745    pub enum RecordError {
746        #[error("Bad context (invalid record: {})", .0.invalid_record)]
747        BadContext(BadContext),
748    }
749
750    pub(super) const CONFIG: ErrorConfig = ErrorConfig {
751        name: Some(XCB_RECORD_NAME),
752        num_errors: 1,
753        parse,
754    };
755
756    unsafe fn parse(_error_code: u8, e: *const xcb_generic_error_t) -> XcbErrorType {
757        let e = &*(e as *const xcb_record_bad_context_error_t);
758        XcbErrorType::Record(RecordError::BadContext(BadContext {
759            invalid_record: e.invalid_record,
760        }))
761    }
762}
763
764pub mod xkb {
765    use super::*;
766
767    const XCB_XKB_NAME: &[u8] = b"XKEYBOARD";
768
769    #[repr(C)]
770    struct xcb_xkb_keyboard_error_t {
771        pub response_type: u8,
772        pub error_code: u8,
773        pub sequence: u16,
774        pub value: u32,
775        pub minor_opcode: u16,
776        pub major_opcode: u8,
777        pub pad0: [u8; 21],
778    }
779
780    bitflags::bitflags! {
781        pub struct XkbKeyboardError: u32 {
782            const BAD_DEVICE = 255;
783            const BAD_CLASS = 254;
784            const BAD_ID = 253;
785        }
786    }
787
788    #[derive(Clone, Debug, Error)]
789    #[error("{ty} (major: {major_opcode}, minor: {minor_opcode})")]
790    pub struct XkbError {
791        pub major_opcode: u8,
792        pub minor_opcode: u16,
793        pub ty: XkbErrorType,
794    }
795
796    #[derive(Clone, Debug, Error)]
797    pub enum XkbErrorType {
798        #[error("Keyboard error: {0:?}")]
799        Keyboard(XkbKeyboardError),
800    }
801
802    pub(super) const CONFIG: ErrorConfig = ErrorConfig {
803        name: Some(XCB_XKB_NAME),
804        num_errors: 1,
805        parse,
806    };
807
808    unsafe fn parse(_error_code: u8, e: *const xcb_generic_error_t) -> XcbErrorType {
809        let e = &*(e as *const xcb_xkb_keyboard_error_t);
810        XcbErrorType::Xkb(XkbError {
811            major_opcode: e.major_opcode,
812            minor_opcode: e.minor_opcode,
813            ty: XkbErrorType::Keyboard(XkbKeyboardError::from_bits_unchecked(e.value)),
814        })
815    }
816}
817
818pub mod glx {
819    use super::*;
820
821    const XCB_GLX_NAME: &[u8] = b"GLX";
822
823    #[repr(C)]
824    struct xcb_glx_generic_error_t {
825        pub response_type: u8,
826        pub error_code: u8,
827        pub sequence: u16,
828        pub bad_value: u32,
829        pub minor_opcode: u16,
830        pub major_opcode: u8,
831        pub pad0: [u8; 21],
832    }
833
834    #[derive(Clone, Debug)]
835    pub struct GenericError {
836        pub bad_value: u32,
837    }
838
839    #[derive(Clone, Debug, Error)]
840    #[error("{ty} (major: {major_opcode}, minor: {minor_opcode})")]
841    pub struct GlxError {
842        pub major_opcode: u8,
843        pub minor_opcode: u16,
844        pub ty: GlxErrorType,
845    }
846
847    #[derive(Clone, Debug, Error)]
848    pub enum GlxErrorType {
849        #[error("Bad context (bad value: {})", .0.bad_value)]
850        BadContext(GenericError),
851        #[error("Bad context state (bad value: {})", .0.bad_value)]
852        BadContextState(GenericError),
853        #[error("Bad drawable (bad value: {})", .0.bad_value)]
854        BadDrawable(GenericError),
855        #[error("Bad pixmap (bad value: {})", .0.bad_value)]
856        BadPixmap(GenericError),
857        #[error("Bad context tag (bad value: {})", .0.bad_value)]
858        BadContextTag(GenericError),
859        #[error("Bad current window (bad value: {})", .0.bad_value)]
860        BadCurrentWindow(GenericError),
861        #[error("Bad render request (bad value: {})", .0.bad_value)]
862        BadRenderRequest(GenericError),
863        #[error("Bad large request (bad value: {})", .0.bad_value)]
864        BadLargeRequest(GenericError),
865        #[error("Unsupported private request (bad value: {})", .0.bad_value)]
866        UnsupportedPrivateRequest(GenericError),
867        #[error("Bad framebuffer config (bad value: {})", .0.bad_value)]
868        BadFBConfig(GenericError),
869        #[error("Bad pixel buffer (bad value: {})", .0.bad_value)]
870        BadPbuffer(GenericError),
871        #[error("Bad current drawable (bad value: {})", .0.bad_value)]
872        BadCurrentDrawable(GenericError),
873        #[error("Bad window (bad value: {})", .0.bad_value)]
874        BadWindow(GenericError),
875        #[error("Bad profile (bad value: {})", .0.bad_value)]
876        GLXBadProfileARB(GenericError),
877    }
878
879    pub(super) const CONFIG: ErrorConfig = ErrorConfig {
880        name: Some(XCB_GLX_NAME),
881        num_errors: 14,
882        parse,
883    };
884
885    unsafe fn parse(error_code: u8, e: *const xcb_generic_error_t) -> XcbErrorType {
886        let e = &*(e as *const xcb_glx_generic_error_t);
887        let ge = GenericError {
888            bad_value: e.bad_value,
889        };
890        let ty = match error_code {
891            0 => GlxErrorType::BadContext(ge),
892            1 => GlxErrorType::BadContextState(ge),
893            2 => GlxErrorType::BadDrawable(ge),
894            3 => GlxErrorType::BadPixmap(ge),
895            4 => GlxErrorType::BadContextTag(ge),
896            5 => GlxErrorType::BadCurrentWindow(ge),
897            6 => GlxErrorType::BadRenderRequest(ge),
898            7 => GlxErrorType::BadLargeRequest(ge),
899            8 => GlxErrorType::UnsupportedPrivateRequest(ge),
900            9 => GlxErrorType::BadFBConfig(ge),
901            10 => GlxErrorType::BadPbuffer(ge),
902            11 => GlxErrorType::BadCurrentDrawable(ge),
903            12 => GlxErrorType::BadWindow(ge),
904            13 => GlxErrorType::GLXBadProfileARB(ge),
905            _ => unreachable!(),
906        };
907        XcbErrorType::Glx(GlxError {
908            major_opcode: e.major_opcode,
909            minor_opcode: e.minor_opcode,
910            ty,
911        })
912    }
913}
914
915pub mod input {
916    use super::*;
917
918    const XCB_INPUT_NAME: &[u8] = b"XInputExtension";
919
920    #[derive(Clone, Debug, Error)]
921    pub enum InputError {
922        #[error("Bad device")]
923        Device,
924        #[error("Bad event")]
925        Event,
926        #[error("Bad mode")]
927        Mode,
928        #[error("Device busy")]
929        DeviceBusy,
930        #[error("Bad class")]
931        Class,
932    }
933
934    pub(super) const CONFIG: ErrorConfig = ErrorConfig {
935        name: Some(XCB_INPUT_NAME),
936        num_errors: 5,
937        parse,
938    };
939
940    unsafe fn parse(error_code: u8, _e: *const xcb_generic_error_t) -> XcbErrorType {
941        let e = match error_code {
942            0 => InputError::Device,
943            1 => InputError::Event,
944            2 => InputError::Mode,
945            3 => InputError::DeviceBusy,
946            4 => InputError::Class,
947            _ => unreachable!(),
948        };
949        XcbErrorType::Input(e)
950    }
951}