mirror of
https://gitlab.freedesktop.org/xorg/lib/libx11.git
synced 2026-05-07 16:48:31 +02:00
Merge branch 'master' of git+ssh://herrb@git.freedesktop.org/git/xorg/lib/libX11
This commit is contained in:
commit
e876efb8aa
3 changed files with 77 additions and 105 deletions
|
|
@ -1622,6 +1622,7 @@ void _XAllocIDs(
|
|||
for (i = grep.count; i < count; i++)
|
||||
ids[i] = XAllocID(dpy);
|
||||
}
|
||||
#endif /* !USE_XCB */
|
||||
|
||||
/*
|
||||
* The hard part about this is that we only get 16 bits from a reply.
|
||||
|
|
@ -1666,6 +1667,7 @@ _XSetLastRequestRead(
|
|||
return(newseq);
|
||||
}
|
||||
|
||||
#if !USE_XCB
|
||||
/*
|
||||
* _XReply - Wait for a reply packet and copy its contents into the
|
||||
* specified rep. Meanwhile we must handle error and event packets that
|
||||
|
|
|
|||
75
src/xcl/io.c
75
src/xcl/io.c
|
|
@ -4,6 +4,7 @@
|
|||
#include "Xlibint.h"
|
||||
#include "xclint.h"
|
||||
#include <X11/XCB/xcbext.h>
|
||||
#include <X11/XCB/xcbxlib.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
|
@ -70,6 +71,7 @@ static void handle_event(Display *dpy, XCBGenericEvent *e)
|
|||
{
|
||||
if(!e)
|
||||
_XIOError(dpy);
|
||||
dpy->last_request_read = e->full_sequence;
|
||||
if(e->response_type == X_Error)
|
||||
_XError(dpy, (xError *) e);
|
||||
else
|
||||
|
|
@ -90,7 +92,7 @@ int _XEventsQueued(Display *dpy, int mode)
|
|||
if(dpy->xcl->event_owner != XlibOwnsEventQueue)
|
||||
return 0;
|
||||
|
||||
c = XCBConnectionOfDisplay(dpy);
|
||||
c = dpy->xcl->connection;
|
||||
if(mode == QueuedAfterFlush)
|
||||
_XSend(dpy, 0, 0);
|
||||
else
|
||||
|
|
@ -110,7 +112,7 @@ void _XReadEvents(Display *dpy)
|
|||
_XSend(dpy, 0, 0);
|
||||
if(dpy->xcl->event_owner != XlibOwnsEventQueue)
|
||||
return;
|
||||
handle_event(dpy, XCBWaitForEvent(XCBConnectionOfDisplay(dpy)));
|
||||
handle_event(dpy, XCBWaitForEvent(dpy->xcl->connection));
|
||||
_XEventsQueued(dpy, QueuedAfterReading);
|
||||
}
|
||||
|
||||
|
|
@ -123,7 +125,7 @@ void _XReadEvents(Display *dpy)
|
|||
*/
|
||||
void _XSend(Display *dpy, const char *data, long size)
|
||||
{
|
||||
XCBConnection *c = XCBConnectionOfDisplay(dpy);
|
||||
XCBConnection *c = dpy->xcl->connection;
|
||||
|
||||
assert(!dpy->xcl->request_extra);
|
||||
dpy->xcl->request_extra = data;
|
||||
|
|
@ -132,7 +134,7 @@ void _XSend(Display *dpy, const char *data, long size)
|
|||
/* give dpy->buffer to XCB */
|
||||
_XPutXCBBuffer(dpy);
|
||||
|
||||
if(XCBFlush(c) < 0)
|
||||
if(XCBFlush(c) <= 0)
|
||||
_XIOError(dpy);
|
||||
|
||||
/* get a new dpy->buffer */
|
||||
|
|
@ -163,7 +165,7 @@ void _XFlush(Display *dpy)
|
|||
/* _XAllocID - resource ID allocation routine. */
|
||||
XID _XAllocID(Display *dpy)
|
||||
{
|
||||
return XCBGenerateID(XCBConnectionOfDisplay(dpy));
|
||||
return XCBGenerateID(dpy->xcl->connection);
|
||||
}
|
||||
|
||||
/* _XAllocIDs - multiple resource ID allocation routine. */
|
||||
|
|
@ -174,45 +176,6 @@ void _XAllocIDs(Display *dpy, XID *ids, int count)
|
|||
ids[i] = XAllocID(dpy);
|
||||
}
|
||||
|
||||
/*
|
||||
* The hard part about this is that we only get 16 bits from a reply.
|
||||
* We have three values that will march along, with the following invariant:
|
||||
* dpy->last_request_read <= rep->sequenceNumber <= dpy->request
|
||||
* We have to keep
|
||||
* dpy->request - dpy->last_request_read < 2^16
|
||||
* or else we won't know for sure what value to use in events. We do this
|
||||
* by forcing syncs when we get close.
|
||||
*/
|
||||
unsigned long _XSetLastRequestRead(Display *dpy, xGenericReply *rep)
|
||||
{
|
||||
unsigned long newseq;
|
||||
unsigned int xcb_seqnum = XCBGetRequestRead(XCBConnectionOfDisplay(dpy));
|
||||
|
||||
/*
|
||||
* KeymapNotify has no sequence number, but is always guaranteed
|
||||
* to immediately follow another event, except when generated via
|
||||
* SendEvent (hmmm).
|
||||
*/
|
||||
if ((rep->type & 0x7f) == KeymapNotify)
|
||||
return(dpy->last_request_read);
|
||||
|
||||
newseq = (xcb_seqnum & ~((unsigned long)0xffff)) | rep->sequenceNumber;
|
||||
|
||||
/* We're always trailing XCB's processing of responses here:
|
||||
* when we see a response, it's always one that XCB has already
|
||||
* counted in its sequence number stream. So we ensure that the
|
||||
* 32-bit sequence number that we pick is, in fact, less than or
|
||||
* equal to the last thing XCB processed, taking wrap into
|
||||
* account. */
|
||||
if (newseq > xcb_seqnum)
|
||||
newseq -= 0x10000;
|
||||
assert_sequence_less(newseq, dpy->request);
|
||||
|
||||
dpy->last_request_read = newseq;
|
||||
assert_sequence_less(dpy->last_request_read, xcb_seqnum);
|
||||
return(newseq);
|
||||
}
|
||||
|
||||
static void _XFreeReplyData(Display *dpy, Bool force)
|
||||
{
|
||||
if(!force && dpy->xcl->reply_consumed < dpy->xcl->reply_length)
|
||||
|
|
@ -230,7 +193,8 @@ static void _XFreeReplyData(Display *dpy, Bool force)
|
|||
Status _XReply(Display *dpy, xReply *rep, int extra, Bool discard)
|
||||
{
|
||||
XCBGenericError *error;
|
||||
XCBConnection *c = XCBConnectionOfDisplay(dpy);
|
||||
XCBConnection *c = dpy->xcl->connection;
|
||||
unsigned long request = dpy->request;
|
||||
char *reply;
|
||||
|
||||
assert(!dpy->xcl->reply_data);
|
||||
|
|
@ -238,17 +202,32 @@ Status _XReply(Display *dpy, xReply *rep, int extra, Bool discard)
|
|||
UnlockDisplay(dpy);
|
||||
/* release buffer if UnlockDisplay didn't already */
|
||||
_XPutXCBBufferIf(dpy, _XBufferLocked);
|
||||
reply = XCBWaitForReply(c, dpy->request, &error);
|
||||
reply = XCBWaitForReply(c, request, &error);
|
||||
/* re-acquire buffer if LockDisplay won't otherwise */
|
||||
_XGetXCBBufferIf(dpy, _XBufferLocked);
|
||||
LockDisplay(dpy);
|
||||
|
||||
check_internal_connections(dpy);
|
||||
|
||||
if(dpy->xcl->event_owner == XlibOwnsEventQueue)
|
||||
{
|
||||
XCBGenericEvent *e;
|
||||
int ret;
|
||||
while((e = XCBPollForEvent(c, &ret)))
|
||||
if(e->response_type == 0 && e->full_sequence == request)
|
||||
error = (XCBGenericError *) e;
|
||||
else
|
||||
handle_event(dpy, e);
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
@ -294,6 +273,8 @@ Status _XReply(Display *dpy, xReply *rep, int extra, Bool discard)
|
|||
return 0;
|
||||
}
|
||||
|
||||
dpy->last_request_read = request;
|
||||
|
||||
/* there's no error and we have a reply. */
|
||||
dpy->xcl->reply_data = reply;
|
||||
dpy->xcl->reply_consumed = sizeof(xReply) + (extra * 4);
|
||||
|
|
@ -307,8 +288,6 @@ Status _XReply(Display *dpy, xReply *rep, int extra, Bool discard)
|
|||
|
||||
memcpy(rep, dpy->xcl->reply_data, dpy->xcl->reply_consumed);
|
||||
_XFreeReplyData(dpy, discard);
|
||||
|
||||
_XEventsQueued(dpy, QueuedAfterReading);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
static void _XLockDisplay(Display *dpy)
|
||||
{
|
||||
pthread_mutex_lock(XCBGetIOLock(XCBConnectionOfDisplay(dpy)));
|
||||
pthread_mutex_lock(XCBGetIOLock(dpy->xcl->connection));
|
||||
_XGetXCBBufferIf(dpy, _XBufferUnlocked);
|
||||
++dpy->xcl->lock_count;
|
||||
}
|
||||
|
|
@ -46,14 +46,14 @@ static void _XUnlockDisplay(Display *dpy)
|
|||
* invariants hold. */
|
||||
if(!dpy->xcl->lock_count)
|
||||
{
|
||||
assert(XCBGetRequestSent(XCBConnectionOfDisplay(dpy)) == dpy->request);
|
||||
assert(XCBGetRequestSent(dpy->xcl->connection) == dpy->request);
|
||||
|
||||
/* Traditional Xlib does this in _XSend; see the Xlib/XCB version
|
||||
* of that function for why we do it here instead. */
|
||||
_XSetSeqSyncFunction(dpy);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(XCBGetIOLock(XCBConnectionOfDisplay(dpy)));
|
||||
pthread_mutex_unlock(XCBGetIOLock(dpy->xcl->connection));
|
||||
}
|
||||
|
||||
void XUnlockDisplay(Display* dpy)
|
||||
|
|
@ -67,12 +67,12 @@ int _XInitDisplayLock(Display *dpy)
|
|||
{
|
||||
#ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
|
||||
pthread_mutex_t lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
|
||||
*XCBGetIOLock(XCBConnectionOfDisplay(dpy)) = lock;
|
||||
*XCBGetIOLock(dpy->xcl->connection) = lock;
|
||||
#else
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||
pthread_mutex_init(XCBGetIOLock(XCBConnectionOfDisplay(dpy)), &attr);
|
||||
pthread_mutex_init(XCBGetIOLock(dpy->xcl->connection), &attr);
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
#endif
|
||||
|
||||
|
|
@ -99,7 +99,6 @@ void _XFreeDisplayLock(Display *dpy)
|
|||
static void call_handlers(Display *dpy, XCBGenericRep *buf)
|
||||
{
|
||||
_XAsyncHandler *async, *next;
|
||||
_XSetLastRequestRead(dpy, (xGenericReply *) buf);
|
||||
for(async = dpy->async_handlers; async; async = next)
|
||||
{
|
||||
next = async->next;
|
||||
|
|
@ -114,7 +113,7 @@ void _XGetXCBBuffer(Display *dpy)
|
|||
{
|
||||
static const xReq dummy_request;
|
||||
|
||||
XCBConnection *c = XCBConnectionOfDisplay(dpy);
|
||||
XCBConnection *c = dpy->xcl->connection;
|
||||
|
||||
dpy->last_req = (char *) &dummy_request;
|
||||
|
||||
|
|
@ -127,7 +126,7 @@ void _XGetXCBBuffer(Display *dpy)
|
|||
PendingRequest *req = dpy->xcl->pending_requests;
|
||||
/* If this request hasn't been read off the wire yet, save the
|
||||
* rest for later. */
|
||||
if((signed int) (XCBGetRequestRead(c) - req->sequence) <= 0)
|
||||
if((signed int) (XCBGetQueuedRequestRead(c) - req->sequence) <= 0)
|
||||
break;
|
||||
dpy->xcl->pending_requests = req->next;
|
||||
/* This can't block due to the above test, but it could "fail"
|
||||
|
|
@ -135,17 +134,20 @@ void _XGetXCBBuffer(Display *dpy)
|
|||
* don't care. In any failure cases, we must not have wanted
|
||||
* an entry in the reply queue for this request after all. */
|
||||
reply = XCBWaitForReply(c, req->sequence, &error);
|
||||
free(req);
|
||||
if(!reply)
|
||||
reply = (XCBGenericRep *) error;
|
||||
if(reply)
|
||||
{
|
||||
dpy->last_request_read = req->sequence;
|
||||
call_handlers(dpy, reply);
|
||||
}
|
||||
free(req);
|
||||
free(reply);
|
||||
}
|
||||
if(!dpy->xcl->pending_requests)
|
||||
dpy->xcl->pending_requests_tail = &dpy->xcl->pending_requests;
|
||||
|
||||
dpy->last_request_read = XCBGetRequestRead(c);
|
||||
dpy->last_request_read = XCBGetQueuedRequestRead(c);
|
||||
assert_sequence_less(dpy->last_request_read, dpy->request);
|
||||
}
|
||||
|
||||
|
|
@ -153,12 +155,12 @@ static inline int issue_complete_request(Display *dpy, int veclen, struct iovec
|
|||
{
|
||||
XCBProtocolRequest xcb_req = { 0 };
|
||||
unsigned int sequence;
|
||||
int bigreq = 0;
|
||||
int flags = XCB_REQUEST_RAW;
|
||||
int i;
|
||||
CARD32 len;
|
||||
size_t rem;
|
||||
size_t len;
|
||||
|
||||
/* skip empty iovecs. if no iovecs remain, we're done. */
|
||||
assert(veclen >= 0);
|
||||
while(veclen > 0 && vec[0].iov_len == 0)
|
||||
--veclen, ++vec;
|
||||
if(!veclen)
|
||||
|
|
@ -167,20 +169,22 @@ static inline int issue_complete_request(Display *dpy, int veclen, struct iovec
|
|||
/* we have at least part of a request. dig out the length field.
|
||||
* note that length fields are always in vec[0]: Xlib doesn't split
|
||||
* fixed-length request parts. */
|
||||
assert(vec[0].iov_len >= 4);
|
||||
len = ((CARD16 *) vec[0].iov_base)[1];
|
||||
if(len == 0)
|
||||
{
|
||||
/* it's a bigrequest. dig out the *real* length field. */
|
||||
assert(vec[0].iov_len >= 8);
|
||||
len = ((CARD32 *) vec[0].iov_base)[1];
|
||||
bigreq = 1;
|
||||
}
|
||||
len <<= 2;
|
||||
|
||||
/* do we have enough data for a complete request? how many iovec
|
||||
* elements does it span? */
|
||||
for(i = 0; i < veclen; ++i)
|
||||
{
|
||||
CARD32 oldlen = len;
|
||||
len -= (vec[i].iov_len + 3) >> 2;
|
||||
size_t oldlen = len;
|
||||
len -= vec[i].iov_len;
|
||||
/* if len is now 0 or has wrapped, we have enough data. */
|
||||
if((len - 1) > oldlen)
|
||||
break;
|
||||
|
|
@ -191,45 +195,30 @@ static inline int issue_complete_request(Display *dpy, int veclen, struct iovec
|
|||
/* we have enough data to issue one complete request. the remaining
|
||||
* code can't fail. */
|
||||
|
||||
/* len says how far we overshot our data needs in 4-byte units.
|
||||
* (it's negative if we actually overshot, or 0 if we're right on.)
|
||||
* rem is overshoot in 1-byte units, so it needs to have trailing
|
||||
* padding subtracted off if we're not using that padding in this
|
||||
* request. */
|
||||
if(len)
|
||||
rem = (-len << 2) - (-vec[i].iov_len & 3);
|
||||
else
|
||||
rem = 0;
|
||||
vec[i].iov_len -= rem;
|
||||
/* len says how far we overshot our data needs. (it's "negative" if
|
||||
* we actually overshot, or 0 if we're right on.) */
|
||||
vec[i].iov_len += len;
|
||||
xcb_req.count = i + 1;
|
||||
xcb_req.opcode = ((CARD8 *) vec[0].iov_base)[0];
|
||||
|
||||
/* undo bigrequest formatting. XCBSendRequest will redo it. */
|
||||
if(bigreq)
|
||||
{
|
||||
CARD32 *p = vec[0].iov_base;
|
||||
p[1] = p[0];
|
||||
vec[0].iov_base = (char *) vec[0].iov_base + 4;
|
||||
vec[0].iov_len -= 4;
|
||||
}
|
||||
/* if we don't own the event queue, we have to ask XCB to set our
|
||||
* errors aside for us. */
|
||||
if(dpy->xcl->event_owner != XlibOwnsEventQueue)
|
||||
flags |= XCB_REQUEST_CHECKED;
|
||||
|
||||
/* send the accumulated request. */
|
||||
XCBSendRequest(XCBConnectionOfDisplay(dpy), &sequence, vec, &xcb_req);
|
||||
sequence = XCBSendRequest(dpy->xcl->connection, flags, vec, &xcb_req);
|
||||
if(!sequence)
|
||||
_XIOError(dpy);
|
||||
|
||||
/* update the iovecs to refer only to data not yet sent. */
|
||||
vec[i].iov_base = (char *) vec[i].iov_base + vec[i].iov_len;
|
||||
vec[i].iov_len = rem;
|
||||
while(--i >= 0)
|
||||
vec[i].iov_len = 0;
|
||||
vec[i].iov_len = -len;
|
||||
|
||||
/* For requests we issue, we need to get back replies and
|
||||
* errors. That's true even if we don't own the event queue, and
|
||||
* also if there are async handlers registered. If we do own the
|
||||
* event queue then errors can be handled elsewhere more
|
||||
* cheaply; and if there aren't any async handlers (but the
|
||||
* pure-Xlib code was correct) then there won't be any replies
|
||||
* so we needn't look for them. */
|
||||
if(dpy->xcl->event_owner != XlibOwnsEventQueue || dpy->async_handlers)
|
||||
/* iff we asked XCB to set aside errors, we must pick those up
|
||||
* eventually. iff there are async handlers, we may have just
|
||||
* issued requests that will generate replies. in either case,
|
||||
* we need to remember to check later. */
|
||||
if(flags & XCB_REQUEST_CHECKED || dpy->async_handlers)
|
||||
{
|
||||
PendingRequest *req = malloc(sizeof(PendingRequest));
|
||||
assert(req);
|
||||
|
|
@ -243,9 +232,11 @@ static inline int issue_complete_request(Display *dpy, int veclen, struct iovec
|
|||
|
||||
void _XPutXCBBuffer(Display *dpy)
|
||||
{
|
||||
XCBConnection *c = XCBConnectionOfDisplay(dpy);
|
||||
static char const pad[3];
|
||||
const int padsize = -dpy->xcl->request_extra_size & 3;
|
||||
XCBConnection *c = dpy->xcl->connection;
|
||||
_XExtension *ext;
|
||||
struct iovec iov[2];
|
||||
struct iovec iov[5];
|
||||
|
||||
assert_sequence_less(dpy->last_request_read, dpy->request);
|
||||
assert_sequence_less(XCBGetRequestSent(c), dpy->request);
|
||||
|
|
@ -255,23 +246,23 @@ void _XPutXCBBuffer(Display *dpy)
|
|||
ext->before_flush(dpy, &ext->codes, dpy->buffer, dpy->bufptr - dpy->buffer);
|
||||
if(dpy->xcl->request_extra)
|
||||
{
|
||||
static char const pad[3];
|
||||
int padsize = -dpy->xcl->request_extra_size & 3;
|
||||
ext->before_flush(dpy, &ext->codes, dpy->xcl->request_extra, dpy->xcl->request_extra_size);
|
||||
if(padsize)
|
||||
ext->before_flush(dpy, &ext->codes, pad, padsize);
|
||||
}
|
||||
}
|
||||
|
||||
iov[0].iov_base = dpy->buffer;
|
||||
iov[0].iov_len = dpy->bufptr - dpy->buffer;
|
||||
iov[1].iov_base = (caddr_t) dpy->xcl->request_extra;
|
||||
iov[1].iov_len = dpy->xcl->request_extra_size;
|
||||
iov[2].iov_base = dpy->buffer;
|
||||
iov[2].iov_len = dpy->bufptr - dpy->buffer;
|
||||
iov[3].iov_base = (caddr_t) dpy->xcl->request_extra;
|
||||
iov[3].iov_len = dpy->xcl->request_extra_size;
|
||||
iov[4].iov_base = (caddr_t) pad;
|
||||
iov[4].iov_len = padsize;
|
||||
|
||||
while(issue_complete_request(dpy, 2, iov))
|
||||
while(issue_complete_request(dpy, 3, iov + 2))
|
||||
/* empty */;
|
||||
|
||||
assert(iov[0].iov_len == 0 && iov[1].iov_len == 0);
|
||||
assert(iov[2].iov_len == 0 && iov[3].iov_len == 0 && iov[4].iov_len == 0);
|
||||
|
||||
dpy->xcl->request_extra = 0;
|
||||
dpy->xcl->request_extra_size = 0;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue