xcb-requests(3)
π xcb-requests β the manual page, bestie edition
okay so this is xcb-requests(3), and it's literally the "how do request manpages work" page from the XCB examples. if you've ever opened a manpage like xcb_map_window(3) and gone "wait what is all this", this is the girl explaining it to you. periodt. π
β¨ NAME β¨
xcb-requests β it's all about request manpages, like, the vibe and the lore behind every XCB request page you'll ever open π¦
πΈ DESCRIPTION πΈ
so. every single request in X11 β take MapWindow for example β corresponds to a whole little squad of functions and data structures in XCB. it's giving ensemble cast.
for MapWindow, XCB hands you the function xcb_map_window, which fills up the xcb_map_window_request_t data structure and then writes that whole thing to the X11 connection. and because the MapWindow request does not have a reply, this is genuinely the most simple case. the tutorial level. the starter pack. π
π REPLIES π
not me about to tell you that many requests DO have replies. and for each reply, XCB gives you at least a matching data structure plus a function that returns a pointer to a filled-in version of that structure. iconic behaviour, honestly.
let's take the InternAtom request as our example, because she's the main character here: XCB provides the xcb_intern_atom_reply_t data structure and the xcb_intern_atom_reply function. π
and for replies that are more complex β like lists, for instance the ones in xcb_list_fonts β accessor functions get provided too. so you're never out here digging through memory manually. we love a supportive API. π«Ά
π COOKIES π
okay so XCB returns a cookie for every request you send. and no, it's not a snack π it's an XCB-specific data structure containing the sequence number that the request was sent to the X11 server with.
to get any reply at all, you have to hand that cookie back β that's how XCB knows which of the waiting replies you actually want. it's the receipt, bestie. keep it.
here's an example showing cookies in action:
void my_example(xcb_connection *conn) {
xcb_intern_atom_cookie_t cookie;
xcb_intern_atom_reply_t *reply;
cookie = xcb_intern_atom(conn, 0, strlen("_NET_WM_NAME"), "_NET_WM_NAME");
/* ... do other work here if possible ... */
if ((reply = xcb_intern_atom_reply(conn, cookie, NULL))) {
printf("The _NET_WM_NAME atom has ID %u\n", reply->atom);
}
free(reply);
}
π CHECKED VS. UNCHECKED π
the checked and unchecked suffixes on functions are the whole entire vibe check for error handling on that specific request. they decide which kind of error handling gets used. choose wisely. π
requests with NO reply β for example xcb_map_window β errors get delivered to the event loop. so you'll receive an X11 event of type 0 when you call xcb_poll_for_event. if you instead want to explicitly check for errors in a blocking fashion, call the _checked version of the function (for example xcb_map_window_checked) and use xcb_request_check. π§
requests WITH a reply β for example xcb_intern_atom β errors get checked when you call the reply function. if you'd rather get those errors in the event loop instead, use the _unchecked version of the function (for example xcb_intern_atom_unchecked). π
and here's an example illustrating all four different ways of handling errors, because yes, there are four, and yes, you're gonna learn them:
/*
* Request without a reply, handling errors in the event loop (default)
*
*/
void my_example(xcb_connection *conn, xcb_window_t window) {
/* This is a request without a reply. Errors will be delivered to the event
* loop. Getting an error to xcb_map_window most likely is a bug in our
* program, so we don't need to check for that in a blocking way. */
xcb_map_window(conn, window);
/* ... of course your event loop would not be in the same function ... */
while ((event = xcb_wait_for_event(conn)) != NULL) {
if (event->response_type == 0) {
fprintf("Received X11 error %d\n", error->error_code);
free(event);
continue;
}
/* ... handle a normal event ... */
}
}
/*
* Request without a reply, handling errors directly
*
*/
void my_example(xcb_connection *conn, xcb_window_t deco, xcb_window_t window) {
/* A reparenting window manager wants to know whether a new window was
* successfully reparented. If not (because the window got destroyed
* already, for example), it does not make sense to map an empty window
* decoration at all, so we need to know this right now. */
xcb_void_cookie_t cookie = xcb_reparent_window_checked(conn, window,
deco, 0, 0);
xcb_generic_error_t *error;
if ((error = xcb_request_check(conn, cookie))) {
fprintf(stderr, "Could not reparent the window\n");
free(error);
return;
}
/* ... do window manager stuff here ... */
}
/*
* Request with a reply, handling errors directly (default)
*
*/
void my_example(xcb_connection *conn, xcb_window_t window) {
xcb_intern_atom_cookie_t cookie;
xcb_intern_atom_reply_t *reply;
xcb_generic_error_t *error;
cookie = xcb_intern_atom(c, 0, strlen("_NET_WM_NAME"), "_NET_WM_NAME");
/* ... do other work here if possible ... */
if ((reply = xcb_intern_atom_reply(c, cookie, &error))) {
printf("The _NET_WM_NAME atom has ID %u\n", reply->atom);
free(reply);
} else {
fprintf(stderr, "X11 Error %d\n", error->error_code);
free(error);
}
}
/*
* Request with a reply, handling errors in the event loop
*
*/
void my_example(xcb_connection *conn, xcb_window_t window) {
xcb_intern_atom_cookie_t cookie;
xcb_intern_atom_reply_t *reply;
cookie = xcb_intern_atom_unchecked(c, 0, strlen("_NET_WM_NAME"),
"_NET_WM_NAME");
/* ... do other work here if possible ... */
if ((reply = xcb_intern_atom_reply(c, cookie, NULL))) {
printf("The _NET_WM_NAME atom has ID %u\n", reply->atom);
free(reply);
}
/* ... of course your event loop would not be in the same function ... */
while ((event = xcb_wait_for_event(conn)) != NULL) {
if (event->response_type == 0) {
fprintf("Received X11 error %d\n", error->error_code);
free(event);
continue;
}
/* ... handle a normal event ... */
}
}
lowkey important: the "default" behaviours in those two block comments are the ones you get when you don't reach for a_checkedor_uncheckedvariant. so if you never think about it, you're already on team default. π«Ά
π SEE ALSO π
go read these next, they're all part of the same friend group:
xcb_map_window(3)xcb_intern_atom(3)xcb_list_fonts(3)xcb_poll_for_event(3)xcb_request_check(3)
π AUTHOR π
Michael Stapelberg <michael+xcb at stapelberg dot de> β credit where credit is due, bestie π
and that's the page!! β¨ this whole thing is X Version 11, libxcb 1.17.0, and it's filed under xcb-requests(3) β so if you ever forget where you read it, that's your girl. mwah π
π¦ where this page comes from
- alpine 3.22: libxcb-doc 1.17.0-r0 Β· MIT
- alpine 3.23: libxcb-doc 1.17.0-r1 Β· MIT
- alpine 3.24: libxcb-doc 1.17.0-r2 Β· MIT
- arch rolling: libxcb 1.17.0-1 Β· X11
- centos-stream 10: libxcb-devel 1.17.0-3.el10 Β· X11
- debian trixie: libxcb-doc 1.17.0-2
- fedora 43: libxcb-devel 1.17.0-6.fc43 Β· X11
- fedora 43: libxcb-devel 1.17.0-6.fc43 Β· X11
- fedora 44: libxcb-devel 1.17.0-7.fc44 Β· X11
- fedora 44: libxcb-devel 1.17.0-7.fc44 Β· X11
- nixpkgs unstable: libxcb 1.17.0
- opensuse-leap 16.0: libxcb-devel-doc 1.17.0-160000.2.2 Β· MIT
- ubuntu questing: libxcb-doc 1.17.0-2build1
- ubuntu resolute: libxcb-doc 1.17.0-2ubuntu1
- ubuntu stonking: libxcb-doc 1.17.0-2ubuntu1
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms