Skip to main content

xcb_dl_util/
property.rs

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}