I'm using XCB to ask X11 windows for PIDs of their processes, among other properties. My code to get various non-string attributes is as follows:
xcb_window_t wid;
xcb_connection_t * conn;
template <typename T>
T get_property(xcb_atom_t property, xcb_atom_t type, size_t len = sizeof(T)) {
xcb_generic_error_t *err = nullptr; // can't use unique_ptr here because get_property_reply overwrites pointer value
/*
Specifies how many 32-bit multiples of data should be retrieved
(e.g. if you set long_length to 4, you will receive 16 bytes of data).
*/
uint32_t ret_size =
len/sizeof(uint32_t) /*integer division, like floor()*/ +
!!(len%sizeof(uint32_t)) /*+1 if there was a remainder*/;
xcb_get_property_cookie_t cookie = xcb_get_property(
conn, 0, wid, property, type, 0, ret_size
);
std::unique_ptr<xcb_get_property_reply_t,decltype(&free)> reply {xcb_get_property_reply(conn, cookie, &err),&free};
if (!reply) {
free(err);
throw std::runtime_error("xcb_get_property returned error");
}
return *reinterpret_cast<T*>(
xcb_get_property_value(
reply.get()
)
);
}
xcb_atom_t NET_WM_PID; // initialized using xcb_intern_atom
// according to libxcb-ewmh, CARDINALs are uint32_t
pid_t pid = get_property<uint32_t>(NET_WM_PID, XCB_ATOM_CARDINAL);
The error handling is reproduced from xcb-requests(3). Problems arise when a window doesn't have _NET_WM_PID
property set (Worker file manager, for example, doesn't do so). In that case, instead of getting a nullptr
from xcb_get_property_reply
and non-null err
, I get a numeric answer equal to the sequence number of XCB request. How do I properly check if _NET_WM_PID
or other property of type CARDINAL
isn't set on a window?
Absence of a property is not an error. If the property is not set, format, type, and length in the reply will all be zero. You probably want to check all of them and verify they have values you expect them to have.