[Copyright status: this file is in the public domain.] Some operations cannot complete immediately (the commonest example is a request which returns values that have to come back from the server, such as GetGeometry). Something has to be done to deal with the delay. Xlib simply blocks. xcb has the application perform another call to wait for the response (I assume there's a way to test for completion, but I don't actually know). liblx usually uses a callback, though the application can poll instead. There are two general paradigms for requests: open-loop and response-required. Which paradigm applies depends on the request. As an example of an open-loop request, consider MapWindow; as example of a response-required request, consider QueryPointer. For open-loop requests, the call (eg, CreateWindow) returns the results, if any, immediately (eg, an LX_XID for CreateWindow, or nothing for Bell) and there is no way to tell when it has completed, except indirectly, such as by a later response-required request's response arriving. (For applications that want to do such a thing deliberately, GetInputFocus is the canonical request; it forces a server round-trip and is cheap.) For response-required requests, the call returns an LX_OP pointer, which can be passed to various calls, such as lx_op_callback, to do useful things with the pending request. LX_OP is an opaque type, used to represent such an operation. The calls for working with LX_OPs are: void lx_op_callback(LX_OP *op, void(*cb)(void *), void *cbarg, unsigned int flags) int lx_op_test(LX_OP *op) void lx_op_drop(LX_OP *op) void lx_op_abort(LX_OP *op) void lx_op_set_udata(LX_OP *op, void *udata) void *lx_op_udata(LX_OP *op) LX_OP_ERR_SETTING lx_op_err(LX_OP *op, int (*handler)(LX_CONN *, LX_OP *, const LX_X_ERR *, void *), void *) LX_OP_ERR_SETTING lx_op_err_setting(LX_OP *op, LX_OP_ERR_SETTING) lx_op_err and lx_op_err_setting are not further described here; see errors.txt for them. lx_op_callback -------------- void lx_op_callback(LX_OP *op, void(*cb)(void *), void *cbarg, unsigned int flags) This arranges for (*cb)(cbarg) to be called when op completes. flags holds flag bits; currently, there is only one flag defined: LX_OP_KEEP By default, once the LX_OP completes, it is dropped with the equivalent of lx_op_drop. If LX_OP_KEEP is set, the LX_OP remains valid. (To dispose of an LX_OP which is done but was kept this way, use lx_op_drop.) All values which the response writes will have been written before the callback is entered. Dropping the request, when applicable (ie, when LX_OP_KEEP was not specified), happens at some indeterminate (from the application's point of view) shortly after the callback returns. During the execution of the callback, the LX_OP pointer is still valid, though undefined behaviour results from calling lx_op_callback, lx_op_drop, or lx_op_abort on it from within the callback (even if LX_OP_KEEP was set), and, while calling lx_op_test on it is permitted, it is undefined whether it returns true or false. The only calls on the LX_OP which are actually useful at that point are lx_op_udata and lx_op_set_udata, the latter mostly when LX_OP_KEEP was specified. For example, to get a window's geometry, an application could do void have_geom(void *wgv) { LX_GET_GEOMETRY *wg; wg = wgv; ...use fields of wg... free(wg); } { LX_GET_GEOMETRY *wg; ... wg = malloc(sizeof(*wg)); lx_op_callback(lx_GetGeometry(conn,win,&wg),&have_geom,wg,0); } lx_op_test ---------- int lx_op_test(LX_OP *op) This simply tests whether op is done (returns 1) or not (returns 0). It never blocks. lx_op_drop ---------- void lx_op_drop(LX_OP *op) This declares that the application does not want any explicit notification of op's completion. When op completes, it is simply discarded. (This also revokes any previous lx_op_callback call for the same LX_OP.) It does not otherwise affect the operation (compare and contrast with lx_op_abort); output values are still written where they should be. The LX_OP pointer must not be used further; from the application's point of view, it goes invalid at some indeterminate point after entry to lx_op_drop. lx_op_abort ----------- void lx_op_abort(LX_OP *op) This declares that the application no longer is interested in op at all. It is like lx_op_drop, but stronger; any output values op's request would normally write which have not already been written by the point lx_op_abort returns will not be written anywhere. It is like lx_op_drop with respect to the LX_OP pointer's validity. lx_op_set_udata, lx_op_udata --------------- ----------- void lx_op_set_udata(LX_OP *op, void *udata) void *lx_op_udata(LX_OP *op) Every LX_OP has a user data pointer associated with it. When the LX_OP is first created, this pointer is nil; it can be set with lx_op_set_udata and fetched with lx_op_udata. The library does not use this pointer in any other way - its use is entirely up to the application.