To use XCB nicely with a main loop instead of threads, I think the following are missing.
1. a way to see if any events or replies are buffered (like XPending, but no IO). Used in the "prepare" and "check" steps of GLib main loop for example. Ideally, separate xcb_has_events and xcb_has_replies perhaps. Errors are events if treated as events and replies if checked.
2. a way to "read from socket into internal queue without returning any events or replies". Used in GLib "check" step for example, followed by the XPending type thing.
3. a way to "partially flush with a single write() call" - xcb_partial_flush?
Then in something like GTK, you would have:
* a GSource for the event queue, similar to current Xlib one. Uses current
xcb_poll_for_event in dispatch(), but uses the new API for prepare and check.
Can also poll on writability and do the "xcb_partial_flush" if socket is writeable, so we never get requests that remain unsent if the main loop runs.
* a GSource that lets you add a callback to invoke when a specific reply arrives. This would need to do "read() just once from socket" in its check(), and then xcb_poll_for_reply
Right now the source that nonblockingly auto-flushes in main loop is not possible, and the source that does a callback when a specific reply arrives I don't think is possible either. (without threads, that is.)