xcb/
error.rs

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/// A protocol error issued from the X server
44///
45/// The second member is the name of the request that emitted the error (if any).
46#[derive(Debug)]
47pub enum ProtocolError {
48    /// The error is from the core X protocol.
49    X(x::Error, Option<&'static str>),
50
51    #[cfg(feature = "damage")]
52    /// The error is issued from the `DAMAGE` extension.
53    Damage(damage::Error, Option<&'static str>),
54
55    #[cfg(feature = "glx")]
56    /// The error is issued from the `GLX` extension.
57    Glx(glx::Error, Option<&'static str>),
58
59    #[cfg(feature = "randr")]
60    /// The error is issued from the `RANDR` extension.
61    RandR(randr::Error, Option<&'static str>),
62
63    #[cfg(feature = "render")]
64    /// The error is issued from the `RENDER` extension.
65    Render(render::Error, Option<&'static str>),
66
67    #[cfg(feature = "shm")]
68    /// The error is issued from the `MIT-SHM` extension.
69    Shm(shm::Error, Option<&'static str>),
70
71    #[cfg(feature = "sync")]
72    /// The error is issued from the `SYNC` extension.
73    Sync(sync::Error, Option<&'static str>),
74
75    #[cfg(feature = "xf86vidmode")]
76    /// The error is issued from the `XFree86-VidModeExtension` extension.
77    Xf86VidMode(xf86vidmode::Error, Option<&'static str>),
78
79    #[cfg(feature = "xfixes")]
80    /// The error is issued from the `XFIXES` extension.
81    XFixes(xfixes::Error, Option<&'static str>),
82
83    #[cfg(feature = "xinput")]
84    /// The error is issued from the `XInputExtension` extension.
85    Input(xinput::Error, Option<&'static str>),
86
87    #[cfg(feature = "xkb")]
88    /// The error is issued from the `XKEYBOARD` extension.
89    Xkb(xkb::Error, Option<&'static str>),
90
91    #[cfg(feature = "xprint")]
92    /// The error is issued from the `XpExtension` extension.
93    XPrint(xprint::Error, Option<&'static str>),
94
95    #[cfg(feature = "xv")]
96    /// The error is issued from the `XVideo` extension.
97    Xv(xv::Error, Option<&'static str>),
98
99    /// The error is unknown.
100    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
144/// an error that was not recognized as part of the core protocol or any enabled extension
145pub 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
200/// Resolve an error from the X server
201///
202/// If the error originates from an extension, the `extension_data` parameter must contain the
203/// data for the extension of origin.
204/// If the resolution fails, an `ProtocolError::Unknown` is returned.
205///
206/// # Safety
207/// The caller must ensure that `error` is a valid pointer to an `xcb_generic_error_t`.
208pub 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    // resolve a core error with core request
395    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    // resolve a core error with xinput request
414    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    // resolve a xinput error with xinput request
446    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    // same as previous, but reverse order of extension data
478    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    // mimic a regular X error (value) with extension that do not have errors (screensaver)
510    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}