2006-11-25 09:33:55 -07:00
|
|
|
/* Copyright (C) 2003-2006 Jamey Sharp, Josh Triplett
|
|
|
|
* This file is licensed under the MIT license. See the file COPYING. */
|
|
|
|
|
|
|
|
#include "Xlibint.h"
|
2006-12-16 09:39:39 -07:00
|
|
|
#include "locking.h"
|
2006-11-25 09:33:55 -07:00
|
|
|
#include "Xxcbint.h"
|
|
|
|
#include <xcb/xcbext.h>
|
|
|
|
#include <xcb/xcbxlib.h>
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
/* Call internal connection callbacks for any fds that are currently
|
|
|
|
* ready to read. This function will not block unless one of the
|
|
|
|
* callbacks blocks.
|
|
|
|
*
|
|
|
|
* This code borrowed from _XWaitForReadable. Inverse call tree:
|
|
|
|
* _XRead
|
|
|
|
* _XWaitForWritable
|
|
|
|
* _XFlush
|
|
|
|
* _XSend
|
|
|
|
* _XEventsQueued
|
|
|
|
* _XReadEvents
|
|
|
|
* _XRead[0-9]+
|
|
|
|
* _XAllocIDs
|
|
|
|
* _XReply
|
|
|
|
* _XEatData
|
|
|
|
* _XReadPad
|
|
|
|
*/
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-16 09:39:39 -07:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2006-11-25 09:33:55 -07:00
|
|
|
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) /* unhandled error */
|
|
|
|
_XError(dpy, (xError *) buf);
|
|
|
|
}
|
|
|
|
|
2006-12-16 09:39:39 -07:00
|
|
|
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;
|
2007-09-30 04:11:57 -06:00
|
|
|
if(wait)
|
2006-12-16 09:39:39 -07:00
|
|
|
{
|
|
|
|
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)
|
2006-11-25 09:33:55 -07:00
|
|
|
{
|
|
|
|
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)
|
2006-12-16 09:39:39 -07:00
|
|
|
event = wait_or_poll_for_event(dpy, wait_for_first_event);
|
2006-11-25 09:33:55 -07:00
|
|
|
|
|
|
|
while(1)
|
|
|
|
{
|
2007-09-30 04:11:57 -06:00
|
|
|
PendingRequest *req = dpy->xcb->pending_requests;
|
2006-12-16 09:39:39 -07:00
|
|
|
assert(!(req && current_request && !XCB_SEQUENCE_COMPARE(req->sequence, <=, current_request)));
|
|
|
|
if(event && (!req || XCB_SEQUENCE_COMPARE(event->full_sequence, <=, req->sequence)))
|
2006-11-25 09:33:55 -07:00
|
|
|
{
|
2007-09-30 04:11:57 -06:00
|
|
|
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)
|
2006-11-25 09:33:55 -07:00
|
|
|
{
|
2007-09-30 04:11:57 -06:00
|
|
|
/* This can only occur when called from
|
|
|
|
* _XReply, which doesn't need a new event. */
|
2006-11-25 09:33:55 -07:00
|
|
|
*current_error = (xcb_generic_error_t *) event;
|
|
|
|
event = 0;
|
|
|
|
break;
|
|
|
|
}
|
2007-09-30 04:11:57 -06:00
|
|
|
else
|
|
|
|
_XError(dpy, (xError *) event);
|
|
|
|
free(event);
|
2006-12-16 09:39:39 -07:00
|
|
|
event = wait_or_poll_for_event(dpy, wait_for_first_event);
|
2006-11-25 09:33:55 -07:00
|
|
|
}
|
2006-12-16 09:39:39 -07:00
|
|
|
else if(req && req->waiters != -1)
|
|
|
|
{
|
|
|
|
if(req->sequence == current_request)
|
|
|
|
break;
|
2007-09-30 04:11:57 -06:00
|
|
|
if(!current_request && !wait_for_first_event)
|
2006-12-16 09:39:39 -07:00
|
|
|
break;
|
|
|
|
dpy->xcb->next_event = event;
|
|
|
|
req->waiters++;
|
|
|
|
assert(req->waiters > 0);
|
|
|
|
condition_wait(dpy, &req->condition);
|
2007-09-30 04:11:57 -06:00
|
|
|
--req->waiters;
|
2006-12-16 09:39:39 -07:00
|
|
|
event = dpy->xcb->next_event;
|
|
|
|
}
|
|
|
|
else if(req && xcb_poll_for_reply(dpy->xcb->connection, req->sequence, &reply, &error))
|
2006-11-25 09:33:55 -07:00
|
|
|
{
|
2007-09-30 04:11:57 -06:00
|
|
|
unsigned int sequence = req->sequence;
|
2006-11-25 09:33:55 -07:00
|
|
|
if(!reply)
|
2007-09-30 04:11:57 -06:00
|
|
|
{
|
|
|
|
dpy->xcb->pending_requests = req->next;
|
|
|
|
if(!dpy->xcb->pending_requests)
|
|
|
|
dpy->xcb->pending_requests_tail = &dpy->xcb->pending_requests;
|
|
|
|
free(req);
|
2006-11-25 09:33:55 -07:00
|
|
|
reply = error;
|
2007-09-30 04:11:57 -06:00
|
|
|
}
|
2006-11-25 09:33:55 -07:00
|
|
|
if(reply)
|
|
|
|
{
|
2007-09-30 04:11:57 -06:00
|
|
|
dpy->last_request_read = sequence;
|
2006-11-25 09:33:55 -07:00
|
|
|
call_handlers(dpy, reply);
|
2007-09-30 04:11:57 -06:00
|
|
|
free(reply);
|
2006-11-25 09:33:55 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
dpy->xcb->next_event = event;
|
|
|
|
|
|
|
|
if(xcb_connection_has_error(c))
|
|
|
|
_XIOError(dpy);
|
|
|
|
|
|
|
|
assert_sequence_less(dpy->last_request_read, dpy->request);
|
2007-09-30 04:11:57 -06:00
|
|
|
assert(!wait_for_first_event);
|
2006-11-25 09:33:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
int _XEventsQueued(Display *dpy, int mode)
|
|
|
|
{
|
2007-09-30 04:11:57 -06:00
|
|
|
if(dpy->flags & XlibDisplayIOError)
|
|
|
|
return 0;
|
2006-11-25 09:33:55 -07:00
|
|
|
if(dpy->xcb->event_owner != XlibOwnsEventQueue)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if(mode == QueuedAfterFlush)
|
|
|
|
_XSend(dpy, 0, 0);
|
|
|
|
else
|
|
|
|
check_internal_connections(dpy);
|
2006-12-16 09:39:39 -07:00
|
|
|
process_responses(dpy, 0, 0, 0);
|
2006-11-25 09:33:55 -07:00
|
|
|
return dpy->qlen;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* _XReadEvents - Flush the output queue,
|
|
|
|
* then read as many events as possible (but at least 1) and enqueue them
|
|
|
|
*/
|
|
|
|
void _XReadEvents(Display *dpy)
|
|
|
|
{
|
2007-09-30 04:11:57 -06:00
|
|
|
if(dpy->flags & XlibDisplayIOError)
|
|
|
|
return;
|
2006-11-25 09:33:55 -07:00
|
|
|
_XSend(dpy, 0, 0);
|
|
|
|
if(dpy->xcb->event_owner != XlibOwnsEventQueue)
|
|
|
|
return;
|
|
|
|
check_internal_connections(dpy);
|
2006-12-16 09:39:39 -07:00
|
|
|
process_responses(dpy, 1, 0, 0);
|
2006-11-25 09:33:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* _XSend - Flush the buffer and send the client data. 32 bit word aligned
|
|
|
|
* transmission is used, if size is not 0 mod 4, extra bytes are transmitted.
|
|
|
|
*
|
|
|
|
* Note that the connection must not be read from once the data currently
|
|
|
|
* in the buffer has been written.
|
|
|
|
*/
|
|
|
|
void _XSend(Display *dpy, const char *data, long size)
|
|
|
|
{
|
|
|
|
xcb_connection_t *c = dpy->xcb->connection;
|
2007-09-30 04:11:57 -06:00
|
|
|
if(dpy->flags & XlibDisplayIOError)
|
|
|
|
return;
|
2006-11-25 09:33:55 -07:00
|
|
|
|
|
|
|
assert(!dpy->xcb->request_extra);
|
|
|
|
dpy->xcb->request_extra = data;
|
|
|
|
dpy->xcb->request_extra_size = size;
|
|
|
|
|
|
|
|
/* give dpy->buffer to XCB */
|
|
|
|
_XPutXCBBuffer(dpy);
|
|
|
|
|
|
|
|
if(xcb_flush(c) <= 0)
|
|
|
|
_XIOError(dpy);
|
|
|
|
|
|
|
|
/* get a new dpy->buffer */
|
|
|
|
_XGetXCBBuffer(dpy);
|
|
|
|
|
|
|
|
check_internal_connections(dpy);
|
|
|
|
|
|
|
|
/* A straight port of XlibInt.c would call _XSetSeqSyncFunction
|
|
|
|
* here. However that does no good: unlike traditional Xlib,
|
|
|
|
* Xlib/XCB almost never calls _XFlush because _XPutXCBBuffer
|
|
|
|
* automatically pushes requests down into XCB, so Xlib's buffer
|
|
|
|
* is empty most of the time. Since setting a synchandler has no
|
|
|
|
* effect until after UnlockDisplay returns, we may as well do
|
|
|
|
* the check in _XUnlockDisplay. */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* _XFlush - Flush the X request buffer. If the buffer is empty, no
|
|
|
|
* action is taken.
|
|
|
|
*/
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* _XAllocID - resource ID allocation routine. */
|
|
|
|
XID _XAllocID(Display *dpy)
|
|
|
|
{
|
|
|
|
XID ret = dpy->xcb->next_xid;
|
|
|
|
dpy->xcb->next_xid = 0;
|
|
|
|
|
2008-06-11 14:55:41 -06:00
|
|
|
if(!(dpy->flags & XlibDisplayPrivSync))
|
|
|
|
{
|
|
|
|
dpy->savedsynchandler = dpy->synchandler;
|
|
|
|
dpy->flags |= XlibDisplayPrivSync;
|
|
|
|
}
|
2006-11-25 09:33:55 -07:00
|
|
|
dpy->synchandler = _XIDHandler;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* _XAllocIDs - multiple resource ID allocation routine. */
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2006-12-16 09:39:39 -07:00
|
|
|
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)
|
|
|
|
{
|
|
|
|
/* Replacing an existing PendingRequest should only happen once,
|
|
|
|
when calling _XReply, and the replaced PendingRequest must
|
|
|
|
not have a condition set. */
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2006-11-25 09:33:55 -07:00
|
|
|
/*
|
|
|
|
* _XReply - Wait for a reply packet and copy its contents into the
|
|
|
|
* specified rep.
|
|
|
|
* extra: number of 32-bit words expected after the reply
|
|
|
|
* discard: should I discard data following "extra" words?
|
|
|
|
*/
|
|
|
|
Status _XReply(Display *dpy, xReply *rep, int extra, Bool discard)
|
|
|
|
{
|
|
|
|
xcb_generic_error_t *error;
|
|
|
|
xcb_connection_t *c = dpy->xcb->connection;
|
|
|
|
char *reply;
|
2006-12-16 09:39:39 -07:00
|
|
|
PendingRequest *current;
|
2006-11-25 09:33:55 -07:00
|
|
|
|
|
|
|
assert(!dpy->xcb->reply_data);
|
|
|
|
|
2007-09-30 04:11:57 -06:00
|
|
|
if(dpy->flags & XlibDisplayIOError)
|
|
|
|
return 0;
|
|
|
|
|
2006-12-16 09:39:39 -07:00
|
|
|
/* Internals of UnlockDisplay done by hand here, so that we can
|
|
|
|
insert_pending_request *after* we _XPutXCBBuffer, but before we
|
|
|
|
unlock the display. */
|
|
|
|
_XPutXCBBuffer(dpy);
|
|
|
|
current = insert_pending_request(dpy);
|
2007-09-30 04:11:57 -06:00
|
|
|
if(!dpy->lock || dpy->lock->locking_level == 0)
|
|
|
|
xcb_xlib_unlock(dpy->xcb->connection);
|
2006-12-16 09:39:39 -07:00
|
|
|
if(dpy->xcb->lock_fns.unlock_display)
|
|
|
|
dpy->xcb->lock_fns.unlock_display(dpy);
|
|
|
|
reply = xcb_wait_for_reply(c, current->sequence, &error);
|
2006-11-25 09:33:55 -07:00
|
|
|
LockDisplay(dpy);
|
|
|
|
|
|
|
|
check_internal_connections(dpy);
|
2006-12-16 09:39:39 -07:00
|
|
|
process_responses(dpy, 0, &error, current->sequence);
|
|
|
|
|
|
|
|
if(current->waiters)
|
|
|
|
{ /* The ConditionBroadcast macro contains an if; braces needed here. */
|
|
|
|
ConditionBroadcast(dpy, ¤t->condition);
|
|
|
|
}
|
2007-09-30 04:11:57 -06:00
|
|
|
--current->waiters;
|
2006-11-25 09:33:55 -07:00
|
|
|
|
|
|
|
if(error)
|
|
|
|
{
|
|
|
|
_XExtension *ext;
|
|
|
|
xError *err = (xError *) error;
|
|
|
|
int ret_code;
|
|
|
|
|
|
|
|
dpy->last_request_read = error->full_sequence;
|
|
|
|
|
|
|
|
/* Xlib is evil and assumes that even errors will be
|
|
|
|
* copied into rep. */
|
|
|
|
memcpy(rep, error, 32);
|
|
|
|
|
|
|
|
/* do not die on "no such font", "can't allocate",
|
|
|
|
"can't grab" failures */
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* we better see if there is an extension who may
|
|
|
|
* want to suppress the error.
|
|
|
|
*/
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* it's not an error, but we don't have a reply, so it's an I/O
|
|
|
|
* error. */
|
|
|
|
if(!reply)
|
|
|
|
{
|
|
|
|
_XIOError(dpy);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-09-30 04:11:57 -06:00
|
|
|
dpy->last_request_read = current->sequence;
|
2006-11-25 09:33:55 -07:00
|
|
|
|
|
|
|
/* there's no error and we have a reply. */
|
|
|
|
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);
|
|
|
|
|
|
|
|
/* error: Xlib asks too much. give them what we can anyway. */
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* _XReadPad - Read bytes from the socket taking into account incomplete
|
|
|
|
* reads. If the number of bytes is not 0 mod 4, read additional pad
|
|
|
|
* bytes.
|
|
|
|
*/
|
|
|
|
void _XReadPad(Display *dpy, char *data, long size)
|
|
|
|
{
|
|
|
|
_XRead(dpy, data, size);
|
|
|
|
dpy->xcb->reply_consumed += -size & 3;
|
|
|
|
_XFreeReplyData(dpy, False);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Read and discard "n" 8-bit bytes of data */
|
|
|
|
void _XEatData(Display *dpy, unsigned long n)
|
|
|
|
{
|
|
|
|
dpy->xcb->reply_consumed += n;
|
|
|
|
_XFreeReplyData(dpy, False);
|
|
|
|
}
|