This is an X interface library, lx. You can think of it as a competitor to Xlib and xcb, if that helps you classify it mentally. The point is to not block. In that respect, it is similar to xcb. However, the ways that lx and xcb do that are very different. (lx and xcb are similar in another way, too: each exposes more protocol details to the application code than Xlib does.) For open-loop requests (eg, MapWindow), there is comparatively little difference. For round-trip requests (eg, QueryPointer) the difference becomes obvious. In xcb, the paradigm is that there is one call to issue a request, then another call to retrieve the result(s); presumably (I haven't dug much), there's a non-blocking way to check whether the call has finished. In lx, the paradigm is that a callback is called when the request finishes. It is built atop libaio - my libaio, that is; I have discovered there is a Linux thing called libaio, which presumably is at least conceptually related; I was not aware of it when I built mine and it is highly unlikely it is compatible. This leads to very callback-heavy code. This is normal for libaio-using programs, since libaio is built around callbacks. Indeed, much of the motivation for creating liblx was to have a libaio-based X interface library. Thus, to query the pointer position, an Xlib program might write status = XQueryPointer(disp,win,&rootw,&childw,&rootx,&rooty,&winx,&winy,&mask); An xcb program would issue two calls, one to send the QueryPointer request and the other to field the response (I don't use xcb; I don't know what the details of the code would look like). An lx program would call lx_QueryPointer or lx_QueryPointer_status (depending on whether it prefers the results to be written into individual variables or into a struct). Then, depending on how it wants to handle the response, it could - Pass the result to lx_op_callback, in which case a callback (specified as args to lx_op_callback) is called when the response arrives. - Pass the result to lx_op_drop, in which case the program receives no explicit indication when the response arrives. This can be useful when the program issues multiple requests and cannot continue until the last one is done; it then may not need explicit callbacks for earlier requests. - Poll the result with lx_op_test whenever it cares about whether the response has arrived. liblx is still pre-alpha at this writing (2024-10-24), but it is mature enough that I've written one `real' (non-testbed) application with it already (an SGF file viewer). lx does significantly more type-checking than Xlib, though not as much as I'd like. (I don't know where xcb stands on this point.) For example, window class InputOutput and backing-store WhenMapped are represented by the same value on the wire (1, in the case of InputOutput and WhenMapped). In Xlib, the API value for each is 1, making it possible to pass WhenMapped (or RetainPermanent, IsUnviewable, or various other semantically nonsense names) as a window class without getting an error. In lx, LX_BACKINGSTORE_WhenMapped and LX_WCLASS_InputOutput are not equal to one another, and neither one is 1; the library maps between API values and protocol values where appropriate. (I would prefer to get a compile-time type-mismatch error for passing, say, LX_WCLASS_InputOutput as a backing-store value. But I would also like values such as LX_WCLASS_InputOutput to be compile-time constants suitable for use in switch statement case labels. I have not come up with any way to get both. So I've gone with the latter and backed down from compile-time to run-time for the type-checking. C++ can probably get both, but I'm not using C++.) Errors and events are, again, handled via callbacks. There are two error handler callbacks (one for X errors and one for library errors) and one event handler callback, per connection. (There is also a way to attach request-specific error handlers to requests-in-progress, so that, for example, a Name error from an AllocNamedColor request can be reflected as failure rather than being just another call to the generic X error callback.) There are also various entirely-client-side calls, such as one to parse a geometry string like "80x24+100+200", and some convenience calls, such as a draw-rectangle call which batches back-to-back calls much the way Xlib's XDrawRectangle does. (There is no DrawRectangle protocol request; a single rectangle is drawn with a PolyRectangle lrequest with a count of one. lx can do that, certainly, by calling lx_PolyRectangle, but batching is useful.) lx does something similar with GCs. There are calls, such as lx_ChangeGC, for dealing with GCs directly at the protocol level. But there are also convenience routines for keeping a client-side shadow and issuing protocol requests only when needed (see the SGC family of routines). lx pollutes the program's namespace less than Xlib does (I don't know where xcb falls on this point). All application-visible API names begin with either lx_ or LX_; names beginning lx__ or LX__ are library-internal, and all user-code-visible library-internal names begin lx__ or LX__. (By intent, at least; if I have slipped up, please let me know, because I consider it a bug I need to fix.) Direct application use of library-internal names is not advised, not supported, and is very much entirely at the application's own risk. For more documentation, see the doc/ subdirectory.