|
|
BSD 4.3reno
/*
* $XConsortium: XlibInt.c,v 11.90 88/09/30 17:25:18 jim Exp $
*/
#include "copyright.h"
/* Copyright Massachusetts Institute of Technology 1985, 1986, 1987 */
/*
* XlibInternal.c - Internal support routines for the C subroutine
* interface library (Xlib) to the X Window System Protocol V11.0.
*/
#define NEED_EVENTS
#define NEED_REPLIES
#include <stdio.h>
#include "Xlibint.h"
#ifdef ISOCONN
#include <isode/psap.h>
#include <isode/tsap.h>
#include <isode/isoservent.h>
#endif /* ISOCONN */
#ifdef CRAY
/*
* Cray UniCOS does not have readv and writev so we emulate
*/
#include <sys/socket.h>
static int readv (fd, iov, iovcnt)
int fd;
struct iovec *iov;
int iovcnt;
{
struct msghdr hdr;
hdr.msg_iov = iov;
hdr.msg_iovlen = iovcnt;
hdr.msg_accrights = 0;
hdr.msg_accrightslen = 0;
hdr.msg_name = 0;
hdr.msg_namelen = 0;
return (recvmsg (fd, &hdr, 0));
}
static int writev (fd, iov, iovcnt)
int fd;
struct iovec *iov;
int iovcnt;
{
struct msghdr hdr;
hdr.msg_iov = iov;
hdr.msg_iovlen = iovcnt;
hdr.msg_accrights = 0;
hdr.msg_accrightslen = 0;
hdr.msg_name = 0;
hdr.msg_namelen = 0;
return (sendmsg (fd, &hdr, 0));
}
#endif /* CRAY */
#ifdef ISOCONN
/*
* Need these Convenience routines to map IO to T-service
* XXX
* Should map error returns in td->td_reason into
* errno's appropriately...
*/
/*
* Check if any bytes queued that could be read...
*/
TBytesReadable(fd, ptr)
int fd;
long *ptr;
{
struct TSAPdisconnect tds;
struct TSAPdisconnect *td = &tds;
int ret = TSelectOctets (fd, ptr, td);
if (ret == NOTOK) {
fprintf(stderr, "Client TBytesReadable: %s\n",
TErrString(td->td_reason));
}
return ret;
}
/*
* need followinf for arg mismatch
*/
UBytesReadable(fd, ptr)
int fd;
long *ptr;
{
return ioctl(fd, FIONREAD, ptr);
}
/*
* Simple read from transport cx, client
*/
TReadFromServer(fd, data, size)
int fd;
unsigned size;
char *data;
{
char *aptr = data;
struct TSAPdisconnect tds;
struct TSAPdisconnect *td = &tds;
static struct TSAPdata txs;
static struct TSAPdata *tx = &txs;
static struct qbuf *qb;
static char *qptr;
static int ingot, qcpy, result = 0;
int q2data, ret;
#ifdef ISODEBUG
if (isodexbug) {
fprintf(stderr, "TReadFromServer %d want %d (%d buffered)\n",
fd, size, result);
}
#endif /* ISODEBUG */
if (result == 0) {
if ((ret = TReadRequest(fd, tx, OK, td)) == NOTOK) {
#ifdef ISODEBUG
if (errno == EWOULDBLOCK) {
fprintf(stderr, "Client TReadReq would block: %s\n",
TErrString(td->td_reason));
if (!DR_FATAL(td->td_reason))
errno = EWOULDBLOCK;
else
errno = EBADF;
return ret;
}
if (isodexbug)
fprintf(stderr, "Client TReadReq: %s\n",
TErrString(td->td_reason));
#endif /* ISODEBUG */
/*
* map problems here - eg fTimeOut...
*/
if (td->td_reason == DR_TIMER)
errno = EWOULDBLOCK;
return ret;
}
result = tx->tx_cc;
qb = &(tx->tx_qbuf);
qptr = qb->qb_data;
#ifdef ISODEBUG
if (isodexbug)
fprintf(stderr, "TReadRequest want %d got %d\n",
size, result);
#endif
}
#ifdef ISODEBUG
else {
if (isodexbug)
fprintf(stderr, "TReadFromServer want %d buffered %d\n",
size, result);
}
#endif
/*
* Buffer it
*/
ingot = 0;
aptr = data;
for(ingot = 0, aptr = data, q2data = min(size, result);
ingot<q2data;
aptr += qcpy, ingot+= qcpy) {
int aleft = q2data - ingot;
if (qb->qb_len > aleft) {
qcpy = aleft;
bcopy(qptr, aptr, qcpy);
qptr += aleft;
} else {
qcpy = qb->qb_len;
bcopy(qb->qb_data, aptr, qcpy);
if ((qb = qb->qb_forw) == NULL)
break;
qptr = qb->qb_data;
}
}
if ((result -= ingot) <= 0) {
result = 0;
TXFREE(tx);
}
return ingot;
}
/*
* Simple write on transport descriptor client
*/
TWriteToServer(fd, data, size)
int fd;
unsigned size;
char *data;
{
struct TSAPdisconnect tds;
struct TSAPdisconnect *td = &tds;
#ifdef ISODEBUG
if (isodexbug)
fprintf(stderr, "TWriteToServer %d: %d\n", fd, size);
#endif
if (TDataRequest(fd, data, size, td) == NOTOK) {
if (errno != EWOULDBLOCK)
fprintf(stderr, "Client TDataReq: %s\n",
TErrString(td->td_reason));
return -1;
} else
return size;
}
/*
* This is really disgusting, as we do 2 copies - one qbuf into data,
* one data into iovecs...should really do something utterly neater or
* ask mtr to provide another T-Service interface for pre-alloced
* bufs - ideally iovec style
*
* or change the structure of X to do async...
*/
TReadvFromServer(fd, iov, iovcnt)
int fd, iovcnt;
struct iovec *iov;
{
int i, size, result, left, bcp;
char *data, *dp;
struct iovec *iovp;
for(i=0, size = 0, iovp = iov; i < iovcnt; i++, iovp++)
size += iovp->iov_len;
#ifdef ISODEBUG
if (isodexbug)
fprintf(stderr, "TReadvFromServer %d, want %d\n", fd, size);
#endif
if ((data = Xmalloc(size)) == NULL) {
#ifdef ISODEBUG
if (isodexbug)
fprintf(stderr, "TReadvFromServer, malloc failed\n");
#endif
/*
* Could map to EWOULDBLOCK...?
*/
return(-1);
}
/*
* Note, TReadFromServer is written to *NOT* return more than size
*/
if ((result = TReadFromServer(fd, data, size)) == NOTOK) {
if (errno != EWOULDBLOCK)
fprintf(stderr, "TReadvReq err\n");
return(-1);
}
left = result;
dp = data;
while (left > 0) {
bcp = iov->iov_len;
if (bcp > left )
bcp = left;
bcopy(dp, iov->iov_base, bcp);
if (bcp < left)
iov++;
dp += bcp;
left -= bcp;
}
Xfree(data);
return result;
}
/*
* scatter gather write to transport descriptor
*/
TWritevToServer(fd, iov, iovcnt)
int fd, iovcnt;
struct iovec *iov;
{
struct TSAPdisconnect tds;
struct TSAPdisconnect *td = &tds;
struct udvec uv[64], *uvp;
int i, ret, tot = 0;
/*
* Yuck needs dynamicising, or else rely on
* iov's being same as uv's
*/
if (iovcnt >= 64) {
fprintf(stderr, "Very Bad News i am afraid\n");
return -99;
}
for (i=0, uvp = uv; i<iovcnt; uvp++, iov++, i++) {
uvp->uv_base = iov->iov_base;
uvp->uv_len = iov->iov_len;
tot += uvp->uv_len;
}
#ifdef ISODEBUG
if (isodexbug)
fprintf(stderr, "TWritevToServer %d: %d\n",fd, tot);
#endif
uv[iovcnt].uv_base = NULLCP;
uv[iovcnt].uv_len = 0;
if ((ret = TWriteRequest(fd, uv, td)) == NOTOK) {
if (errno != EWOULDBLOCK)
fprintf(stderr, "Client TReadReq: %s\n", TErrString(td->td_reason));
return -1;
}
return tot;
}
TDiscFromServer(fd)
int fd;
{
struct TSAPdisconnect tds;
struct TSAPdisconnect *td = &tds;
if (TDiscRequest(fd, NULLCP, 0, td) == NOTOK)
fprintf(stderr, "TDR failed %s\n", TErrString(td->td_reason));
}
#endif /* ISOCONN */
/*
* The following routines are internal routines used by Xlib for protocol
* packet transmission and reception.
*
* XIOError(Display *) will be called if any sort of system call error occurs.
* This is assumed to be a fatal condition, i.e., XIOError should not return.
*
* XError(Display *, XErrorEvent *) will be called whenever an X_Error event is
* received. This is not assumed to be a fatal condition, i.e., it is
* acceptable for this procedure to return. However, XError should NOT
* perform any operations (directly or indirectly) on the DISPLAY.
*
* Routines declared with a return type of 'Status' return 0 on failure,
* and non 0 on success. Routines with no declared return type don't
* return anything. Whenever possible routines that create objects return
* the object they have created.
*/
_XQEvent *_qfree = NULL; /* NULL _XQEvent. */
static int padlength[4] = {0, 3, 2, 1};
/* lookup table for adding padding bytes to data that is read from
or written to the X socket. */
static xReq _dummy_request = {
0, 0, 0
};
/*
* _XFlush - Flush the X request buffer. If the buffer is empty, no
* action is taken. This routine correctly handles incremental writes.
* This routine may have to be reworked if int < long.
*/
_XFlush (dpy)
register Display *dpy;
{
register long size, todo;
register int write_stat;
register char *bufindex;
size = todo = dpy->bufptr - dpy->buffer;
bufindex = dpy->bufptr = dpy->buffer;
/*
* While write has not written the entire buffer, keep looping
* until the entire buffer is written. bufindex will be incremented
* and size decremented as buffer is written out.
*/
while (size) {
errno = 0;
write_stat = WriteToServer(dpy->fd, bufindex, (int) todo);
if (write_stat >= 0) {
size -= write_stat;
todo = size;
bufindex += write_stat;
#ifdef EWOULDBLOCK
} else if (errno == EWOULDBLOCK) {
_XWaitForWritable(dpy);
#endif
#ifdef SUNSYSV
} else if (errno == 0) {
_XWaitForWritable(dpy);
#endif
#ifdef EMSGSIZE
} else if (errno == EMSGSIZE) {
todo >>= 1;
#endif
} else {
/* Write failed! */
/* errno set by write system call. */
(*_XIOErrorFunction)(dpy);
}
}
dpy->last_req = (char *)&_dummy_request;
}
int
_XEventsQueued (dpy, mode)
register Display *dpy;
int mode;
{
register int len;
int pend;
char buf[BUFSIZE];
register xReply *rep;
if (mode == QueuedAfterFlush)
_XFlush(dpy);
if (BytesReadable(dpy->fd, (char *) &pend) < 0)
(*_XIOErrorFunction)(dpy);
if ((len = pend) < SIZEOF(xReply))
return(dpy->qlen); /* _XFlush can enqueue events */
else if (len > BUFSIZE)
len = BUFSIZE;
len /= SIZEOF(xReply);
pend = len * SIZEOF(xReply);
_XRead (dpy, buf, (long) pend);
/* no space between comma and type or else macro will die */
STARTITERATE (rep,xReply, buf, (len > 0), len--) {
if (rep->generic.type == X_Error)
_XError(dpy, (xError *)rep);
else /* must be an event packet */
_XEnq(dpy, (xEvent *) rep);
}
ENDITERATE
return(dpy->qlen);
}
/* _XReadEvents - Flush the output queue,
* then read as many events as possible (but at least 1) and enqueue them
*/
_XReadEvents(dpy)
register Display *dpy;
{
char buf[BUFSIZE];
long pend_not_register; /* because can't "&" a register variable */
register long pend;
register xEvent *ev;
Bool not_yet_flushed = True;
do {
/* find out how much data can be read */
if (BytesReadable(dpy->fd, (char *) &pend_not_register) < 0)
(*_XIOErrorFunction)(dpy);
pend = pend_not_register;
/* must read at least one xEvent; if none is pending, then
we'll just flush and block waiting for it */
if (pend < SIZEOF(xEvent)) {
pend = SIZEOF(xEvent);
/* don't flush until we block the first time */
if (not_yet_flushed) {
int qlen = dpy->qlen;
_XFlush (dpy);
if (qlen != dpy->qlen) return;
not_yet_flushed = False;
}
}
/* but we won't read more than the max buffer size */
if (pend > BUFSIZE)
pend = BUFSIZE;
/* round down to an integral number of XReps */
pend = (pend / SIZEOF(xEvent)) * SIZEOF(xEvent);
_XRead (dpy, buf, pend);
/* no space between comma and type or else macro will die */
STARTITERATE (ev,xEvent, buf, (pend > 0),
pend -= SIZEOF(xEvent)) {
if (ev->u.u.type == X_Error)
_XError (dpy, (xError *) ev);
else /* it's an event packet; enqueue it */
_XEnq (dpy, ev);
}
ENDITERATE
} while (dpy->head == NULL);
}
/*
* _XRead - Read bytes from the socket taking into account incomplete
* reads. This routine may have to be reworked if int < long.
*/
_XRead (dpy, data, size)
register Display *dpy;
register char *data;
register long size;
{
register long bytes_read;
if (size == 0) return;
errno = 0;
while ((bytes_read = ReadFromServer(dpy->fd, data, (int)size))
!= size) {
if (bytes_read > 0) {
size -= bytes_read;
data += bytes_read;
}
#ifdef EWOULDBLOCK
else if (errno == EWOULDBLOCK) {
_XWaitForReadable(dpy);
errno = 0;
}
#endif
#ifdef SUNSYSV
else if (errno == 0) {
_XWaitForReadable(dpy);
}
#endif
else if (bytes_read == 0) {
/* Read failed because of end of file! */
errno = EPIPE;
(*_XIOErrorFunction)(dpy);
}
else /* bytes_read is less than 0; presumably -1 */ {
/* If it's a system call interrupt, it's not an error. */
if (errno != EINTR)
(*_XIOErrorFunction)(dpy);
}
}
}
#ifdef WORD64
/*
* XXX This is a *really* stupid way of doing this....
*/
#define PACKBUFFERSIZE 4096
/*
* _XRead32 - Read bytes from the socket unpacking each 32 bits
* into a long (64 bits on a CRAY computer).
*
*/
static _doXRead32 (dpy, data, size, packbuffer)
register Display *dpy;
register long *data;
register long size;
register char *packbuffer;
{
long *lpack,*lp;
long mask32 = 0x00000000ffffffff;
long maskw, nwords, i, bits;
_XReadPad (dpy, packbuffer, size);
lp = data;
lpack = (long *) packbuffer;
nwords = size >> 2;
bits = 32;
for(i=0;i<nwords;i++){
maskw = mask32 << bits;
*lp++ = ( *lpack & maskw ) >> bits;
bits = bits ^32;
if(bits){
lpack++;
}
}
}
_XRead32 (dpy, data, len)
Display *dpy;
long *data;
long len;
{
char packbuffer[PACKBUFFERSIZE];
unsigned nwords = (PACKBUFFERSIZE >> 2); /* bytes to CARD32 */
for (; len > nwords; len -= nwords, data += nwords) {
_doXRead32 (dpy, data, nwords, packbuffer);
}
_doXRead32 (dpy, data, len, packbuffer);
}
/*
* _XRead16 - Read bytes from the socket unpacking each 16 bits
* into a long (64 bits on a CRAY computer).
*
*/
static _doXRead16 (dpy, data, size, packbuffer)
register Display *dpy;
register short *data;
register long size;
char *packbuffer;
{
long *lpack,*lp;
long mask16 = 0x000000000000ffff;
long maskw, nwords, i, bits;
_XRead(dpy,packbuffer,size); /* don't do a padded read... */
lp = (long *) data;
lpack = (long *) packbuffer;
nwords = size >> 1; /* number of 16 bit words to be unpacked */
bits = 48;
for(i=0;i<nwords;i++){
maskw = mask16 << bits;
*lp++ = ( *lpack & maskw ) >> bits;
bits -= 16;
if(bits < 0){
lpack++;
bits = 48;
}
}
}
_XRead16 (dpy, data, len)
Display *dpy;
short *data;
long len;
{
char packbuffer[PACKBUFFERSIZE];
unsigned nwords = (PACKBUFFERSIZE >> 1); /* bytes to CARD16 */
for (; len > nwords; len -= nwords, data += nwords) {
_doXRead16 (dpy, data, nwords, packbuffer);
}
_doXRead16 (dpy, data, len, packbuffer);
}
_XRead16Pad (dpy, data, size)
Display *dpy;
short *data;
long size;
{
int slop = (size & 3);
short slopbuf[3];
_XRead16 (dpy, data, size);
if (slop > 0) {
_XRead16 (dpy, slopbuf, 4 - slop);
}
}
#endif /* WORD64 */
/*
* _XReadPad - Read bytes from the socket taking into account incomplete
* reads. If the number of bytes is not 0 mod 32, read additional pad
* bytes. This routine may have to be reworked if int < long.
*/
_XReadPad (dpy, data, size)
register Display *dpy;
register char *data;
register long size;
{
register long bytes_read;
struct iovec iov[2];
char pad[3];
if (size == 0) return;
iov[0].iov_len = (int)size;
iov[0].iov_base = data;
/*
* The following hack is used to provide 32 bit long-word
* aligned padding. The [1] vector is of length 0, 1, 2, or 3,
* whatever is needed.
*/
iov[1].iov_len = padlength[size & 3];
iov[1].iov_base = pad;
size += iov[1].iov_len;
errno = 0;
while ((bytes_read = ReadvFromServer (dpy->fd, iov, 2)) != size) {
if (bytes_read > 0) {
size -= bytes_read;
if ((iov[0].iov_len -= bytes_read) < 0) {
iov[1].iov_len += iov[0].iov_len;
iov[1].iov_base -= iov[0].iov_len;
iov[0].iov_len = 0;
}
else
iov[0].iov_base += bytes_read;
}
#ifdef EWOULDBLOCK
else if (errno == EWOULDBLOCK) {
_XWaitForReadable(dpy);
errno = 0;
}
#endif
#ifdef SUNSYSV
else if (errno == 0) {
_XWaitForReadable(dpy);
}
#endif
else if (bytes_read == 0) {
/* Read failed because of end of file! */
errno = EPIPE;
(*_XIOErrorFunction)(dpy);
}
else /* bytes_read is less than 0; presumably -1 */ {
/* If it's a system call interrupt, it's not an error. */
if (errno != EINTR)
(*_XIOErrorFunction)(dpy);
}
}
}
/*
* _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.
* This routine may have to be reworked if int < long;
*/
_XSend (dpy, data, size)
register Display *dpy;
char *data;
register long size;
{
struct iovec iov[3];
static char pad[3] = {0, 0, 0};
/* XText8 and XText16 require that the padding bytes be zero! */
long skip = 0;
long total = (dpy->bufptr - dpy->buffer) + ((size + 3) & ~3);
long todo = total;
while (total) {
long before = skip;
long remain = todo;
int i = 0;
long len;
/* You could be very general here and have "in" and "out" iovecs
* and write a loop without using a macro, but what the heck
*/
#define InsertIOV(pointer, length) \
len = (length) - before; \
if (len > remain) \
len = remain; \
if (len <= 0) { \
before = -len; \
} else { \
iov[i].iov_len = len; \
iov[i].iov_base = (pointer) + before; \
i++; \
remain -= len; \
before = 0; \
}
InsertIOV(dpy->buffer, dpy->bufptr - dpy->buffer)
InsertIOV(data, size)
/* Provide 32-bit aligned padding as necessary */
InsertIOV(pad, padlength[size & 3])
errno = 0;
if ((len = WritevToServer(dpy->fd, iov, i)) >= 0) {
skip += len;
total -= len;
todo = total;
#ifdef EWOULDBLOCK
} else if (errno == EWOULDBLOCK) {
_XWaitForWritable(dpy);
#endif
#ifdef SUNSYSV
} else if (errno == 0) {
_XWaitForWritable(dpy);
#endif
#ifdef EMSGSIZE
} else if (errno == EMSGSIZE) {
todo = todo >> 1;
#endif
} else {
(*_XIOErrorFunction)(dpy);
}
}
dpy->bufptr = dpy->buffer;
dpy->last_req = (char *) & _dummy_request;
}
/*
* _XAllocID - normal resource ID allocation routine. A client
* can roll his own and instatantiate it if he wants, but must
* follow the rules.
*/
XID _XAllocID(dpy)
register Display *dpy;
{
return (dpy->resource_base + (dpy->resource_id++ << dpy->resource_shift));
}
/*
* The hard part about this is that we only get 16 bits from a reply. Well,
* then, we have three values that will march along, with the following
* invariant:
* dpy->last_request_read <= rep->sequenceNumber <= dpy->request
* The right choice for rep->sequenceNumber is the largest that
* still meets these constraints.
*/
static unsigned long
_SetLastRequestRead(dpy, rep)
register Display *dpy;
register xGenericReply *rep;
{
register unsigned long newseq, lastseq;
/*
* 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 = (dpy->last_request_read & ~((unsigned long)0xffff)) |
rep->sequenceNumber;
lastseq = dpy->last_request_read;
while (newseq < lastseq) {
newseq += 0x10000;
if (newseq > dpy->request) {
(void) fprintf (stderr,
"Xlib: sequence lost (0x%lx > 0x%lx) in reply type 0x%x!\n",
newseq, dpy->request,
(unsigned int) rep->type);
newseq -= 0x10000;
break;
}
}
dpy->last_request_read = newseq;
return(newseq);
}
/*
* _XReply - Wait for a reply packet and copy its contents into the
* specified rep. Mean while we must handle error and event packets that
* we may encounter.
*/
Status _XReply (dpy, rep, extra, discard)
register Display *dpy;
register xReply *rep;
int extra; /* number of 32-bit words expected after the reply */
Bool discard; /* should I discard data followind "extra" words? */
{
/* Pull out the serial number now, so that (currently illegal) requests
* generated by an error handler don't confuse us.
*/
unsigned long cur_request = dpy->request;
_XFlush(dpy);
while (1) {
_XRead(dpy, (char *)rep, (long)SIZEOF(xReply));
switch ((int)rep->generic.type) {
case X_Reply:
/* Reply received. Fast update for synchronous replies,
* but deal with multiple outstanding replies.
*/
if (rep->generic.sequenceNumber == (cur_request & 0xffff))
dpy->last_request_read = cur_request;
else
(void) _SetLastRequestRead(dpy, &rep->generic);
if (extra == 0) {
if (discard && (rep->generic.length > 0))
/* unexpectedly long reply! */
_EatData (dpy, rep->generic.length);
return (1);
}
if (extra == rep->generic.length) {
/*
* Read the extra data into storage immediately following
* the GenericReply structure.
*/
_XRead (dpy, NEXTPTR(rep,xReply), ((long)extra) << 2);
return (1);
}
if (extra < rep->generic.length) {
/* Actual reply is longer than "extra" */
_XRead (dpy, NEXTPTR(rep,xReply), ((long)extra) << 2);
if (discard)
_EatData (dpy, rep->generic.length - extra);
return (1);
}
/*
*if we get here, then extra > rep->generic.length--meaning we
* read a reply that's shorter than we expected. This is an
* error, but we still need to figure out how to handle it...
*/
_XRead (dpy, NEXTPTR(rep,xReply),
((long) rep->generic.length) << 2);
(*_XIOErrorFunction) (dpy);
return (0);
case X_Error:
{
register _XExtension *ext;
register Bool ret = False;
int ret_code;
xError *err = (xError *) rep;
unsigned long serial;
serial = _SetLastRequestRead(dpy, (xGenericReply *)rep);
if (serial == cur_request)
/* do not die on "no such font", "can't allocate",
"can't grab" failures */
switch ((int)err->errorCode) {
case BadName:
switch (err->majorCode) {
case X_OpenFont:
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.
*/
default:
ext = dpy->ext_procs;
while (ext) {
if (ext->error != NULL)
ret = (*ext->error)
(dpy, err, &ext->codes, &ret_code);
ext = ext->next;
}
if (ret) return (ret_code);
break;
}
_XError(dpy, err);
if (serial == cur_request)
return(0);
}
break;
default:
_XEnq(dpy, (xEvent *) rep);
break;
}
}
}
/* Read and discard "n" 32-bit words. */
static _EatData (dpy, n)
Display *dpy;
unsigned long n;
{
unsigned int bufsize;
char *buf;
n <<= 2; /* convert to number of bytes */
buf = Xmalloc (bufsize = (n > 2048) ? 2048 : n);
while (n) {
long bytes_read = (n > bufsize) ? bufsize : n;
_XRead (dpy, buf, bytes_read);
n -= bytes_read;
}
Xfree (buf);
}
/*
* _XEnq - Place event packets on the display's queue.
* note that no squishing of move events in V11, since there
* is pointer motion hints....
*/
_XEnq (dpy, event)
register Display *dpy;
register xEvent *event;
{
register _XQEvent *qelt;
/*NOSTRICT*/
if (qelt = _qfree) {
/* If _qfree is non-NULL do this, else malloc a new one. */
_qfree = qelt->next;
}
else if ((qelt =
(_XQEvent *) Xmalloc((unsigned)sizeof(_XQEvent))) == NULL) {
/* Malloc call failed! */
errno = ENOMEM;
(*_XIOErrorFunction)(dpy);
}
qelt->next = NULL;
/* go call through display to find proper event reformatter */
if ((*dpy->event_vec[event->u.u.type & 0177])(dpy, &qelt->event, event)) {
if (dpy->tail) dpy->tail->next = qelt;
else dpy->head = qelt;
dpy->tail = qelt;
dpy->qlen++;
} else {
/* ignored, or stashed away for many-to-one compression */
qelt->next = _qfree;
_qfree = qelt;
}
}
/*
* EventToWire in seperate file in that often not needed.
*/
/*ARGSUSED*/
Bool
_XUnknownWireEvent(dpy, re, event)
register Display *dpy; /* pointer to display structure */
register XEvent *re; /* pointer to where event should be reformatted */
register xEvent *event; /* wire protocol event */
{
#ifdef notdef
(void) fprintf(stderr,
"Xlib: unhandled wire event! event number = %d, display = %x\n.",
event->u.u.type, dpy);
#endif
return(False);
}
/*ARGSUSED*/
Status
_XUnknownNativeEvent(dpy, re, event)
register Display *dpy; /* pointer to display structure */
register XEvent *re; /* pointer to where event should be reformatted */
register xEvent *event; /* wire protocol event */
{
#ifdef notdef
(void) fprintf(stderr,
"Xlib: unhandled native event! event number = %d, display = %x\n.",
re->type, dpy);
#endif
return(0);
}
/*
* reformat a wire event into an XEvent structure of the right type.
*/
Bool
_XWireToEvent(dpy, re, event)
register Display *dpy; /* pointer to display structure */
register XEvent *re; /* pointer to where event should be reformatted */
register xEvent *event; /* wire protocol event */
{
re->type = event->u.u.type & 0x7f;
((XAnyEvent *)re)->serial = _SetLastRequestRead(dpy,
(xGenericReply *)event);
((XAnyEvent *)re)->send_event = ((event->u.u.type & 0x80) != 0);
((XAnyEvent *)re)->display = dpy;
/* Ignore the leading bit of the event type since it is set when a
client sends an event rather than the server. */
switch (event-> u.u.type & 0177) {
case KeyPress:
case KeyRelease:
{
register XKeyEvent *ev = (XKeyEvent*) re;
ev->root = event->u.keyButtonPointer.root;
ev->window = event->u.keyButtonPointer.event;
ev->subwindow = event->u.keyButtonPointer.child;
ev->time = event->u.keyButtonPointer.time;
ev->x = event->u.keyButtonPointer.eventX;
ev->y = event->u.keyButtonPointer.eventY;
ev->x_root = event->u.keyButtonPointer.rootX;
ev->y_root = event->u.keyButtonPointer.rootY;
ev->state = event->u.keyButtonPointer.state;
ev->same_screen = event->u.keyButtonPointer.sameScreen;
ev->keycode = event->u.u.detail;
}
break;
case ButtonPress:
case ButtonRelease:
{
register XButtonEvent *ev = (XButtonEvent *) re;
ev->root = event->u.keyButtonPointer.root;
ev->window = event->u.keyButtonPointer.event;
ev->subwindow = event->u.keyButtonPointer.child;
ev->time = event->u.keyButtonPointer.time;
ev->x = event->u.keyButtonPointer.eventX;
ev->y = event->u.keyButtonPointer.eventY;
ev->x_root = event->u.keyButtonPointer.rootX;
ev->y_root = event->u.keyButtonPointer.rootY;
ev->state = event->u.keyButtonPointer.state;
ev->same_screen = event->u.keyButtonPointer.sameScreen;
ev->button = event->u.u.detail;
}
break;
case MotionNotify:
{
register XMotionEvent *ev = (XMotionEvent *)re;
ev->root = event->u.keyButtonPointer.root;
ev->window = event->u.keyButtonPointer.event;
ev->subwindow = event->u.keyButtonPointer.child;
ev->time = event->u.keyButtonPointer.time;
ev->x = event->u.keyButtonPointer.eventX;
ev->y = event->u.keyButtonPointer.eventY;
ev->x_root = event->u.keyButtonPointer.rootX;
ev->y_root = event->u.keyButtonPointer.rootY;
ev->state = event->u.keyButtonPointer.state;
ev->same_screen = event->u.keyButtonPointer.sameScreen;
ev->is_hint = event->u.u.detail;
}
break;
case EnterNotify:
case LeaveNotify:
{
register XCrossingEvent *ev = (XCrossingEvent *) re;
ev->root = event->u.enterLeave.root;
ev->window = event->u.enterLeave.event;
ev->subwindow = event->u.enterLeave.child;
ev->time = event->u.enterLeave.time;
ev->x = event->u.enterLeave.eventX;
ev->y = event->u.enterLeave.eventY;
ev->x_root = event->u.enterLeave.rootX;
ev->y_root = event->u.enterLeave.rootY;
ev->state = event->u.enterLeave.state;
ev->mode = event->u.enterLeave.mode;
ev->same_screen = (event->u.enterLeave.flags &
ELFlagSameScreen) && True;
ev->focus = (event->u.enterLeave.flags &
ELFlagFocus) && True;
ev->detail = event->u.u.detail;
}
break;
case FocusIn:
case FocusOut:
{
register XFocusChangeEvent *ev = (XFocusChangeEvent *) re;
ev->window = event->u.focus.window;
ev->mode = event->u.focus.mode;
ev->detail = event->u.u.detail;
}
break;
case KeymapNotify:
{
register XKeymapEvent *ev = (XKeymapEvent *) re;
ev->window = dpy->current;
bcopy ((char *)((xKeymapEvent *) event)->map,
&ev->key_vector[1],
sizeof (((xKeymapEvent *) event)->map));
}
break;
case Expose:
{
register XExposeEvent *ev = (XExposeEvent *) re;
ev->window = event->u.expose.window;
ev->x = event->u.expose.x;
ev->y = event->u.expose.y;
ev->width = event->u.expose.width;
ev->height = event->u.expose.height;
ev->count = event->u.expose.count;
}
break;
case GraphicsExpose:
{
register XGraphicsExposeEvent *ev =
(XGraphicsExposeEvent *) re;
ev->drawable = event->u.graphicsExposure.drawable;
ev->x = event->u.graphicsExposure.x;
ev->y = event->u.graphicsExposure.y;
ev->width = event->u.graphicsExposure.width;
ev->height = event->u.graphicsExposure.height;
ev->count = event->u.graphicsExposure.count;
ev->major_code = event->u.graphicsExposure.majorEvent;
ev->minor_code = event->u.graphicsExposure.minorEvent;
}
break;
case NoExpose:
{
register XNoExposeEvent *ev = (XNoExposeEvent *) re;
ev->drawable = event->u.noExposure.drawable;
ev->major_code = event->u.noExposure.majorEvent;
ev->minor_code = event->u.noExposure.minorEvent;
}
break;
case VisibilityNotify:
{
register XVisibilityEvent *ev = (XVisibilityEvent *) re;
ev->window = event->u.visibility.window;
ev->state = event->u.visibility.state;
}
break;
case CreateNotify:
{
register XCreateWindowEvent *ev =
(XCreateWindowEvent *) re;
ev->window = event->u.createNotify.window;
ev->parent = event->u.createNotify.parent;
ev->x = event->u.createNotify.x;
ev->y = event->u.createNotify.y;
ev->width = event->u.createNotify.width;
ev->height = event->u.createNotify.height;
ev->border_width = event->u.createNotify.borderWidth;
ev->override_redirect = event->u.createNotify.override;
}
break;
case DestroyNotify:
{
register XDestroyWindowEvent *ev =
(XDestroyWindowEvent *) re;
ev->window = event->u.destroyNotify.window;
ev->event = event->u.destroyNotify.event;
}
break;
case UnmapNotify:
{
register XUnmapEvent *ev = (XUnmapEvent *) re;
ev->window = event->u.unmapNotify.window;
ev->event = event->u.unmapNotify.event;
ev->from_configure = event->u.unmapNotify.fromConfigure;
}
break;
case MapNotify:
{
register XMapEvent *ev = (XMapEvent *) re;
ev->window = event->u.mapNotify.window;
ev->event = event->u.mapNotify.event;
ev->override_redirect = event->u.mapNotify.override;
}
break;
case MapRequest:
{
register XMapRequestEvent *ev = (XMapRequestEvent *) re;
ev->window = event->u.mapRequest.window;
ev->parent = event->u.mapRequest.parent;
}
break;
case ReparentNotify:
{
register XReparentEvent *ev = (XReparentEvent *) re;
ev->event = event->u.reparent.event;
ev->window = event->u.reparent.window;
ev->parent = event->u.reparent.parent;
ev->x = event->u.reparent.x;
ev->y = event->u.reparent.y;
ev->override_redirect = event->u.reparent.override;
}
break;
case ConfigureNotify:
{
register XConfigureEvent *ev = (XConfigureEvent *) re;
ev->event = event->u.configureNotify.event;
ev->window = event->u.configureNotify.window;
ev->above = event->u.configureNotify.aboveSibling;
ev->x = event->u.configureNotify.x;
ev->y = event->u.configureNotify.y;
ev->width = event->u.configureNotify.width;
ev->height = event->u.configureNotify.height;
ev->border_width = event->u.configureNotify.borderWidth;
ev->override_redirect = event->u.configureNotify.override;
}
break;
case ConfigureRequest:
{
register XConfigureRequestEvent *ev =
(XConfigureRequestEvent *) re;
ev->window = event->u.configureRequest.window;
ev->parent = event->u.configureRequest.parent;
ev->above = event->u.configureRequest.sibling;
ev->x = event->u.configureRequest.x;
ev->y = event->u.configureRequest.y;
ev->width = event->u.configureRequest.width;
ev->height = event->u.configureRequest.height;
ev->border_width = event->u.configureRequest.borderWidth;
ev->value_mask = event->u.configureRequest.valueMask;
ev->detail = event->u.u.detail;
}
break;
case GravityNotify:
{
register XGravityEvent *ev = (XGravityEvent *) re;
ev->window = event->u.gravity.window;
ev->event = event->u.gravity.event;
ev->x = event->u.gravity.x;
ev->y = event->u.gravity.y;
}
break;
case ResizeRequest:
{
register XResizeRequestEvent *ev =
(XResizeRequestEvent *) re;
ev->window = event->u.resizeRequest.window;
ev->width = event->u.resizeRequest.width;
ev->height = event->u.resizeRequest.height;
}
break;
case CirculateNotify:
{
register XCirculateEvent *ev = (XCirculateEvent *) re;
ev->window = event->u.circulate.window;
ev->event = event->u.circulate.event;
ev->place = event->u.circulate.place;
}
break;
case CirculateRequest:
{
register XCirculateRequestEvent *ev =
(XCirculateRequestEvent *) re;
ev->window = event->u.circulate.window;
ev->parent = event->u.circulate.event;
ev->place = event->u.circulate.place;
}
break;
case PropertyNotify:
{
register XPropertyEvent *ev = (XPropertyEvent *) re;
ev->window = event->u.property.window;
ev->atom = event->u.property.atom;
ev->time = event->u.property.time;
ev->state = event->u.property.state;
}
break;
case SelectionClear:
{
register XSelectionClearEvent *ev =
(XSelectionClearEvent *) re;
ev->window = event->u.selectionClear.window;
ev->selection = event->u.selectionClear.atom;
ev->time = event->u.selectionClear.time;
}
break;
case SelectionRequest:
{
register XSelectionRequestEvent *ev =
(XSelectionRequestEvent *) re;
ev->owner = event->u.selectionRequest.owner;
ev->requestor = event->u.selectionRequest.requestor;
ev->selection = event->u.selectionRequest.selection;
ev->target = event->u.selectionRequest.target;
ev->property = event->u.selectionRequest.property;
ev->time = event->u.selectionRequest.time;
}
break;
case SelectionNotify:
{
register XSelectionEvent *ev = (XSelectionEvent *) re;
ev->requestor = event->u.selectionNotify.requestor;
ev->selection = event->u.selectionNotify.selection;
ev->target = event->u.selectionNotify.target;
ev->property = event->u.selectionNotify.property;
ev->time = event->u.selectionNotify.time;
}
break;
case ColormapNotify:
{
register XColormapEvent *ev = (XColormapEvent *) re;
ev->window = event->u.colormap.window;
ev->colormap = event->u.colormap.colormap;
ev->new = event->u.colormap.new;
ev->state = event->u.colormap.state;
}
break;
case ClientMessage:
{
register int i;
register XClientMessageEvent *ev
= (XClientMessageEvent *) re;
ev->window = event->u.clientMessage.window;
ev->format = event->u.u.detail;
switch (ev->format) {
case 8:
ev->message_type = event->u.clientMessage.u.b.type;
for (i = 0; i < 20; i++)
ev->data.b[i] = event->u.clientMessage.u.b.bytes[i];
break;
case 16:
ev->message_type = event->u.clientMessage.u.s.type;
ev->data.s[0] = event->u.clientMessage.u.s.shorts0;
ev->data.s[1] = event->u.clientMessage.u.s.shorts1;
ev->data.s[2] = event->u.clientMessage.u.s.shorts2;
ev->data.s[3] = event->u.clientMessage.u.s.shorts3;
ev->data.s[4] = event->u.clientMessage.u.s.shorts4;
ev->data.s[5] = event->u.clientMessage.u.s.shorts5;
ev->data.s[6] = event->u.clientMessage.u.s.shorts6;
ev->data.s[7] = event->u.clientMessage.u.s.shorts7;
ev->data.s[8] = event->u.clientMessage.u.s.shorts8;
ev->data.s[9] = event->u.clientMessage.u.s.shorts9;
break;
case 32:
ev->message_type = event->u.clientMessage.u.l.type;
ev->data.l[0] = event->u.clientMessage.u.l.longs0;
ev->data.l[1] = event->u.clientMessage.u.l.longs1;
ev->data.l[2] = event->u.clientMessage.u.l.longs2;
ev->data.l[3] = event->u.clientMessage.u.l.longs3;
ev->data.l[4] = event->u.clientMessage.u.l.longs4;
break;
default: /* XXX should never occur */
break;
}
}
break;
case MappingNotify:
{
register XMappingEvent *ev = (XMappingEvent *)re;
ev->first_keycode = event->u.mappingNotify.firstKeyCode;
ev->request = event->u.mappingNotify.request;
ev->count = event->u.mappingNotify.count;
}
break;
default:
return(_XUnknownWireEvent(dpy, re, event));
}
return(True);
}
static char *_SysErrorMsg (n)
int n;
{
extern char *sys_errlist[];
extern int sys_nerr;
char *s = ((n >= 0 && n < sys_nerr) ? sys_errlist[n] : "unknown error");
return (s ? s : "no such error");
}
/*
* _XIOError - Default fatal system error reporting routine. Called when
* an X internal system error is encountered.
*/
_XIOError (dpy)
Display *dpy;
{
(void) fprintf (stderr,
"XIO: fatal IO error %d (%s) on X server \"%s\"\r\n",
errno, _SysErrorMsg (errno), DisplayString (dpy));
(void) fprintf (stderr,
" after %lu requests (%lu known processed) with %d events remaining.\r\n",
NextRequest(dpy) - 1, LastKnownRequestProcessed(dpy),
QLength(dpy));
if (errno == EPIPE) {
(void) fprintf (stderr,
" The connection was probably broken by a server shutdown or KillClient.\r\n");
}
exit (1);
}
/*
* _XError - Default non-fatal error reporting routine. Called when an
* X_Error packet is encountered in the input stream.
*/
int _XError (dpy, rep)
Display *dpy;
xError *rep;
{
XErrorEvent event;
/*
* X_Error packet encountered! We need to unpack the error before
* giving it to the user.
*/
event.display = dpy;
event.type = X_Error;
event.serial = _SetLastRequestRead(dpy, (xGenericReply *)rep);
event.resourceid = rep->resourceID;
event.error_code = rep->errorCode;
event.request_code = rep->majorCode;
event.minor_code = rep->minorCode;
if (_XErrorFunction != NULL) {
return ((*_XErrorFunction)(dpy, &event));
}
exit(1);
/*NOTREACHED*/
}
int _XPrintDefaultError (dpy, event, fp)
Display *dpy;
XErrorEvent *event;
FILE *fp;
{
char buffer[BUFSIZ];
char mesg[BUFSIZ];
char number[32];
char *mtype = "XlibMessage";
XGetErrorText(dpy, event->error_code, buffer, BUFSIZ);
XGetErrorDatabaseText(dpy, mtype, "XError", "X Error", mesg, BUFSIZ);
(void) fprintf(fp, "%s: %s\n ", mesg, buffer);
XGetErrorDatabaseText(dpy, mtype, "MajorCode", "Request Major code %d",
mesg, BUFSIZ);
(void) fprintf(fp, mesg, event->request_code);
sprintf(number, "%d", event->request_code);
XGetErrorDatabaseText(dpy, "XRequest", number, "", buffer, BUFSIZ);
(void) fprintf(fp, " (%s)", buffer);
fputs("\n ", fp);
XGetErrorDatabaseText(dpy, mtype, "MinorCode", "Request Minor code",
mesg, BUFSIZ);
(void) fprintf(fp, mesg, event->minor_code);
fputs("\n ", fp);
XGetErrorDatabaseText(dpy, mtype, "ResourceID", "ResourceID 0x%x",
mesg, BUFSIZ);
(void) fprintf(fp, mesg, event->resourceid);
fputs("\n ", fp);
XGetErrorDatabaseText(dpy, mtype, "ErrorSerial", "Error Serial #%d",
mesg, BUFSIZ);
(void) fprintf(fp, mesg, event->serial);
fputs("\n ", fp);
XGetErrorDatabaseText(dpy, mtype, "CurrentSerial", "Current Serial #%d",
mesg, BUFSIZ);
(void) fprintf(fp, mesg, dpy->request);
fputs("\n", fp);
if (event->error_code == BadImplementation) return 0;
return 1;
}
int _XDefaultError(dpy, event)
Display *dpy;
XErrorEvent *event;
{
if (_XPrintDefaultError (dpy, event, stderr) == 0) return 0;
exit(1);
/*NOTREACHED*/
}
int (*_XIOErrorFunction)() = _XIOError;
int (*_XErrorFunction)() = _XDefaultError;
/*
* This routine can be used to (cheaply) get some memory within a single
* Xlib routine for scratch space. It is reallocated from the same place
* each time, unless the library needs a large scratch space.
*/
char *_XAllocScratch (dpy, nbytes)
register Display *dpy;
unsigned long nbytes;
{
if (nbytes > dpy->scratch_length) {
if (dpy->scratch_buffer != NULL) Xfree (dpy->scratch_buffer);
return( dpy->scratch_length = nbytes,
dpy->scratch_buffer = Xmalloc ((unsigned)nbytes) );
}
return (dpy->scratch_buffer);
}
/*
* Given a visual id, find the visual structure for this id on this display.
*/
Visual *_XVIDtoVisual (dpy, id)
Display *dpy;
VisualID id;
{
register int i, j, k;
register Screen *sp;
register Depth *dp;
register Visual *vp;
for (i = 0; i < dpy->nscreens; i++) {
sp = &dpy->screens[i];
for (j = 0; j < sp->ndepths; j++) {
dp = &sp->depths[j];
for (k = 0; k < dp->nvisuals; k++) {
vp = &dp->visuals[k];
if (vp->visualid == id) return (vp);
}
}
}
return (NULL);
}
XFree (data)
char *data;
{
Xfree (data);
}
#ifdef DataRoutineIsProcedure
void Data (dpy, data, len)
Display *dpy;
char *data;
long len;
{
if (dpy->bufptr + (len) <= dpy->bufmax) {
bcopy(data, dpy->bufptr, (int)len);
dpy->bufptr += ((len) + 3) & ~3;
} else {
_XSend(dpy, data, len);
}
}
#endif /* DataRoutineIsProcedure */
#ifdef WORD64
/*
* XXX This is a *really* stupid way of doing this. It should just use
* dpy->bufptr directly, taking into account where in the word it is.
*/
/*
* Data16 - Place 16 bit data in the buffer.
*
* "dpy" is a pointer to a Display.
* "data" is a pointer to the data.
* "len" is the length in bytes of the data.
*/
static doData16(dpy, data, len, packbuffer)
register Display *dpy;
short *data;
unsigned len;
char *packbuffer;
{
long *lp,*lpack;
long i, nwords,bits;
long mask16 = 0x000000000000ffff;
lp = (long *)data;
lpack = (long *)packbuffer;
*lpack = 0;
/* nwords is the number of 16 bit values to be packed,
* the low order 16 bits of each word will be packed
* into 64 bit words
*/
nwords = len >> 1;
bits = 48;
for(i=0;i<nwords;i++){
*lpack ^= (*lp & mask16) << bits;
bits -= 16 ;
lp++;
if(bits < 0){
lpack++;
*lpack = 0;
bits = 48;
}
}
Data(dpy, packbuffer, len);
}
Data16 (dpy, data, len)
Display *dpy;
short *data;
unsigned len;
{
char packbuffer[PACKBUFFERSIZE];
unsigned nwords = (PACKBUFFERSIZE >> 1); /* bytes to CARD16 */
for (; len > nwords; len -= nwords, data += nwords) {
doData16 (dpy, data, nwords, packbuffer);
}
doData16 (dpy, data, len, packbuffer);
}
/*
* Data32 - Place 32 bit data in the buffer.
*
* "dpy" is a pointer to a Display.
* "data" is a pointer to the data.
* "len" is the length in bytes of the data.
*/
static doData32 (dpy, data, len, packbuffer)
register Display *dpy;
long *data;
unsigned len;
char *packbuffer;
{
long *lp,*lpack;
long i,bits,nwords;
long mask32 = 0x00000000ffffffff;
lpack = (long *) packbuffer;
lp = data;
*lpack = 0;
/* nwords is the number of 32 bit values to be packed
* the low order 32 bits of each word will be packed
* into 64 bit words
*/
nwords = len >> 2;
bits = 32;
for(i=0;i<nwords;i++){
*lpack ^= (*lp & mask32) << bits;
bits = bits ^32;
lp++;
if(bits){
lpack++;
*lpack = 0;
}
}
Data(dpy, packbuffer, len);
}
Data32 (dpy, data, len)
Display *dpy;
short *data;
unsigned len;
{
char packbuffer[PACKBUFFERSIZE];
unsigned nwords = (PACKBUFFERSIZE >> 2); /* bytes to CARD32 */
for (; len > nwords; len -= nwords, data += nwords) {
doData32 (dpy, data, nwords, packbuffer);
}
doData32 (dpy, data, len, packbuffer);
}
#endif /* WORD64 */
/*
* _XFreeQ - free the queue of events, called by XCloseDisplay when there are
* no more displays left on the display list
*/
void _XFreeQ ()
{
register _XQEvent *qelt = _qfree;
while (qelt) {
register _XQEvent *qnext = qelt->next;
Xfree (qelt);
qelt = qnext;
}
_qfree = NULL;
return;
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.