#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "Xlibint.h"
#include "locking.h"
#include "Xxcbint.h"
#include <xcb/xcbext.h>
#include <xcb/xcbxlib.h>
#include <pthread.h>
static void _XCBLockDisplay(Display *dpy)
{
if(dpy->xcb->lock_fns.lock_display)
dpy->xcb->lock_fns.lock_display(dpy);
if(!dpy->lock || dpy->lock->locking_level == 0)
xcb_xlib_lock(dpy->xcb->connection);
if(!(dpy->flags & XlibDisplayIOError))
_XGetXCBBuffer(dpy);
}
static void _XCBUnlockDisplay(Display *dpy)
{
if(!(dpy->flags & XlibDisplayIOError))
{
_XPutXCBBuffer(dpy);
assert(dpy->xcb->partial_request == 0);
assert(xcb_get_request_sent(dpy->xcb->connection) == dpy->request);
_XSetSeqSyncFunction(dpy);
}
if(!dpy->lock || dpy->lock->locking_level == 0)
xcb_xlib_unlock(dpy->xcb->connection);
if(dpy->xcb->lock_fns.unlock_display)
dpy->xcb->lock_fns.unlock_display(dpy);
}
int _XCBInitDisplayLock(Display *dpy)
{
if(!dpy->lock_fns && !(dpy->lock_fns = Xcalloc(1, sizeof(*dpy->lock_fns))))
return 0;
dpy->xcb->lock_fns.lock_display = dpy->lock_fns->lock_display;
dpy->lock_fns->lock_display = _XCBLockDisplay;
dpy->xcb->lock_fns.unlock_display = dpy->lock_fns->unlock_display;
dpy->lock_fns->unlock_display = _XCBUnlockDisplay;
return 1;
}
void _XCBShutdownDisplayLock(Display *dpy)
{
if(dpy->lock_fns) {
Xfree((char *)dpy->lock_fns);
dpy->lock_fns = NULL;
}
}
void _XGetXCBBuffer(Display *dpy)
{
static const xReq dummy_request;
unsigned int xcb_req = xcb_get_request_sent(dpy->xcb->connection);
if(xcb_connection_has_error(dpy->xcb->connection))
_XIOError(dpy);
if(dpy->xcb->partial_request)
++xcb_req;
assert(XCB_SEQUENCE_COMPARE(xcb_req, >=, dpy->request));
dpy->request = xcb_req;
dpy->last_req = (char *) &dummy_request;
}
static size_t request_length(struct iovec *vec)
{
size_t len;
assert(vec[0].iov_len >= 4);
len = ((uint16_t *) vec[0].iov_base)[1];
if(len == 0)
{
assert(vec[0].iov_len >= 8);
len = ((uint32_t *) vec[0].iov_base)[1];
}
return len << 2;
}
static inline int issue_complete_request(Display *dpy, int veclen, struct iovec *vec)
{
xcb_protocol_request_t xcb_req = { 0 };
unsigned int sequence;
int flags = XCB_REQUEST_RAW;
int i;
size_t len;
assert(veclen >= 0);
while(veclen > 0 && vec[0].iov_len == 0)
--veclen, ++vec;
if(!veclen)
return 0;
len = request_length(vec);
for(i = 0; i < veclen; ++i)
{
size_t oldlen = len;
len -= vec[i].iov_len;
if((len - 1) > oldlen)
break;
}
if(i == veclen)
return 0;
vec[i].iov_len += len;
xcb_req.count = i + 1;
xcb_req.opcode = ((uint8_t *) vec[0].iov_base)[0];
if(dpy->xcb->event_owner != XlibOwnsEventQueue)
flags |= XCB_REQUEST_CHECKED;
if (xcb_get_request_sent(dpy->xcb->connection) == 0xffffffff)
dpy->request++;
sequence = xcb_send_request(dpy->xcb->connection, flags, vec, &xcb_req);
if(!sequence)
_XIOError(dpy);
vec[i].iov_len = -len;
if(flags & XCB_REQUEST_CHECKED || dpy->async_handlers)
{
PendingRequest *req = malloc(sizeof(PendingRequest));
assert(req);
req->next = 0;
req->waiters = -1;
req->sequence = sequence;
*dpy->xcb->pending_requests_tail = req;
dpy->xcb->pending_requests_tail = &req->next;
}
return 1;
}
void _XPutXCBBuffer(Display *dpy)
{
static char const pad[3];
const int padsize = -dpy->xcb->request_extra_size & 3;
xcb_connection_t *c = dpy->xcb->connection;
_XExtension *ext;
struct iovec iov[6];
assert_sequence_less(dpy->last_request_read, dpy->request);
assert_sequence_less(xcb_get_request_sent(c), dpy->request);
for(ext = dpy->flushes; ext; ext = ext->next_flush)
{
ext->before_flush(dpy, &ext->codes, dpy->buffer, dpy->bufptr - dpy->buffer);
if(dpy->xcb->request_extra)
{
ext->before_flush(dpy, &ext->codes, dpy->xcb->request_extra, dpy->xcb->request_extra_size);
if(padsize)
ext->before_flush(dpy, &ext->codes, pad, padsize);
}
}
iov[2].iov_base = dpy->xcb->partial_request;
iov[2].iov_len = dpy->xcb->partial_request_offset;
iov[3].iov_base = dpy->buffer;
iov[3].iov_len = dpy->bufptr - dpy->buffer;
iov[4].iov_base = (caddr_t) dpy->xcb->request_extra;
iov[4].iov_len = dpy->xcb->request_extra_size;
iov[5].iov_base = (caddr_t) pad;
iov[5].iov_len = padsize;
while(issue_complete_request(dpy, 4, iov + 2))
;
if(iov[2].iov_len == 0 && dpy->xcb->partial_request)
{
free(dpy->xcb->partial_request);
dpy->xcb->partial_request = 0;
dpy->xcb->partial_request_offset = 0;
}
if(iov[3].iov_len != 0 || iov[4].iov_len != 0 || iov[5].iov_len != 0)
{
int i;
if(!dpy->xcb->partial_request)
{
size_t len = request_length(iov + 3);
assert(!dpy->xcb->partial_request_offset);
dpy->xcb->partial_request = malloc(len);
assert(dpy->xcb->partial_request);
}
for(i = 3; i < sizeof(iov) / sizeof(*iov); ++i)
{
memcpy(dpy->xcb->partial_request + dpy->xcb->partial_request_offset, iov[i].iov_base, iov[i].iov_len);
dpy->xcb->partial_request_offset += iov[i].iov_len;
}
}
dpy->xcb->request_extra = 0;
dpy->xcb->request_extra_size = 0;
dpy->bufptr = dpy->buffer;
}