#include "Xlibint.h"
#include "locking.h"
#include "Xxcbint.h"
#include <xcb/xcbext.h>
#include <xcb/xcbxlib.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
static void check_internal_connections(Display *dpy)
{
struct _XConnectionInfo *ilist;
fd_set r_mask;
struct timeval tv;
int result;
int highest_fd = -1;
if(dpy->flags & XlibDisplayProcConni || !dpy->im_fd_info)
return;
FD_ZERO(&r_mask);
for(ilist = dpy->im_fd_info; ilist; ilist = ilist->next)
{
assert(ilist->fd >= 0);
FD_SET(ilist->fd, &r_mask);
if(ilist->fd > highest_fd)
highest_fd = ilist->fd;
}
assert(highest_fd >= 0);
tv.tv_sec = 0;
tv.tv_usec = 0;
result = select(highest_fd + 1, &r_mask, NULL, NULL, &tv);
if(result == -1)
{
if(errno == EINTR)
return;
_XIOError(dpy);
}
for(ilist = dpy->im_fd_info; result && ilist; ilist = ilist->next)
if(FD_ISSET(ilist->fd, &r_mask))
{
_XProcessInternalConnection(dpy, ilist);
--result;
}
}
static void condition_wait(Display *dpy, xcondition_t cv)
{
_XPutXCBBuffer(dpy);
xcb_xlib_unlock(dpy->xcb->connection);
ConditionWait(dpy, cv);
xcb_xlib_lock(dpy->xcb->connection);
_XGetXCBBuffer(dpy);
}
static void call_handlers(Display *dpy, xcb_generic_reply_t *buf)
{
_XAsyncHandler *async, *next;
for(async = dpy->async_handlers; async; async = next)
{
next = async->next;
if(async->handler(dpy, (xReply *) buf, (char *) buf, sizeof(xReply) + (buf->length << 2), async->data))
return;
}
if(buf->response_type == 0)
_XError(dpy, (xError *) buf);
}
static xcb_generic_event_t * wait_or_poll_for_event(Display *dpy, int wait)
{
xcb_connection_t *c = dpy->xcb->connection;
xcb_generic_event_t *event;
if(wait)
{
UnlockDisplay(dpy);
event = xcb_wait_for_event(c);
LockDisplay(dpy);
}
else
event = xcb_poll_for_event(c);
return event;
}
static void process_responses(Display *dpy, int wait_for_first_event, xcb_generic_error_t **current_error, unsigned int current_request)
{
void *reply;
xcb_generic_event_t *event = dpy->xcb->next_event;
xcb_generic_error_t *error;
xcb_connection_t *c = dpy->xcb->connection;
if(!event && dpy->xcb->event_owner == XlibOwnsEventQueue)
event = wait_or_poll_for_event(dpy, wait_for_first_event);
while(1)
{
PendingRequest *req = dpy->xcb->pending_requests;
assert(!(req && current_request && !XCB_SEQUENCE_COMPARE(req->sequence, <=, current_request)));
if(event && (!req || XCB_SEQUENCE_COMPARE(event->full_sequence, <=, req->sequence)))
{
dpy->last_request_read = event->full_sequence;
if(event->response_type != X_Error)
{
_XEnq(dpy, (xEvent *) event);
wait_for_first_event = 0;
}
else if(current_error && event->full_sequence == current_request)
{
*current_error = (xcb_generic_error_t *) event;
event = 0;
break;
}
else
_XError(dpy, (xError *) event);
free(event);
event = wait_or_poll_for_event(dpy, wait_for_first_event);
}
else if(req && req->waiters != -1)
{
if(req->sequence == current_request)
break;
if(!current_request && !wait_for_first_event)
break;
dpy->xcb->next_event = event;
req->waiters++;
assert(req->waiters > 0);
condition_wait(dpy, &req->condition);
--req->waiters;
event = dpy->xcb->next_event;
}
else if(req && xcb_poll_for_reply(dpy->xcb->connection, req->sequence, &reply, &error))
{
unsigned int sequence = req->sequence;
if(!reply)
{
dpy->xcb->pending_requests = req->next;
if(!dpy->xcb->pending_requests)
dpy->xcb->pending_requests_tail = &dpy->xcb->pending_requests;
free(req);
reply = error;
}
if(reply)
{
dpy->last_request_read = sequence;
call_handlers(dpy, reply);
free(reply);
}
}
else
break;
}
dpy->xcb->next_event = event;
if(xcb_connection_has_error(c))
_XIOError(dpy);
assert_sequence_less(dpy->last_request_read, dpy->request);
assert(!wait_for_first_event);
}
int _XEventsQueued(Display *dpy, int mode)
{
if(dpy->flags & XlibDisplayIOError)
return 0;
if(dpy->xcb->event_owner != XlibOwnsEventQueue)
return 0;
if(mode == QueuedAfterFlush)
_XSend(dpy, 0, 0);
else
check_internal_connections(dpy);
process_responses(dpy, 0, 0, 0);
return dpy->qlen;
}
void _XReadEvents(Display *dpy)
{
if(dpy->flags & XlibDisplayIOError)
return;
_XSend(dpy, 0, 0);
if(dpy->xcb->event_owner != XlibOwnsEventQueue)
return;
check_internal_connections(dpy);
process_responses(dpy, 1, 0, 0);
}
void _XSend(Display *dpy, const char *data, long size)
{
xcb_connection_t *c = dpy->xcb->connection;
if(dpy->flags & XlibDisplayIOError)
return;
assert(!dpy->xcb->request_extra);
dpy->xcb->request_extra = data;
dpy->xcb->request_extra_size = size;
_XPutXCBBuffer(dpy);
if(xcb_flush(c) <= 0)
_XIOError(dpy);
_XGetXCBBuffer(dpy);
check_internal_connections(dpy);
}
void _XFlush(Display *dpy)
{
_XSend(dpy, 0, 0);
_XEventsQueued(dpy, QueuedAfterReading);
}
static int
_XIDHandler(Display *dpy)
{
XID next = xcb_generate_id(dpy->xcb->connection);
LockDisplay(dpy);
dpy->xcb->next_xid = next;
if(dpy->flags & XlibDisplayPrivSync)
{
dpy->synchandler = dpy->savedsynchandler;
dpy->flags &= ~XlibDisplayPrivSync;
}
UnlockDisplay(dpy);
SyncHandle();
return 0;
}
XID _XAllocID(Display *dpy)
{
XID ret = dpy->xcb->next_xid;
dpy->xcb->next_xid = 0;
assert(!(dpy->flags & XlibDisplayPrivSync));
dpy->savedsynchandler = dpy->synchandler;
dpy->flags |= XlibDisplayPrivSync;
dpy->synchandler = _XIDHandler;
return ret;
}
void _XAllocIDs(Display *dpy, XID *ids, int count)
{
int i;
_XPutXCBBuffer(dpy);
for (i = 0; i < count; i++)
ids[i] = xcb_generate_id(dpy->xcb->connection);
_XGetXCBBuffer(dpy);
}
static void _XFreeReplyData(Display *dpy, Bool force)
{
if(!force && dpy->xcb->reply_consumed < dpy->xcb->reply_length)
return;
free(dpy->xcb->reply_data);
dpy->xcb->reply_data = 0;
}
static PendingRequest * insert_pending_request(Display *dpy)
{
PendingRequest **cur = &dpy->xcb->pending_requests;
while(*cur && XCB_SEQUENCE_COMPARE((*cur)->sequence, <, dpy->request))
cur = &((*cur)->next);
if(*cur && (*cur)->sequence == dpy->request)
{
assert((*cur)->waiters == -1);
}
else
{
PendingRequest *node = malloc(sizeof(PendingRequest));
assert(node);
node->next = *cur;
node->sequence = dpy->request;
if(cur == dpy->xcb->pending_requests_tail)
dpy->xcb->pending_requests_tail = &(node->next);
*cur = node;
}
(*cur)->waiters = 0;
xcondition_init(&((*cur)->condition));
return *cur;
}
Status _XReply(Display *dpy, xReply *rep, int extra, Bool discard)
{
xcb_generic_error_t *error;
xcb_connection_t *c = dpy->xcb->connection;
char *reply;
PendingRequest *current;
assert(!dpy->xcb->reply_data);
if(dpy->flags & XlibDisplayIOError)
return 0;
_XPutXCBBuffer(dpy);
current = insert_pending_request(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);
reply = xcb_wait_for_reply(c, current->sequence, &error);
LockDisplay(dpy);
check_internal_connections(dpy);
process_responses(dpy, 0, &error, current->sequence);
if(current->waiters)
{
ConditionBroadcast(dpy, ¤t->condition);
}
--current->waiters;
if(error)
{
_XExtension *ext;
xError *err = (xError *) error;
int ret_code;
dpy->last_request_read = error->full_sequence;
memcpy(rep, error, 32);
switch(err->errorCode)
{
case BadName:
switch(err->majorCode)
{
case X_LookupColor:
case X_AllocNamedColor:
return 0;
}
break;
case BadFont:
if(err->majorCode == X_QueryFont)
return 0;
break;
case BadAlloc:
case BadAccess:
return 0;
}
for(ext = dpy->ext_procs; ext; ext = ext->next)
if(ext->error && ext->error(dpy, err, &ext->codes, &ret_code))
return ret_code;
_XError(dpy, (xError *) error);
return 0;
}
if(!reply)
{
_XIOError(dpy);
return 0;
}
dpy->last_request_read = current->sequence;
dpy->xcb->reply_data = reply;
dpy->xcb->reply_consumed = sizeof(xReply) + (extra * 4);
dpy->xcb->reply_length = sizeof(xReply);
if(dpy->xcb->reply_data[0] == 1)
dpy->xcb->reply_length += (((xcb_generic_reply_t *) dpy->xcb->reply_data)->length * 4);
if(dpy->xcb->reply_length < dpy->xcb->reply_consumed)
dpy->xcb->reply_consumed = dpy->xcb->reply_length;
memcpy(rep, dpy->xcb->reply_data, dpy->xcb->reply_consumed);
_XFreeReplyData(dpy, discard);
return 1;
}
int _XRead(Display *dpy, char *data, long size)
{
assert(size >= 0);
if(size == 0)
return 0;
assert(dpy->xcb->reply_data != 0);
assert(dpy->xcb->reply_consumed + size <= dpy->xcb->reply_length);
memcpy(data, dpy->xcb->reply_data + dpy->xcb->reply_consumed, size);
dpy->xcb->reply_consumed += size;
_XFreeReplyData(dpy, False);
return 0;
}
void _XReadPad(Display *dpy, char *data, long size)
{
_XRead(dpy, data, size);
dpy->xcb->reply_consumed += -size & 3;
_XFreeReplyData(dpy, False);
}
void _XEatData(Display *dpy, unsigned long n)
{
dpy->xcb->reply_consumed += n;
_XFreeReplyData(dpy, False);
}