1use crate::error::{XcbError, XcbErrorParser};
2use crate::format::XcbDataType;
3use std::{ptr, slice};
4use thiserror::Error;
5use xcb_dl::ffi::*;
6use xcb_dl::*;
7
8#[derive(Clone, Debug, Error)]
9pub enum XcbGetPropertyError {
10 #[error("Invalid property type (expected: {expected}, actual: {actual})")]
11 InvalidPropertyType {
12 expected: xcb_atom_t,
13 actual: xcb_atom_t,
14 },
15 #[error("Invalid property format (expected: {expected}, actual: {actual})")]
16 InvalidPropertyFormat { expected: u8, actual: u8 },
17 #[error("The property is not set")]
18 Unset,
19 #[error("xcb error: {0}")]
20 Xcb(#[from] XcbError),
21}
22
23pub unsafe fn get_property<T: XcbDataType>(
24 xcb: &Xcb,
25 errors: &XcbErrorParser,
26 window: xcb_window_t,
27 property: xcb_atom_t,
28 type_: xcb_atom_t,
29 delete: bool,
30 step: u32,
31) -> Result<Vec<T>, XcbGetPropertyError> {
32 let mut buf = vec![];
33 get_property_in(xcb, errors, window, property, type_, delete, step, &mut buf)?;
34 Ok(buf)
35}
36
37pub unsafe fn get_property_in<T: XcbDataType>(
38 xcb: &Xcb,
39 errors: &XcbErrorParser,
40 window: xcb_window_t,
41 property: xcb_atom_t,
42 type_: xcb_atom_t,
43 delete: bool,
44 step: u32,
45 buf: &mut Vec<T>,
46) -> Result<(), XcbGetPropertyError> {
47 let mut offset = 0;
48 loop {
49 let mut err = ptr::null_mut();
50 let res = xcb.xcb_get_property_reply(
51 errors.c,
52 xcb.xcb_get_property(
53 errors.c,
54 delete as u8,
55 window,
56 property,
57 type_,
58 offset,
59 step,
60 ),
61 &mut err,
62 );
63 let res = errors.check(xcb, res, err)?;
64 if res.type_ != type_ {
65 if res.type_ == 0 {
66 return Err(XcbGetPropertyError::Unset);
67 }
68 return Err(XcbGetPropertyError::InvalidPropertyType {
69 expected: type_,
70 actual: res.type_,
71 });
72 }
73 if res.format != T::XCB_BITS {
74 return Err(XcbGetPropertyError::InvalidPropertyFormat {
75 expected: T::XCB_BITS,
76 actual: res.format,
77 });
78 }
79 let value = xcb.xcb_get_property_value(&*res);
80 buf.extend_from_slice(slice::from_raw_parts(
81 value as *const T,
82 res.value_len as usize,
83 ));
84 if res.bytes_after == 0 {
85 break;
86 }
87 offset += step;
88 }
89 Ok(())
90}