aboutsummaryrefslogtreecommitdiff
path: root/nx-X11/lib/src/XlibInt.c
diff options
context:
space:
mode:
Diffstat (limited to 'nx-X11/lib/src/XlibInt.c')
-rw-r--r--nx-X11/lib/src/XlibInt.c4199
1 files changed, 4199 insertions, 0 deletions
diff --git a/nx-X11/lib/src/XlibInt.c b/nx-X11/lib/src/XlibInt.c
new file mode 100644
index 000000000..5afc65149
--- /dev/null
+++ b/nx-X11/lib/src/XlibInt.c
@@ -0,0 +1,4199 @@
+/**************************************************************************/
+/* */
+/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */
+/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */
+/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/
+/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */
+/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */
+/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */
+/* */
+/* nx-X11, NX protocol compression and NX extensions to this software */
+/* are copyright of the aforementioned persons and companies. */
+/* */
+/* Redistribution and use of the present software is allowed according */
+/* to terms specified in the file LICENSE which comes in the source */
+/* distribution. */
+/* */
+/* All rights reserved. */
+/* */
+/* NOTE: This software has received contributions from various other */
+/* contributors, only the core maintainers and supporters are listed as */
+/* copyright holders. Please contact us, if you feel you should be listed */
+/* as copyright holder, as well. */
+/* */
+/**************************************************************************/
+
+/*
+
+Copyright 1985, 1986, 1987, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+
+*/
+
+/*
+ * XlibInt.c - Internal support routines for the C subroutine
+ * interface library (Xlib) to the X Window System Protocol V11.0.
+ */
+
+#ifdef WIN32
+#define _XLIBINT_
+#endif
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "Xlibint.h"
+#include "Xprivate.h"
+#include <nx-X11/Xpoll.h>
+#if !USE_XCB
+#include <nx-X11/Xtrans/Xtrans.h>
+#include <nx-X11/extensions/xcmiscstr.h>
+#endif /* !USE_XCB */
+#include <assert.h>
+#include <stdio.h>
+#ifdef WIN32
+#include <direct.h>
+#endif
+
+#ifdef XTHREADS
+#include "locking.h"
+
+/* these pointers get initialized by XInitThreads */
+LockInfoPtr _Xglobal_lock = NULL;
+void (*_XCreateMutex_fn)(LockInfoPtr) = NULL;
+/* struct _XCVList *(*_XCreateCVL_fn)() = NULL; */
+void (*_XFreeMutex_fn)(LockInfoPtr) = NULL;
+void (*_XLockMutex_fn)(
+ LockInfoPtr /* lock */
+#if defined(XTHREADS_WARN) || defined(XTHREADS_FILE_LINE)
+ , char * /* file */
+ , int /* line */
+#endif
+ ) = NULL;
+void (*_XUnlockMutex_fn)(
+ LockInfoPtr /* lock */
+#if defined(XTHREADS_WARN) || defined(XTHREADS_FILE_LINE)
+ , char * /* file */
+ , int /* line */
+#endif
+ ) = NULL;
+xthread_t (*_Xthread_self_fn)(void) = NULL;
+
+#define XThread_Self() ((*_Xthread_self_fn)())
+
+#if !USE_XCB
+#define UnlockNextReplyReader(d) if ((d)->lock) \
+ (*(d)->lock->pop_reader)((d),&(d)->lock->reply_awaiters,&(d)->lock->reply_awaiters_tail)
+
+#define QueueReplyReaderLock(d) ((d)->lock ? \
+ (*(d)->lock->push_reader)(d,&(d)->lock->reply_awaiters_tail) : NULL)
+#define QueueEventReaderLock(d) ((d)->lock ? \
+ (*(d)->lock->push_reader)(d,&(d)->lock->event_awaiters_tail) : NULL)
+#endif /* !USE_XCB */
+
+#else /* XTHREADS else */
+
+#if !USE_XCB
+#define UnlockNextReplyReader(d)
+#define UnlockNextEventReader(d)
+#endif /* !USE_XCB */
+
+#endif /* XTHREADS else */
+
+#ifdef NX_TRANS_SOCKET
+
+#include <nx/NX.h>
+#include <nx/NXvars.h>
+
+static struct timeval retry;
+
+/*
+ * From Xtranssock.c. Presently the congestion state
+ * is reported by the proxy to the application, by
+ * invoking the callback directly. The function will
+ * be possibly used in the future, to be able to track
+ * the bandwidth usage even when the NX transport is
+ * not running. Note that in this sample implementation
+ * the congestion state is checked very often and can
+ * be surely optimized.
+ */
+
+#ifdef NX_TRANS_CHANGE
+extern int _X11TransSocketCongestionChange(XtransConnInfo, int *);
+#endif
+
+#endif /* #ifdef NX_TRANS_SOCKET */
+
+/* check for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX
+ * systems are broken and return EWOULDBLOCK when they should return EAGAIN
+ */
+#ifdef WIN32
+#define ETEST() (WSAGetLastError() == WSAEWOULDBLOCK)
+#else
+#ifdef __CYGWIN__ /* Cygwin uses ENOBUFS to signal socket is full */
+#define ETEST() (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
+#else
+#if defined(EAGAIN) && defined(EWOULDBLOCK)
+#define ETEST() (errno == EAGAIN || errno == EWOULDBLOCK)
+#else
+#ifdef EAGAIN
+#define ETEST() (errno == EAGAIN)
+#else
+#define ETEST() (errno == EWOULDBLOCK)
+#endif /* EAGAIN */
+#endif /* EAGAIN && EWOULDBLOCK */
+#endif /* __CYGWIN__ */
+#endif /* WIN32 */
+
+#ifdef WIN32
+#define ECHECK(err) (WSAGetLastError() == err)
+#define ESET(val) WSASetLastError(val)
+#else
+#define ECHECK(err) (errno == err)
+#define ESET(val) errno = val
+#endif
+
+#if defined(LOCALCONN) || defined(LACHMAN)
+#ifdef EMSGSIZE
+#define ESZTEST() (ECHECK(EMSGSIZE) || ECHECK(ERANGE))
+#else
+#define ESZTEST() ECHECK(ERANGE)
+#endif
+#else
+#ifdef EMSGSIZE
+#define ESZTEST() ECHECK(EMSGSIZE)
+#endif
+#endif
+
+#if !USE_XCB
+
+#define STARTITERATE(tpvar,type,start,endcond) \
+ for (tpvar = (type *) (start); endcond; )
+#define ITERPTR(tpvar) (char *)tpvar
+#define RESETITERPTR(tpvar,type,start) tpvar = (type *) (start)
+#define INCITERPTR(tpvar,type) tpvar++
+#define ENDITERATE
+
+
+typedef union {
+ xReply rep;
+ char buf[BUFSIZE];
+} _XAlignedBuffer;
+
+static char *_XAsyncReply(
+ Display *dpy,
+ register xReply *rep,
+ char *buf,
+ register int *lenp,
+ Bool discard);
+#endif /* !USE_XCB */
+
+/*
+ * 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 *, xError *) 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.
+ */
+
+#if !USE_XCB
+static xReq _dummy_request = {
+ 0, 0, 0
+};
+
+#ifdef NX_TRANS_SOCKET
+
+/*
+ * Replace the standard Select with a version giving NX a
+ * chance to check its own descriptors. This doesn't cover
+ * the cases where the system is using poll or when system-
+ * specific defines override the Select definition (OS/2).
+ */
+
+int _XSelect(int maxfds, fd_set *readfds, fd_set *writefds,
+ fd_set *exceptfds, struct timeval *timeout)
+{
+#ifdef NX_TRANS_TEST
+ fprintf(stderr, "_XSelect: Called with [%d][%p][%p][%p][%p].\n",
+ maxfds, (void *) readfds, (void *) writefds, (void *) exceptfds,
+ (void *) timeout);
+#endif
+
+ if (NXTransRunning(NX_FD_ANY))
+ {
+ fd_set t_readfds, t_writefds;
+ struct timeval t_timeout;
+
+ int n, r, e;
+
+#ifdef NX_TRANS_TEST
+
+ if (exceptfds != NULL)
+ {
+ fprintf(stderr, "_XSelect: WARNING! Can't handle exception fds in select.\n");
+ }
+
+#endif
+
+ if (readfds == NULL)
+ {
+ FD_ZERO(&t_readfds);
+
+ readfds = &t_readfds;
+ }
+
+ if (writefds == NULL)
+ {
+ FD_ZERO(&t_writefds);
+
+ writefds = &t_writefds;
+ }
+
+ if (timeout == NULL)
+ {
+ t_timeout.tv_sec = 10;
+ t_timeout.tv_usec = 0;
+
+ timeout = &t_timeout;
+ }
+
+ n = maxfds;
+
+ /*
+ * If the transport is gone avoid
+ * sleeping until the timeout.
+ */
+
+ if (NXTransPrepare(&n, readfds, writefds, timeout) != 0)
+ {
+ NXTransSelect(&r, &e, &n, readfds, writefds, timeout);
+
+ NXTransExecute(&r, &e, &n, readfds, writefds, timeout);
+
+ errno = e;
+
+ return r;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ else
+ {
+ return select(maxfds, readfds, writefds, exceptfds, timeout);
+ }
+}
+
+#else /* #ifdef NX_TRANS_SOCKET */
+
+int _XSelect(int maxfds, fd_set *readfds, fd_set *writefds,
+ fd_set *exceptfds, struct timeval *timeout)
+{
+ return select(maxfds, readfds, writefds, exceptfds, timeout);
+}
+
+#endif /* #ifdef NX_TRANS_SOCKET */
+
+/*
+ * This is an OS dependent routine which:
+ * 1) returns as soon as the connection can be written on....
+ * 2) if the connection can be read, must enqueue events and handle errors,
+ * until the connection is writable.
+ */
+static void
+_XWaitForWritable(
+ Display *dpy
+#ifdef XTHREADS
+ ,
+ xcondition_t cv /* our reading condition variable */
+#endif
+ )
+{
+#ifdef USE_POLL
+ struct pollfd filedes;
+#else
+ fd_set r_mask;
+ fd_set w_mask;
+#endif
+ int nfound;
+
+#ifdef NX_TRANS_SOCKET
+#if defined(NX_TRANS_CHANGE)
+ int congestion;
+#endif
+ if (_XGetIOError(dpy)) {
+ return;
+ }
+#endif
+
+#ifdef USE_POLL
+ filedes.fd = dpy->fd;
+ filedes.events = 0;
+#else
+ FD_ZERO(&r_mask);
+ FD_ZERO(&w_mask);
+#endif
+
+ for (;;) {
+#ifdef XTHREADS
+ /* We allow only one thread at a time to read, to minimize
+ passing of read data between threads.
+ Now, who is it? If there is a non-NULL reply_awaiters and
+ we (i.e., our cv) are not at the head of it, then whoever
+ is at the head is the reader, and we don't read.
+ Otherwise there is no reply_awaiters or we are at the
+ head, having just appended ourselves.
+ In this case, if there is a event_awaiters, then whoever
+ is at the head of it got there before we did, and they are the
+ reader.
+
+ Last cases: no event_awaiters and we are at the head of
+ reply_awaiters or reply_awaiters is NULL: we are the reader,
+ since there is obviously no one else involved.
+
+ XXX - what if cv is NULL and someone else comes along after
+ us while we are waiting?
+ */
+
+ if (!dpy->lock ||
+ (!dpy->lock->event_awaiters &&
+ (!dpy->lock->reply_awaiters ||
+ dpy->lock->reply_awaiters->cv == cv)))
+#endif
+
+#ifndef NX_TRANS_SOCKET
+#ifdef USE_POLL
+ filedes.events = POLLIN;
+ filedes.events |= POLLOUT;
+#else
+ FD_SET(dpy->fd, &r_mask);
+ FD_SET(dpy->fd, &w_mask);
+#endif
+#endif /* #ifndef NX_TRANS_SOCKET */
+
+ do {
+#ifdef NX_TRANS_SOCKET
+ /*
+ * Give a chance to the registered client to perform
+ * any needed operation before entering the select.
+ */
+
+#ifdef NX_TRANS_TEST
+ fprintf(stderr, "_XWaitForWritable: WAIT! Waiting for the display to become writable.\n");
+#endif
+ NXTransFlush(dpy->fd);
+
+ if (_NXDisplayBlockFunction != NULL) {
+ (*_NXDisplayBlockFunction)(dpy, NXBlockWrite);
+ }
+
+ /*
+ * Need to set again the descriptors as we could have
+ * run multiple selects before having the possibility
+ * to read or write to the X connection.
+ */
+
+#ifdef USE_POLL
+ filedes.events = POLLIN;
+ filedes.events |= POLLOUT;
+#else
+ FD_SET(dpy->fd, &r_mask);
+ FD_SET(dpy->fd, &w_mask);
+#endif
+#endif /* #ifdef NX_TRANS_SOCKET */
+ UnlockDisplay(dpy);
+#ifdef USE_POLL
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG)
+ fprintf(stderr, "_XWaitForWritable: Calling poll().\n");
+#endif
+ nfound = poll (&filedes, 1, -1);
+#else /* USE_POLL */
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG)
+ fprintf(stderr, "_XWaitForWritable: Calling select() after [%ld] ms.\n",
+ NXTransTime());
+#endif /* defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG) */
+#ifdef NX_TRANS_SOCKET
+ /*
+ * Give a chance to the callback to detect
+ * the failure of the display even if we
+ * miss the interrupt inside the select.
+ */
+
+ if (_NXDisplayErrorFunction != NULL) {
+ retry.tv_sec = 5;
+ retry.tv_usec = 0;
+ nfound = Select (dpy->fd + 1, &r_mask, &w_mask, NULL, &retry);
+ } else {
+ nfound = Select (dpy->fd + 1, &r_mask, &w_mask, NULL, NULL);
+ }
+#else /* NX_TRANS_SOCKET */
+ nfound = Select (dpy->fd + 1, &r_mask, &w_mask, NULL, NULL);
+#endif /* NX_TRANS_SOCKET */
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG)
+ fprintf(stderr, "_XWaitForWritable: Out of select() with [%d] after [%ld] ms.\n",
+ nfound, NXTransTime());
+
+ if (FD_ISSET(dpy->fd, &r_mask))
+ {
+ BytesReadable_t pend;
+
+ _X11TransBytesReadable(dpy->trans_conn, &pend);
+
+ fprintf(stderr, "_XWaitForWritable: Descriptor [%d] is ready with [%ld] bytes to read.\n",
+ dpy->fd, pend);
+ }
+
+ if (FD_ISSET(dpy->fd, &w_mask))
+ {
+ fprintf(stderr, "_XWaitForWritable: Descriptor [%d] has become writable.\n\n",
+ dpy->fd);
+ }
+#endif /* defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG) */
+#endif /* USE_POLL */
+ InternalLockDisplay(dpy, cv != NULL);
+#ifdef NX_TRANS_SOCKET
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_CHANGE)
+ if (_NXDisplayCongestionFunction != NULL &&
+ _X11TransSocketCongestionChange(dpy->trans_conn, &congestion) == 1) {
+ (*_NXDisplayCongestionFunction)(dpy, congestion);
+ }
+#endif /* defined(NX_TRANS_SOCKET) && defined(NX_TRANS_CHANGE) */
+ if (nfound <= 0) {
+ if ((nfound == -1 && !(ECHECK(EINTR) || ETEST())) ||
+ (_NXDisplayErrorFunction != NULL &&
+ (*_NXDisplayErrorFunction)(dpy, _XGetIOError(dpy)))) {
+ _XIOError(dpy);
+ return;
+ }
+ }
+#else /* NX_TRANS_SOCKET */
+ if (nfound < 0 && !(ECHECK(EINTR) || ETEST()))
+ _XIOError(dpy);
+#endif /* NX_TRANS_SOCKET */
+ } while (nfound <= 0);
+
+ if (
+#ifdef USE_POLL
+ filedes.revents & POLLIN
+#else /* USE_POLL */
+ FD_ISSET(dpy->fd, &r_mask)
+#endif /* USE_POLL */
+ )
+ {
+ _XAlignedBuffer buf;
+ BytesReadable_t pend;
+ register int len;
+ register xReply *rep;
+
+ /* find out how much data can be read */
+ if (_X11TransBytesReadable(dpy->trans_conn, &pend) < 0)
+#ifdef NX_TRANS_SOCKET
+ {
+ _XIOError(dpy);
+
+ return;
+ }
+#else /* NX_TRANS_SOCKET */
+ _XIOError(dpy);
+#endif /* NX_TRANS_SOCKET */
+ len = pend;
+
+ /* must read at least one xEvent; if none is pending, then
+ we'll just block waiting for it */
+ if (len < SIZEOF(xReply)
+#ifdef XTHREADS
+ || dpy->async_handlers
+#endif
+ )
+ len = SIZEOF(xReply);
+
+ /* but we won't read more than the max buffer size */
+ if (len > BUFSIZE) len = BUFSIZE;
+
+ /* round down to an integral number of XReps */
+ len = (len / SIZEOF(xReply)) * SIZEOF(xReply);
+
+ (void) _XRead (dpy, buf.buf, (long) len);
+
+ STARTITERATE(rep,xReply,buf.buf,len > 0) {
+ if (rep->generic.type == X_Reply) {
+ int tmp = len;
+ RESETITERPTR(rep,xReply,
+ _XAsyncReply (dpy, rep,
+ ITERPTR(rep), &tmp, True));
+ len = tmp;
+ pend = len;
+ } else {
+ if (rep->generic.type == X_Error)
+ _XError (dpy, (xError *)rep);
+ else /* must be an event packet */
+ _XEnq (dpy, (xEvent *)rep);
+ INCITERPTR(rep,xReply);
+ len -= SIZEOF(xReply);
+ }
+ } ENDITERATE
+#ifdef XTHREADS
+ if (dpy->lock && dpy->lock->event_awaiters)
+ ConditionSignal(dpy, dpy->lock->event_awaiters->cv);
+#endif
+ }
+#ifdef USE_POLL
+ if (filedes.revents & (POLLOUT|POLLHUP|POLLERR))
+#else
+ if (FD_ISSET(dpy->fd, &w_mask))
+#endif
+ {
+#ifdef XTHREADS
+ if (dpy->lock) {
+ ConditionBroadcast(dpy, dpy->lock->writers);
+ }
+#endif
+ return;
+ }
+ }
+}
+#endif /* !USE_XCB */
+
+
+#define POLLFD_CACHE_SIZE 5
+
+/* initialize the struct array passed to poll() below */
+Bool _XPollfdCacheInit(
+ Display *dpy)
+{
+#ifdef USE_POLL
+ struct pollfd *pfp;
+
+ pfp = Xmalloc(POLLFD_CACHE_SIZE * sizeof(struct pollfd));
+ if (!pfp)
+ return False;
+ pfp[0].fd = dpy->fd;
+ pfp[0].events = POLLIN;
+
+ dpy->filedes = (XPointer)pfp;
+#endif
+ return True;
+}
+
+void _XPollfdCacheAdd(
+ Display *dpy,
+ int fd)
+{
+#ifdef USE_POLL
+ struct pollfd *pfp = (struct pollfd *)dpy->filedes;
+
+ if (dpy->im_fd_length <= POLLFD_CACHE_SIZE) {
+ pfp[dpy->im_fd_length].fd = fd;
+ pfp[dpy->im_fd_length].events = POLLIN;
+ }
+#endif
+}
+
+/* ARGSUSED */
+void _XPollfdCacheDel(
+ Display *dpy,
+ int fd) /* not used */
+{
+#ifdef USE_POLL
+ struct pollfd *pfp = (struct pollfd *)dpy->filedes;
+ struct _XConnectionInfo *conni;
+
+ /* just recalculate whole list */
+ if (dpy->im_fd_length <= POLLFD_CACHE_SIZE) {
+ int loc = 1;
+ for (conni = dpy->im_fd_info; conni; conni=conni->next) {
+ pfp[loc].fd = conni->fd;
+ pfp[loc].events = POLLIN;
+ loc++;
+ }
+ }
+#endif
+}
+
+#if !USE_XCB
+/* returns True iff there is an event in the queue newer than serial_num */
+
+static Bool
+_XNewerQueuedEvent(
+ Display *dpy,
+ int serial_num)
+{
+ _XQEvent *qev;
+
+ if (dpy->next_event_serial_num == serial_num)
+ return False;
+
+ qev = dpy->head;
+ while (qev) {
+ if (qev->qserial_num >= serial_num) {
+ return True;
+ }
+ qev = qev->next;
+ }
+ return False;
+}
+
+static int
+_XWaitForReadable(
+ Display *dpy)
+{
+ int result;
+ int fd = dpy->fd;
+ struct _XConnectionInfo *ilist;
+ register int saved_event_serial = 0;
+ int in_read_events = 0;
+ register Bool did_proc_conni = False;
+#ifdef USE_POLL
+ struct pollfd *filedes;
+#else
+ fd_set r_mask;
+ int highest_fd = fd;
+#endif
+
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_CHANGE)
+ int congestion;
+#endif
+#ifdef NX_TRANS_SOCKET
+ if (_XGetIOError(dpy)) {
+ return -1;
+ }
+#endif
+
+#ifdef USE_POLL
+ if (dpy->im_fd_length + 1 > POLLFD_CACHE_SIZE
+ && !(dpy->flags & XlibDisplayProcConni)) {
+ /* XXX - this fallback is gross */
+ int i;
+
+ filedes = (struct pollfd *)Xmalloc(dpy->im_fd_length * sizeof(struct pollfd));
+ filedes[0].fd = fd;
+ filedes[0].events = POLLIN;
+ for (ilist=dpy->im_fd_info, i=1; ilist; ilist=ilist->next, i++) {
+ filedes[i].fd = ilist->fd;
+ filedes[i].events = POLLIN;
+ }
+ } else {
+ filedes = (struct pollfd *)dpy->filedes;
+ }
+#else /* USE_POLL */
+ FD_ZERO(&r_mask);
+#endif /* USE_POLL */
+ for (;;) {
+#ifndef USE_POLL
+ FD_SET(fd, &r_mask);
+ if (!(dpy->flags & XlibDisplayProcConni))
+ for (ilist=dpy->im_fd_info; ilist; ilist=ilist->next) {
+ FD_SET(ilist->fd, &r_mask);
+ if (ilist->fd > highest_fd)
+ highest_fd = ilist->fd;
+ }
+#endif /* USE_POLL */
+ UnlockDisplay(dpy);
+#ifdef USE_POLL
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG)
+ fprintf(stderr, "_XWaitForReadable: Calling poll().\n");
+#endif
+ result = poll(filedes,
+ (dpy->flags & XlibDisplayProcConni) ? 1 : 1+dpy->im_fd_length,
+ -1);
+#else /* USE_POLL */
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG)
+ fprintf(stderr, "_XWaitForReadable: Calling select().\n");
+#endif
+#ifdef NX_TRANS_SOCKET
+ /*
+ * Give a chance to the registered application
+ * to perform any needed operation.
+ */
+
+#ifdef NX_TRANS_TEST
+ fprintf(stderr, "_XWaitForReadable: WAIT! Waiting for the display to become readable.\n");
+#endif
+ NXTransFlush(dpy->fd);
+
+ if (_NXDisplayBlockFunction != NULL) {
+ (*_NXDisplayBlockFunction)(dpy, NXBlockRead);
+ }
+
+ if (_NXDisplayErrorFunction != NULL) {
+ retry.tv_sec = 5;
+ retry.tv_usec = 0;
+ result = Select(highest_fd + 1, &r_mask, NULL, NULL, &retry);
+ } else {
+ result = Select(highest_fd + 1, &r_mask, NULL, NULL, NULL);
+ }
+#else /* NX_TRANS_SOCKET */
+ result = Select(highest_fd + 1, &r_mask, NULL, NULL, NULL);
+#endif /* NX_TRANS_SOCKET */
+#endif /* USE_POLL */
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG)
+ fprintf(stderr, "_XWaitForReadable: Out of select with result [%d] and errno [%d].\n",
+ result, (result < 0 ? errno : 0));
+#endif
+ InternalLockDisplay(dpy, dpy->flags & XlibDisplayReply);
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_CHANGE)
+ if (_NXDisplayCongestionFunction != NULL &&
+ _X11TransSocketCongestionChange(dpy->trans_conn, &congestion) == 1) {
+ (*_NXDisplayCongestionFunction)(dpy, congestion);
+ }
+#endif
+#ifdef NX_TRANS_SOCKET
+ if (result <= 0) {
+ if ((result == -1 && !(ECHECK(EINTR) || ETEST())) ||
+ (_NXDisplayErrorFunction != NULL &&
+ (*_NXDisplayErrorFunction)(dpy, _XGetIOError(dpy)))) {
+ _XIOError(dpy);
+ return -1;
+ }
+ continue;
+ }
+#else
+ if (result == -1 && !(ECHECK(EINTR) || ETEST())) _XIOError(dpy);
+ if (result <= 0)
+ continue;
+#endif
+#ifdef USE_POLL
+ if (filedes[0].revents & (POLLIN|POLLHUP|POLLERR))
+#else
+ if (FD_ISSET(fd, &r_mask))
+#endif
+ break;
+ if (!(dpy->flags & XlibDisplayProcConni)) {
+ int i;
+
+ saved_event_serial = dpy->next_event_serial_num;
+ /* dpy flags can be clobbered by internal connection callback */
+ in_read_events = dpy->flags & XlibDisplayReadEvents;
+ for (ilist=dpy->im_fd_info, i=1; ilist; ilist=ilist->next, i++) {
+#ifdef USE_POLL
+ if (filedes[i].revents & POLLIN)
+#else
+ if (FD_ISSET(ilist->fd, &r_mask))
+#endif
+ {
+ _XProcessInternalConnection(dpy, ilist);
+ did_proc_conni = True;
+ }
+ }
+#ifdef USE_POLL
+ if (dpy->im_fd_length + 1 > POLLFD_CACHE_SIZE)
+ Xfree(filedes);
+#endif
+ }
+ if (did_proc_conni) {
+ /* some internal connection callback might have done an
+ XPutBackEvent. We notice it here and if we needed an event,
+ we can return all the way. */
+ if (_XNewerQueuedEvent(dpy, saved_event_serial)
+ && (in_read_events
+#ifdef XTHREADS
+ || (dpy->lock && dpy->lock->event_awaiters)
+#endif
+ ))
+ return -2;
+ did_proc_conni = False;
+ }
+ }
+#ifdef XTHREADS
+#ifdef XTHREADS_DEBUG
+ printf("thread %x _XWaitForReadable returning\n", XThread_Self());
+#endif
+#endif
+ return 0;
+}
+#endif /* !USE_XCB */
+
+static int sync_hazard(Display *dpy)
+{
+ unsigned long span = dpy->request - dpy->last_request_read;
+ unsigned long hazard = min((dpy->bufmax - dpy->buffer) / SIZEOF(xReq), 65535 - 10);
+ return span >= 65535 - hazard - 10;
+}
+
+static
+void sync_while_locked(Display *dpy)
+{
+#ifdef XTHREADS
+ if (dpy->lock)
+ (*dpy->lock->user_lock_display)(dpy);
+#endif
+ UnlockDisplay(dpy);
+ SyncHandle();
+ InternalLockDisplay(dpy, /* don't skip user locks */ 0);
+#ifdef XTHREADS
+ if (dpy->lock)
+ (*dpy->lock->user_unlock_display)(dpy);
+#endif
+}
+
+void _XSeqSyncFunction(
+ register Display *dpy)
+{
+ xGetInputFocusReply rep;
+ _X_UNUSED register xReq *req;
+
+#ifdef NX_TRANS_SOCKET
+#ifdef NX_TRANS_DEBUG
+ fprintf(stderr, "_XSeqSyncFunction: Going to synchronize the display.\n");
+#endif
+
+ if (dpy->flags & XlibDisplayIOError)
+ {
+#ifdef NX_TRANS_DEBUG
+ fprintf(stderr, "_XSeqSyncFunction: Returning 0 with I/O error detected.\n");
+#endif
+ return;
+ }
+#endif /* NX_TRANS_SOCKET */
+ if ((dpy->request - dpy->last_request_read) >= (65535 - BUFSIZE/SIZEOF(xReq))) {
+ GetEmptyReq(GetInputFocus, req);
+ (void) _XReply (dpy, (xReply *)&rep, 0, xTrue);
+ sync_while_locked(dpy);
+ } else if (sync_hazard(dpy))
+ _XSetPrivSyncFunction(dpy);
+}
+
+/* NOTE: only called if !XTHREADS, or when XInitThreads wasn't called. */
+static int
+_XPrivSyncFunction (Display *dpy)
+{
+#ifdef XTHREADS
+ assert(!dpy->lock_fns);
+#endif
+ assert(dpy->synchandler == _XPrivSyncFunction);
+ assert((dpy->flags & XlibDisplayPrivSync) != 0);
+ dpy->synchandler = dpy->savedsynchandler;
+ dpy->savedsynchandler = NULL;
+ dpy->flags &= ~XlibDisplayPrivSync;
+ if(dpy->synchandler)
+ dpy->synchandler(dpy);
+ _XIDHandler(dpy);
+ _XSeqSyncFunction(dpy);
+ return 0;
+}
+
+void _XSetPrivSyncFunction(Display *dpy)
+{
+#ifdef XTHREADS
+ if (dpy->lock_fns)
+ return;
+#endif
+ if (!(dpy->flags & XlibDisplayPrivSync)) {
+ dpy->savedsynchandler = dpy->synchandler;
+ dpy->synchandler = _XPrivSyncFunction;
+ dpy->flags |= XlibDisplayPrivSync;
+ }
+}
+
+void _XSetSeqSyncFunction(Display *dpy)
+{
+ if (sync_hazard(dpy))
+ _XSetPrivSyncFunction (dpy);
+}
+
+#if !USE_XCB
+#ifdef XTHREADS
+static void _XFlushInt(
+ register Display *dpy,
+ register xcondition_t cv);
+#endif
+
+/*
+ * _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.
+ */
+void _XFlush(
+ register Display *dpy)
+{
+#ifdef XTHREADS
+ /* With multi-threading we introduce an internal routine to which
+ we can pass a condition variable to do locking correctly. */
+
+ _XFlushInt(dpy, NULL);
+}
+
+/* _XFlushInt - Internal version of _XFlush used to do multi-threaded
+ * locking correctly.
+ */
+
+static void _XFlushInt(
+ register Display *dpy,
+ register xcondition_t cv)
+{
+#endif /* XTHREADS*/
+ register long size, todo;
+ register int write_stat;
+ register char *bufindex;
+ _XExtension *ext;
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_CHANGE)
+ int congestion;
+#endif
+
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG)
+ fprintf(stderr, "_XFlushInt: Entering flush with [%d] bytes to write.\n",
+ (dpy->bufptr - dpy->buffer));
+#endif
+ /* This fix resets the bufptr to the front of the buffer so
+ * additional appends to the bufptr will not corrupt memory. Since
+ * the server is down, these appends are no-op's anyway but
+ * callers of _XFlush() are not verifying this before they call it.
+ */
+ if (dpy->flags & XlibDisplayIOError)
+ {
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG)
+ fprintf(stderr, "_XFlushInt: Returning with I/O error detected.\n");
+#endif
+ dpy->bufptr = dpy->buffer;
+ dpy->last_req = (char *)&_dummy_request;
+ return;
+ }
+
+#ifdef XTHREADS
+#ifdef NX_TRANS_SOCKET
+ while (dpy->flags & XlibDisplayWriting) {
+ if (_XGetIOError(dpy)) {
+ return;
+ }
+#else
+ while (dpy->flags & XlibDisplayWriting) {
+#endif
+ if (dpy->lock) {
+ ConditionWait(dpy, dpy->lock->writers);
+ } else {
+ _XWaitForWritable (dpy, cv);
+ }
+ }
+#endif
+ size = todo = dpy->bufptr - dpy->buffer;
+ if (!size) return;
+#ifdef XTHREADS
+ dpy->flags |= XlibDisplayWriting;
+ /* make sure no one else can put in data */
+ dpy->bufptr = dpy->bufmax;
+#endif
+ for (ext = dpy->flushes; ext; ext = ext->next_flush)
+ (*ext->before_flush)(dpy, &ext->codes, dpy->buffer, size);
+ bufindex = 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) {
+ ESET(0);
+ write_stat = _X11TransWrite(dpy->trans_conn,
+ bufindex, (int) todo);
+ if (write_stat >= 0) {
+#ifdef NX_TRANS_SOCKET
+ if (_NXDisplayWriteFunction != NULL) {
+ (*_NXDisplayWriteFunction)(dpy, write_stat);
+ }
+#ifdef NX_TRANS_CHANGE
+ if (_NXDisplayCongestionFunction != NULL &&
+ _X11TransSocketCongestionChange(dpy->trans_conn, &congestion) == 1) {
+ (*_NXDisplayCongestionFunction)(dpy, congestion);
+ }
+#endif
+#endif
+ size -= write_stat;
+ todo = size;
+ bufindex += write_stat;
+ } else if (ETEST()) {
+ _XWaitForWritable(dpy
+#ifdef XTHREADS
+ , cv
+#endif
+ );
+#ifdef SUNSYSV
+ } else if (ECHECK(0)) {
+ _XWaitForWritable(dpy
+#ifdef XTHREADS
+ , cv
+#endif
+ );
+#endif
+#ifdef ESZTEST
+ } else if (ESZTEST()) {
+ if (todo > 1)
+ todo >>= 1;
+ else {
+ _XWaitForWritable(dpy
+#ifdef XTHREADS
+ , cv
+#endif
+ );
+ }
+#endif
+#ifdef NX_TRANS_SOCKET
+ } else if (!ECHECK(EINTR) ||
+ (_NXDisplayErrorFunction != NULL &&
+ (*_NXDisplayErrorFunction)(dpy, _XGetIOError(dpy)))) {
+ _XIOError(dpy);
+ return;
+ }
+#else
+ } else if (!ECHECK(EINTR)) {
+ /* Write failed! */
+ /* errno set by write system call. */
+ _XIOError(dpy);
+ }
+#endif
+#ifdef NX_TRANS_SOCKET
+ if (_XGetIOError(dpy)) {
+ return;
+ }
+#endif
+ }
+ dpy->last_req = (char *)&_dummy_request;
+ _XSetSeqSyncFunction(dpy);
+ dpy->bufptr = dpy->buffer;
+#ifdef XTHREADS
+ dpy->flags &= ~XlibDisplayWriting;
+#endif
+}
+
+int
+_XEventsQueued(
+ register Display *dpy,
+ int mode)
+{
+ register int len;
+ BytesReadable_t pend;
+ _XAlignedBuffer buf;
+ register xReply *rep;
+ char *read_buf;
+#ifdef XTHREADS
+ int entry_event_serial_num;
+ struct _XCVList *cvl = NULL;
+ xthread_t self;
+
+#ifdef XTHREADS_DEBUG
+ printf("_XEventsQueued called in thread %x\n", XThread_Self());
+#endif
+#endif /* XTHREADS*/
+
+ if (mode == QueuedAfterFlush)
+ {
+ _XFlush(dpy);
+ if (dpy->qlen)
+ return(dpy->qlen);
+ }
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG)
+ if (dpy->flags & XlibDisplayIOError) {
+ fprintf(stderr, "_XEventsQueued: Returning [%d] after display failure.\n",
+ dpy->qlen);
+ }
+#endif
+ if (dpy->flags & XlibDisplayIOError) return(dpy->qlen);
+
+#ifdef XTHREADS
+ /* create our condition variable and append to list,
+ * unless we were called from within XProcessInternalConnection
+ * or XLockDisplay
+ */
+ xthread_clear_id(self);
+ if (dpy->lock && (xthread_have_id (dpy->lock->conni_thread)
+ || xthread_have_id (dpy->lock->locking_thread)))
+ /* some thread is in XProcessInternalConnection or XLockDisplay
+ so we have to see if we are it */
+ self = XThread_Self();
+ if (!xthread_have_id(self)
+ || (!xthread_equal(self, dpy->lock->conni_thread)
+ && !xthread_equal(self, dpy->lock->locking_thread))) {
+ /* In the multi-threaded case, if there is someone else
+ reading events, then there aren't any available, so
+ we just return. If we waited we would block.
+ */
+ if (dpy->lock && dpy->lock->event_awaiters)
+ return dpy->qlen;
+ /* nobody here but us, so lock out any newcomers */
+ cvl = QueueEventReaderLock(dpy);
+ }
+
+ while (dpy->lock && cvl && dpy->lock->reply_first) {
+ /* note which events we have already seen so we'll know
+ if _XReply (in another thread) reads one */
+ entry_event_serial_num = dpy->next_event_serial_num;
+ ConditionWait(dpy, cvl->cv);
+ /* did _XReply read an event we can return? */
+ if (_XNewerQueuedEvent(dpy, entry_event_serial_num))
+ {
+ UnlockNextEventReader(dpy);
+ return 0;
+ }
+ }
+#endif /* XTHREADS*/
+
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG)
+ fprintf(stderr, "_XEventsQueued: Checking bytes readable.\n");
+#endif
+ if (_X11TransBytesReadable(dpy->trans_conn, &pend) < 0)
+#ifdef NX_TRANS_SOCKET
+ {
+ _XIOError(dpy);
+
+ return (dpy->qlen);
+ }
+#else
+ _XIOError(dpy);
+#endif
+#ifdef XCONN_CHECK_FREQ
+ /* This is a crock, required because FIONREAD or equivalent is
+ * not guaranteed to detect a broken connection.
+ */
+ if (!pend && !dpy->qlen && ++dpy->conn_checker >= XCONN_CHECK_FREQ)
+ {
+ int result;
+#ifdef USE_POLL
+ struct pollfd filedes;
+#else
+ fd_set r_mask;
+ static struct timeval zero_time;
+#endif
+
+ dpy->conn_checker = 0;
+#ifdef USE_POLL
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG)
+ fprintf(stderr, "_XEventsQueued: Calling poll().\n");
+#endif
+ filedes.fd = dpy->fd;
+ filedes.events = POLLIN;
+ if ((result = poll(&filedes, 1, 0)))
+#else
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG)
+ fprintf(stderr, "_XEventsQueued: Calling select().\n");
+#endif
+ FD_ZERO(&r_mask);
+ FD_SET(dpy->fd, &r_mask);
+ if ((result = Select(dpy->fd + 1, &r_mask, NULL, NULL, &zero_time)))
+#endif
+ {
+ if (result > 0)
+ {
+ if (_X11TransBytesReadable(dpy->trans_conn, &pend) < 0)
+#ifdef NX_TRANS_SOCKET
+ {
+ _XIOError(dpy);
+
+ return (dpy->qlen);
+ }
+#else
+ _XIOError(dpy);
+#endif
+ /* we should not get zero, if we do, force a read */
+ if (!pend)
+ pend = SIZEOF(xReply);
+ }
+#ifdef NX_TRANS_SOCKET
+ if (result <= 0) {
+ if ((result == -1 && !(ECHECK(EINTR) || ETEST())) ||
+ (_NXDisplayErrorFunction != NULL &&
+ (*_NXDisplayErrorFunction)(dpy, _XGetIOError(dpy)))) {
+ _XIOError(dpy);
+ return (dpy->qlen);
+ }
+ }
+#else
+ else if (result < 0 && !(ECHECK(EINTR) || ETEST()))
+#endif
+ _XIOError(dpy);
+ }
+ }
+#endif /* XCONN_CHECK_FREQ */
+ if (!(len = pend)) {
+ /* _XFlush can enqueue events */
+#ifdef XTHREADS
+ if (cvl)
+#endif
+ {
+ UnlockNextEventReader(dpy);
+ }
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG)
+ fprintf(stderr, "_XEventsQueued: Returning [%d].\n", dpy->qlen);
+#endif
+ return(dpy->qlen);
+ }
+ /* Force a read if there is not enough data. Otherwise,
+ * a select() loop at a higher-level will spin undesirably,
+ * and we've seen at least one OS that appears to not update
+ * the result from FIONREAD once it has returned nonzero.
+ */
+#ifdef XTHREADS
+ if (dpy->lock && dpy->lock->reply_awaiters) {
+ read_buf = (char *)dpy->lock->reply_awaiters->buf;
+ len = SIZEOF(xReply);
+ } else
+#endif /* XTHREADS*/
+ {
+ read_buf = buf.buf;
+
+ if (len < SIZEOF(xReply)
+#ifdef XTHREADS
+ || dpy->async_handlers
+#endif
+ )
+ len = SIZEOF(xReply);
+ else if (len > BUFSIZE)
+ len = BUFSIZE;
+ len = (len / SIZEOF(xReply)) * SIZEOF(xReply);
+ }
+#ifdef XCONN_CHECK_FREQ
+ dpy->conn_checker = 0;
+#endif
+
+ (void) _XRead (dpy, read_buf, (long) len);
+
+#ifdef NX_TRANS_SOCKET
+ if (_XGetIOError(dpy)) {
+ return(dpy->qlen);
+ }
+#endif
+#ifdef XTHREADS
+ /* what did we actually read: reply or event? */
+ if (dpy->lock && dpy->lock->reply_awaiters) {
+ if (((xReply *)read_buf)->generic.type == X_Reply ||
+ ((xReply *)read_buf)->generic.type == X_Error)
+ {
+ dpy->lock->reply_was_read = True;
+ dpy->lock->reply_first = True;
+ if (read_buf != (char *)dpy->lock->reply_awaiters->buf)
+ memcpy(dpy->lock->reply_awaiters->buf, read_buf,
+ len);
+ if (cvl) {
+ UnlockNextEventReader(dpy);
+ }
+ return(dpy->qlen); /* we read, so we can return */
+ } else if (read_buf != buf.buf)
+ memcpy(buf.buf, read_buf, len);
+ }
+#endif /* XTHREADS*/
+
+ STARTITERATE(rep,xReply,buf.buf,len > 0) {
+ if (rep->generic.type == X_Reply) {
+ int tmp = len;
+ RESETITERPTR(rep,xReply,
+ _XAsyncReply (dpy, rep,
+ ITERPTR(rep), &tmp, True));
+ len = tmp;
+ pend = len;
+ } else {
+ if (rep->generic.type == X_Error)
+ _XError (dpy, (xError *)rep);
+ else /* must be an event packet */
+ _XEnq (dpy, (xEvent *)rep);
+ INCITERPTR(rep,xReply);
+ len -= SIZEOF(xReply);
+ }
+ } ENDITERATE
+
+#ifdef XTHREADS
+ if (cvl)
+#endif
+ {
+ UnlockNextEventReader(dpy);
+ }
+ return(dpy->qlen);
+}
+
+/* _XReadEvents - Flush the output queue,
+ * then read as many events as possible (but at least 1) and enqueue them
+ */
+void _XReadEvents(
+ register Display *dpy)
+{
+ _XAlignedBuffer buf;
+ BytesReadable_t pend;
+ int len;
+ register xReply *rep;
+ Bool not_yet_flushed = True;
+ char *read_buf;
+ int i;
+ int entry_event_serial_num = dpy->next_event_serial_num;
+#ifdef XTHREADS
+ struct _XCVList *cvl = NULL;
+ xthread_t self;
+
+#ifdef XTHREADS_DEBUG
+ printf("_XReadEvents called in thread %x\n",
+ XThread_Self());
+#endif
+ /* create our condition variable and append to list,
+ * unless we were called from within XProcessInternalConnection
+ * or XLockDisplay
+ */
+ xthread_clear_id(self);
+ if (dpy->lock && (xthread_have_id (dpy->lock->conni_thread)
+ || xthread_have_id (dpy->lock->locking_thread)))
+ /* some thread is in XProcessInternalConnection or XLockDisplay
+ so we have to see if we are it */
+ self = XThread_Self();
+ if (!xthread_have_id(self)
+ || (!xthread_equal(self, dpy->lock->conni_thread)
+ && !xthread_equal(self, dpy->lock->locking_thread)))
+ cvl = QueueEventReaderLock(dpy);
+#endif /* XTHREADS */
+
+ do {
+#ifdef XTHREADS
+ /* if it is not our turn to read an event off the wire,
+ wait til we're at head of list */
+ if (dpy->lock && cvl &&
+ (dpy->lock->event_awaiters != cvl ||
+ dpy->lock->reply_first)) {
+ ConditionWait(dpy, cvl->cv);
+ continue;
+ }
+#endif /* XTHREADS */
+ /* find out how much data can be read */
+ if (_X11TransBytesReadable(dpy->trans_conn, &pend) < 0)
+ {
+ _XIOError(dpy);
+#ifdef NX_TRANS_SOCKET
+ return;
+#endif
+ }
+ len = pend;
+
+ /* must read at least one xEvent; if none is pending, then
+ we'll just flush and block waiting for it */
+ if (len < SIZEOF(xEvent)
+#ifdef XTHREADS
+ || dpy->async_handlers
+#endif
+ ) {
+ len = SIZEOF(xEvent);
+ /* don't flush until the first time we would block */
+ if (not_yet_flushed) {
+ _XFlush (dpy);
+ if (_XNewerQueuedEvent(dpy, entry_event_serial_num)) {
+ /* _XReply has read an event for us */
+ goto got_event;
+ }
+ not_yet_flushed = False;
+ }
+ }
+
+#ifdef XTHREADS
+ /* If someone is waiting for a reply, gamble that
+ the reply will be the next thing on the wire
+ and read it into their buffer. */
+ if (dpy->lock && dpy->lock->reply_awaiters) {
+ read_buf = (char *)dpy->lock->reply_awaiters->buf;
+ len = SIZEOF(xReply);
+ } else
+#endif /* XTHREADS*/
+ {
+ read_buf = buf.buf;
+
+ /* but we won't read more than the max buffer size */
+ if (len > BUFSIZE)
+ len = BUFSIZE;
+
+ /* round down to an integral number of XReps */
+ len = (len / SIZEOF(xEvent)) * SIZEOF(xEvent);
+ }
+
+#ifdef XTHREADS
+ if (xthread_have_id(self))
+ /* save value we may have to stick in conni_thread */
+ dpy->lock->reading_thread = self;
+#endif /* XTHREADS */
+ dpy->flags |= XlibDisplayReadEvents;
+ i = _XRead (dpy, read_buf, (long) len);
+ dpy->flags &= ~XlibDisplayReadEvents;
+#ifdef NX_TRANS_SOCKET
+ if (dpy->flags & XlibDisplayIOError)
+ {
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG)
+ fprintf(stderr, "_XReadEvents: Returning with I/O error detected.\n");
+#endif
+ return;
+ }
+#endif
+ if (i == -2) {
+ /* special flag from _XRead to say that internal connection has
+ done XPutBackEvent. Which we can use so we're done. */
+ got_event:
+#ifdef XTHREADS
+ if (dpy->lock && dpy->lock->lock_wait) {
+ if (dpy->lock->event_awaiters != cvl)
+ /* since it is not us, must be user lock thread */
+ ConditionSignal(dpy,
+ dpy->lock->event_awaiters->cv);
+ (*dpy->lock->lock_wait)(dpy);
+ continue;
+ }
+#endif
+ break;
+ }
+#ifdef XTHREADS
+ if (xthread_have_id(self))
+ xthread_clear_id(dpy->lock->reading_thread);
+
+ /* what did we actually read: reply or event? */
+ if (dpy->lock && dpy->lock->reply_awaiters) {
+ if (((xReply *)read_buf)->generic.type == X_Reply ||
+ ((xReply *)read_buf)->generic.type == X_Error)
+ {
+ dpy->lock->reply_was_read = True;
+ dpy->lock->reply_first = True;
+ if (read_buf != (char *)dpy->lock->reply_awaiters->buf)
+ memcpy(dpy->lock->reply_awaiters->buf,
+ read_buf, len);
+ ConditionSignal(dpy, dpy->lock->reply_awaiters->cv);
+ continue;
+ } else if (read_buf != buf.buf)
+ memcpy(buf.buf, read_buf, len);
+ }
+#endif /* XTHREADS */
+
+ STARTITERATE(rep,xReply,buf.buf,len > 0) {
+ if (rep->generic.type == X_Reply) {
+ RESETITERPTR(rep,xReply,
+ _XAsyncReply (dpy, rep,
+ ITERPTR(rep), &len, True));
+ pend = len;
+ } else {
+ if (rep->generic.type == X_Error)
+ _XError (dpy, (xError *) rep);
+ else /* must be an event packet */
+ {
+ if (rep->generic.type == GenericEvent)
+ {
+ int evlen;
+ evlen = (rep->generic.length << 2);
+ if (_XRead(dpy, &read_buf[len], evlen) == -2)
+ goto got_event; /* XXX: aargh! */
+ }
+
+ _XEnq (dpy, (xEvent *)rep);
+ }
+ INCITERPTR(rep,xReply);
+ len -= SIZEOF(xReply);
+ }
+ } ENDITERATE;
+ } while (!_XNewerQueuedEvent(dpy, entry_event_serial_num));
+
+ UnlockNextEventReader(dpy);
+}
+
+/*
+ * _XRead - Read bytes from the socket taking into account incomplete
+ * reads. This routine may have to be reworked if int < long.
+ */
+int _XRead(
+ register Display *dpy,
+ register char *data,
+ register long size)
+{
+ register long bytes_read;
+#ifdef XTHREADS
+ int original_size = size;
+#endif
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_CHANGE)
+ int congestion;
+#endif
+
+ if ((dpy->flags & XlibDisplayIOError) || size == 0)
+ return 0;
+ ESET(0);
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_CHANGE)
+ while (1) {
+ /*
+ * Need to check the congestion state
+ * after the read so split the statement
+ * in multiple blocks.
+ */
+
+ bytes_read = _X11TransRead(dpy->trans_conn, data, (int)size);
+ if (_NXDisplayCongestionFunction != NULL &&
+ _X11TransSocketCongestionChange(dpy->trans_conn, &congestion) == 1) {
+ (*_NXDisplayCongestionFunction)(dpy, congestion);
+ }
+ if (bytes_read == size) {
+ break;
+ }
+#else
+ while ((bytes_read = _X11TransRead(dpy->trans_conn, data, (int)size))
+ != size) {
+#endif
+
+ if (bytes_read > 0) {
+ size -= bytes_read;
+ data += bytes_read;
+ }
+ else if (ETEST()) {
+ if (_XWaitForReadable(dpy) == -2)
+ return -2; /* internal connection did XPutBackEvent */
+ ESET(0);
+ }
+#ifdef SUNSYSV
+ else if (ECHECK(0)) {
+ if (_XWaitForReadable(dpy) == -2)
+ return -2; /* internal connection did XPutBackEvent */
+ }
+#endif
+ else if (bytes_read == 0) {
+ /* Read failed because of end of file! */
+ ESET(EPIPE);
+#ifdef NX_TRANS_SOCKET
+ _XIOError(dpy);
+
+ return -1;
+#else
+ _XIOError(dpy);
+#endif
+ }
+
+ else /* bytes_read is less than 0; presumably -1 */ {
+ /* If it's a system call interrupt, it's not an error. */
+#ifdef NX_TRANS_SOCKET
+ if (!ECHECK(EINTR) ||
+ (_NXDisplayErrorFunction != NULL &&
+ (*_NXDisplayErrorFunction)(dpy, _XGetIOError(dpy)))) {
+ _XIOError(dpy);
+ return -1;
+ }
+#else
+ if (!ECHECK(EINTR))
+ _XIOError(dpy);
+#endif
+ }
+#ifdef NX_TRANS_SOCKET
+ if (_XGetIOError(dpy)) {
+ return -1;
+ }
+#endif
+ }
+#ifdef XTHREADS
+ if (dpy->lock && dpy->lock->reply_bytes_left > 0)
+ {
+ dpy->lock->reply_bytes_left -= original_size;
+ if (dpy->lock->reply_bytes_left == 0) {
+ dpy->flags &= ~XlibDisplayReply;
+ UnlockNextReplyReader(dpy);
+ }
+ }
+#endif /* XTHREADS*/
+ return 0;
+}
+#endif /* !USE_XCB */
+
+#ifdef LONG64
+void _XRead32(
+ Display *dpy,
+ register long *data,
+ long len)
+{
+ register int *buf;
+ register long i;
+
+ if (len) {
+ (void) _XRead(dpy, (char *)data, len);
+ i = len >> 2;
+ buf = (int *)data + i;
+ data += i;
+ while (--i >= 0)
+ *--data = *--buf;
+ }
+}
+#endif /* LONG64 */
+
+
+
+#if !USE_XCB
+/*
+ * _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. This routine may have to be reworked if int < long.
+ */
+void _XReadPad(
+ register Display *dpy,
+ register char *data,
+ register long size)
+{
+ register long bytes_read;
+ struct iovec iov[2];
+ char pad[3];
+#ifdef XTHREADS
+ int original_size;
+#endif
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_CHANGE)
+ int congestion;
+#endif
+
+ if ((dpy->flags & XlibDisplayIOError) || 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 = -size & 3;
+ iov[1].iov_base = pad;
+ size += iov[1].iov_len;
+#ifdef XTHREADS
+ original_size = size;
+#endif
+ ESET(0);
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_CHANGE)
+ while (1) {
+ bytes_read = _X11TransReadv (dpy->trans_conn, iov, 2);
+ if (_NXDisplayCongestionFunction != NULL &&
+ _X11TransSocketCongestionChange(dpy->trans_conn, &congestion) == 1) {
+ (*_NXDisplayCongestionFunction)(dpy, congestion);
+ }
+ if (bytes_read == size) {
+ break;
+ }
+#else
+ while ((bytes_read = _X11TransReadv (dpy->trans_conn, iov, 2)) != size) {
+#endif
+
+ if (bytes_read > 0) {
+ size -= bytes_read;
+ if (iov[0].iov_len < bytes_read) {
+ int pad_bytes_read = bytes_read - iov[0].iov_len;
+ iov[1].iov_len -= pad_bytes_read;
+ iov[1].iov_base =
+ (char *)iov[1].iov_base + pad_bytes_read;
+ iov[0].iov_len = 0;
+ }
+ else {
+ iov[0].iov_len -= bytes_read;
+ iov[0].iov_base = (char *)iov[0].iov_base + bytes_read;
+ }
+ }
+ else if (ETEST()) {
+ _XWaitForReadable(dpy);
+ ESET(0);
+ }
+#ifdef SUNSYSV
+ else if (ECHECK(0)) {
+ _XWaitForReadable(dpy);
+ }
+#endif
+ else if (bytes_read == 0) {
+ /* Read failed because of end of file! */
+ ESET(EPIPE);
+#ifdef NX_TRANS_SOCKET
+ _XIOError(dpy);
+
+ return;
+#else
+ _XIOError(dpy);
+#endif
+ }
+
+ else /* bytes_read is less than 0; presumably -1 */ {
+ /* If it's a system call interrupt, it's not an error. */
+#ifdef NX_TRANS_SOCKET
+ if (!ECHECK(EINTR) ||
+ (_NXDisplayErrorFunction != NULL &&
+ (*_NXDisplayErrorFunction)(dpy, _XGetIOError(dpy)))) {
+ _XIOError(dpy);
+ return;
+ }
+#else
+ if (!ECHECK(EINTR))
+ _XIOError(dpy);
+#endif
+ }
+#ifdef NX_TRANS_SOCKET
+ if (_XGetIOError(dpy)) {
+ return;
+ }
+#endif
+ }
+#ifdef XTHREADS
+ if (dpy->lock && dpy->lock->reply_bytes_left > 0)
+ {
+ dpy->lock->reply_bytes_left -= original_size;
+ if (dpy->lock->reply_bytes_left == 0) {
+ dpy->flags &= ~XlibDisplayReply;
+ UnlockNextReplyReader(dpy);
+ }
+ }
+#endif /* XTHREADS*/
+}
+
+/*
+ * _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;
+ */
+void
+_XSend (
+ register Display *dpy,
+ _Xconst char *data,
+ register long size)
+{
+ struct iovec iov[3];
+ static char const pad[3] = {0, 0, 0};
+ /* XText8 and XText16 require that the padding bytes be zero! */
+
+ long skip, dbufsize, padsize, total, todo;
+ _XExtension *ext;
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_CHANGE)
+ int congestion;
+#endif
+
+#ifdef NX_TRANS_SOCKET
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG)
+ fprintf(stderr, "_XSend: Sending data with [%d] bytes to write.\n",
+ (dpy->bufptr - dpy->buffer));
+#endif
+ if (!size || (dpy->flags & XlibDisplayIOError))
+ {
+ if (dpy->flags & XlibDisplayIOError)
+ {
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG)
+ fprintf(stderr, "_XSend: Returning with I/O error detected.\n");
+#endif
+ dpy->bufptr = dpy->buffer;
+ dpy->last_req = (char *)&_dummy_request;
+ }
+
+ return;
+ }
+#else
+ if (!size || (dpy->flags & XlibDisplayIOError)) return;
+#endif
+ dbufsize = dpy->bufptr - dpy->buffer;
+#ifdef XTHREADS
+ dpy->flags |= XlibDisplayWriting;
+ /* make sure no one else can put in data */
+ dpy->bufptr = dpy->bufmax;
+#endif
+ padsize = -size & 3;
+ for (ext = dpy->flushes; ext; ext = ext->next_flush) {
+ (*ext->before_flush)(dpy, &ext->codes, dpy->buffer, dbufsize);
+ (*ext->before_flush)(dpy, &ext->codes, (char *)data, size);
+ if (padsize)
+ (*ext->before_flush)(dpy, &ext->codes, pad, padsize);
+ }
+ skip = 0;
+ todo = total = dbufsize + size + padsize;
+
+ /*
+ * There are 3 pieces that may need to be written out:
+ *
+ * o whatever is in the display buffer
+ * o the data passed in by the user
+ * o any padding needed to 32bit align the whole mess
+ *
+ * This loop looks at all 3 pieces each time through. It uses skip
+ * to figure out whether or not a given piece is needed.
+ */
+ while (total) {
+ long before = skip; /* amount of whole thing written */
+ long remain = todo; /* amount to try this time, <= total */
+ 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. This
+ * translates to:
+ *
+ * how much of this piece is new?
+ * if more new then we are trying this time, clamp
+ * if nothing new
+ * then bump down amount already written, for next piece
+ * else put new stuff in iovec, will need all of next piece
+ *
+ * Note that todo had better be at least 1 or else we'll end up
+ * writing 0 iovecs.
+ */
+#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, dbufsize)
+ InsertIOV ((char *)data, size)
+ InsertIOV ((char *)pad, padsize)
+
+ ESET(0);
+ if ((len = _X11TransWritev(dpy->trans_conn, iov, i)) >= 0) {
+#ifdef NX_TRANS_SOCKET
+ if (_NXDisplayWriteFunction != NULL) {
+ (*_NXDisplayWriteFunction)(dpy, len);
+ }
+#ifdef NX_TRANS_CHANGE
+ if (_NXDisplayCongestionFunction != NULL &&
+ _X11TransSocketCongestionChange(dpy->trans_conn, &congestion) == 1) {
+ (*_NXDisplayCongestionFunction)(dpy, congestion);
+ }
+#endif
+#endif
+ skip += len;
+ total -= len;
+ todo = total;
+ } else if (ETEST()) {
+ _XWaitForWritable(dpy
+#ifdef XTHREADS
+ , NULL
+#endif
+ );
+#ifdef SUNSYSV
+ } else if (ECHECK(0)) {
+ _XWaitForWritable(dpy
+#ifdef XTHREADS
+ , NULL
+#endif
+ );
+#endif
+#ifdef ESZTEST
+ } else if (ESZTEST()) {
+ if (todo > 1)
+ todo >>= 1;
+ else {
+ _XWaitForWritable(dpy
+#ifdef XTHREADS
+ , NULL
+#endif
+ );
+ }
+#endif
+#ifdef NX_TRANS_SOCKET
+ } else if (!ECHECK(EINTR) ||
+ (_NXDisplayErrorFunction != NULL &&
+ (*_NXDisplayErrorFunction)(dpy, _XGetIOError(dpy)))) {
+ _XIOError(dpy);
+ return;
+ }
+#else
+ } else if (!ECHECK(EINTR)) {
+ _XIOError(dpy);
+ }
+#endif
+#ifdef NX_TRANS_SOCKET
+ if (_XGetIOError(dpy)) {
+ return;
+ }
+#endif
+ }
+ dpy->last_req = (char *) & _dummy_request;
+ _XSetSeqSyncFunction(dpy);
+ dpy->bufptr = dpy->buffer;
+#ifdef XTHREADS
+ dpy->flags &= ~XlibDisplayWriting;
+#endif
+ return;
+}
+
+static void
+_XGetMiscCode(
+ register Display *dpy)
+{
+ xQueryExtensionReply qrep;
+ register xQueryExtensionReq *qreq;
+ xXCMiscGetVersionReply vrep;
+ register xXCMiscGetVersionReq *vreq;
+
+ if (dpy->xcmisc_opcode)
+ return;
+ GetReq(QueryExtension, qreq);
+ qreq->nbytes = sizeof(XCMiscExtensionName) - 1;
+ qreq->length += (qreq->nbytes+(unsigned)3)>>2;
+ _XSend(dpy, XCMiscExtensionName, (long)qreq->nbytes);
+ if (!_XReply (dpy, (xReply *)&qrep, 0, xTrue))
+ dpy->xcmisc_opcode = -1;
+ else {
+ GetReq(XCMiscGetVersion, vreq);
+ vreq->reqType = qrep.major_opcode;
+ vreq->miscReqType = X_XCMiscGetVersion;
+ vreq->majorVersion = XCMiscMajorVersion;
+ vreq->minorVersion = XCMiscMinorVersion;
+ if (!_XReply (dpy, (xReply *)&vrep, 0, xTrue))
+ dpy->xcmisc_opcode = -1;
+ else
+ dpy->xcmisc_opcode = qrep.major_opcode;
+ }
+}
+
+void
+_XIDHandler(
+ register Display *dpy)
+{
+ xXCMiscGetXIDRangeReply grep;
+ register xXCMiscGetXIDRangeReq *greq;
+
+ if (dpy->resource_max == dpy->resource_mask + 1) {
+ _XGetMiscCode(dpy);
+ if (dpy->xcmisc_opcode > 0) {
+ GetReq(XCMiscGetXIDRange, greq);
+ greq->reqType = dpy->xcmisc_opcode;
+ greq->miscReqType = X_XCMiscGetXIDRange;
+ if (_XReply (dpy, (xReply *)&grep, 0, xTrue) && grep.count) {
+ dpy->resource_id = ((grep.start_id - dpy->resource_base) >>
+ dpy->resource_shift);
+ dpy->resource_max = dpy->resource_id;
+ if (grep.count > 5)
+ dpy->resource_max += grep.count - 6;
+ dpy->resource_max <<= dpy->resource_shift;
+ }
+ sync_while_locked(dpy);
+ }
+ }
+}
+
+/*
+ * _XAllocID - resource ID allocation routine.
+ */
+XID _XAllocID(
+ register Display *dpy)
+{
+ XID id;
+
+ id = dpy->resource_id << dpy->resource_shift;
+ if (id >= dpy->resource_max) {
+ _XSetPrivSyncFunction(dpy);
+ dpy->resource_max = dpy->resource_mask + 1;
+ }
+ if (id <= dpy->resource_mask) {
+ dpy->resource_id++;
+ return (dpy->resource_base + id);
+ }
+ if (id != 0x10000000) {
+ (void) fprintf(stderr,
+ "Xlib: resource ID allocation space exhausted!\n");
+ id = 0x10000000;
+ dpy->resource_id = id >> dpy->resource_shift;
+ }
+ return id;
+}
+
+/*
+ * _XAllocIDs - multiple resource ID allocation routine.
+ */
+void _XAllocIDs(
+ register Display *dpy,
+ XID *ids,
+ int count)
+{
+ XID id;
+ int i;
+ xXCMiscGetXIDListReply grep;
+ register xXCMiscGetXIDListReq *greq;
+
+ id = dpy->resource_id << dpy->resource_shift;
+ if (dpy->resource_max <= dpy->resource_mask &&
+ id <= dpy->resource_mask &&
+ (dpy->resource_max - id) > ((count - 1) << dpy->resource_shift)) {
+ id += dpy->resource_base;
+ for (i = 0; i < count; i++) {
+ ids[i] = id;
+ id += (1 << dpy->resource_shift);
+ dpy->resource_id++;
+ }
+ return;
+ }
+ grep.count = 0;
+ _XGetMiscCode(dpy);
+ if (dpy->xcmisc_opcode > 0) {
+ GetReq(XCMiscGetXIDList, greq);
+ greq->reqType = dpy->xcmisc_opcode;
+ greq->miscReqType = X_XCMiscGetXIDList;
+ greq->count = count;
+ if (_XReply(dpy, (xReply *)&grep, 0, xFalse) && grep.count) {
+ _XRead32(dpy, (long *) ids, 4L * (long) (grep.count));
+ for (i = 0; i < grep.count; i++) {
+ id = (ids[i] - dpy->resource_base) >> dpy->resource_shift;
+ if (id >= dpy->resource_id)
+ dpy->resource_id = id;
+ }
+ if (id >= dpy->resource_max) {
+ _XSetPrivSyncFunction(dpy);
+ dpy->resource_max = dpy->resource_mask + 1;
+ }
+ }
+ }
+ 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.
+ * 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(
+ register Display *dpy,
+ register xGenericReply *rep)
+{
+ register unsigned long newseq, lastseq;
+
+ lastseq = dpy->last_request_read;
+ /*
+ * 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(lastseq);
+
+ newseq = (lastseq & ~((unsigned long)0xffff)) | rep->sequenceNumber;
+
+ if (newseq < lastseq) {
+ newseq += 0x10000;
+ if (newseq > dpy->request) {
+#ifdef NX_TRANS_SOCKET
+ if (_NXLostSequenceFunction != NULL)
+ {
+ (*_NXLostSequenceFunction)(dpy, newseq, dpy->request,
+ (unsigned int) rep->type);
+ }
+ else
+#endif /* #ifdef NX_TRANS_SOCKET */
+ {
+ (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;
+ }
+ }
+
+ dpy->last_request_read = newseq;
+ 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
+ * we may encounter.
+ */
+Status
+_XReply (
+ register Display *dpy,
+ register xReply *rep,
+ int extra, /* number of 32-bit words expected after the reply */
+ Bool discard) /* should I discard data following "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;
+#ifdef XTHREADS
+ struct _XCVList *cvl;
+#endif
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG)
+ fprintf(stderr, "_XReply: Going to wait for an X reply.\n");
+#endif
+
+#ifdef NX_TRANS_SOCKET
+ if (dpy->flags & XlibDisplayIOError)
+ {
+#ifdef NX_TRANS_DEBUG
+ fprintf(stderr, "_XReply: Returning 0 with I/O error detected.\n");
+#endif
+ return 0;
+ }
+#else
+ if (dpy->flags & XlibDisplayIOError)
+ return 0;
+#endif
+
+#ifdef XTHREADS
+ /* create our condition variable and append to list */
+ cvl = QueueReplyReaderLock(dpy);
+ if (cvl) {
+ cvl->buf = rep;
+ if (dpy->lock->reply_awaiters == cvl && !dpy->lock->event_awaiters)
+ dpy->lock->reply_first = True;
+ }
+
+#ifdef XTHREADS_DEBUG
+ printf("_XReply called in thread %x, adding %x to cvl\n",
+ XThread_Self(), cvl);
+#endif
+
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG)
+ fprintf(stderr, "_XReply: Going to flush the display buffer.\n");
+#endif
+ _XFlushInt(dpy, cvl ? cvl->cv : NULL);
+ /* if it is not our turn to read a reply off the wire,
+ * wait til we're at head of list. if there is an event waiter,
+ * and our reply hasn't been read, they'll be in select and will
+ * hand control back to us next.
+ */
+ if(dpy->lock &&
+ (dpy->lock->reply_awaiters != cvl || !dpy->lock->reply_first)) {
+ ConditionWait(dpy, cvl->cv);
+ }
+ dpy->flags |= XlibDisplayReply;
+#else /* XTHREADS else */
+ _XFlush(dpy);
+#endif
+
+#ifdef NX_TRANS_SOCKET
+ /*
+ * We are going to block waiting for the remote
+ * X server. Be sure that the proxy has flushed
+ * all the data.
+ */
+
+#ifdef NX_TRANS_TEST
+ fprintf(stderr, "_XReply: Requesting a flush of the NX transport.\n");
+#endif
+ NXTransFlush(dpy->fd);
+#endif
+
+ for (;;) {
+#ifdef XTHREADS
+ /* Did another thread's _XReadEvents get our reply by accident? */
+ if (!dpy->lock || !dpy->lock->reply_was_read)
+#endif
+ (void) _XRead(dpy, (char *)rep, (long)SIZEOF(xReply));
+#ifdef XTHREADS
+ if (dpy->lock)
+ dpy->lock->reply_was_read = False;
+#endif
+
+ 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 {
+ int pend = SIZEOF(xReply);
+ if (_XAsyncReply(dpy, rep, (char *)rep, &pend, False)
+ != (char *)rep)
+ continue;
+ }
+ if (extra <= rep->generic.length) {
+ if (extra > 0)
+ /*
+ * Read the extra data into storage immediately
+ * following the GenericReply structure.
+ */
+ (void) _XRead (dpy, (char *) (NEXTPTR(rep,xReply)),
+ ((long)extra) << 2);
+ if (discard) {
+ if (extra < rep->generic.length)
+ _XEatData(dpy, (rep->generic.length - extra) << 2);
+ }
+#ifdef XTHREADS
+ if (dpy->lock) {
+ if (discard) {
+ dpy->lock->reply_bytes_left = 0;
+ } else {
+ dpy->lock->reply_bytes_left =
+ (rep->generic.length - extra) << 2;
+ }
+ if (dpy->lock->reply_bytes_left == 0) {
+ dpy->flags &= ~XlibDisplayReply;
+ UnlockNextReplyReader(dpy);
+ }
+ } else
+ dpy->flags &= ~XlibDisplayReply;
+#endif
+ 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...
+ */
+ (void) _XRead (dpy, (char *) (NEXTPTR(rep,xReply)),
+ ((long) rep->generic.length) << 2);
+ dpy->flags &= ~XlibDisplayReply;
+ UnlockNextReplyReader(dpy);
+#ifdef NX_TRANS_SOCKET
+ /*
+ * The original code has provision
+ * for returning already.
+ */
+#endif
+ _XIOError (dpy);
+ return (0);
+
+ case X_Error:
+ {
+ register _XExtension *ext;
+ register Bool ret = False;
+ int ret_code;
+ xError *err = (xError *) rep;
+ unsigned long serial;
+
+ dpy->flags &= ~XlibDisplayReply;
+ serial = _XSetLastRequestRead(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_LookupColor:
+ case X_AllocNamedColor:
+ UnlockNextReplyReader(dpy);
+ return(0);
+ }
+ break;
+ case BadFont:
+ if (err->majorCode == X_QueryFont) {
+ UnlockNextReplyReader(dpy);
+ return (0);
+ }
+ break;
+ case BadAlloc:
+ case BadAccess:
+ UnlockNextReplyReader(dpy);
+ return (0);
+ }
+ /*
+ * we better see if there is an extension who may
+ * want to suppress the error.
+ */
+ for (ext = dpy->ext_procs; !ret && ext; ext = ext->next) {
+ if (ext->error)
+ ret = (*ext->error)(dpy, err, &ext->codes, &ret_code);
+ }
+ if (!ret) {
+ _XError(dpy, err);
+ ret_code = 0;
+ }
+ if (serial == cur_request) {
+ UnlockNextReplyReader(dpy);
+ return(ret_code);
+ }
+
+ } /* case X_Error */
+ break;
+ default:
+ _XEnq(dpy, (xEvent *) rep);
+#ifdef XTHREADS
+ if (dpy->lock && dpy->lock->event_awaiters)
+ ConditionSignal(dpy, dpy->lock->event_awaiters->cv);
+#endif
+ break;
+ }
+#ifdef NX_TRANS_SOCKET
+ if (_XGetIOError(dpy)) {
+ UnlockNextReplyReader(dpy);
+ return 0;
+ }
+#endif
+ }
+}
+
+static char *
+_XAsyncReply(
+ Display *dpy,
+ register xReply *rep,
+ char *buf,
+ register int *lenp,
+ Bool discard)
+{
+ register _XAsyncHandler *async, *next;
+ register int len;
+ register Bool consumed = False;
+ char *nbuf;
+
+ (void) _XSetLastRequestRead(dpy, &rep->generic);
+ len = SIZEOF(xReply) + (rep->generic.length << 2);
+ if (len < SIZEOF(xReply)) {
+#ifdef NX_TRANS_SOCKET
+
+ /*
+ * The original code has provision
+ * for returning already.
+ */
+
+#endif
+ _XIOError (dpy);
+ buf += *lenp;
+ *lenp = 0;
+ return buf;
+ }
+
+ for (async = dpy->async_handlers; async; async = next) {
+ next = async->next;
+ if ((consumed = (*async->handler)(dpy, rep, buf, *lenp, async->data)))
+ break;
+ }
+ if (!consumed) {
+ if (!discard)
+ return buf;
+ (void) fprintf(stderr,
+ "Xlib: unexpected async reply (sequence 0x%lx)!\n",
+ dpy->last_request_read);
+#ifdef XTHREADS
+#ifdef XTHREADS_DEBUG
+ printf("thread %x, unexpected async reply\n", XThread_Self());
+#endif
+#endif
+ if (len > *lenp)
+ _XEatData(dpy, len - *lenp);
+ }
+ if (len < SIZEOF(xReply))
+ {
+#ifdef NX_TRANS_SOCKET
+
+ /*
+ * The original code has provision
+ * for returning already.
+ */
+
+#endif
+ _XIOError (dpy);
+ buf += *lenp;
+ *lenp = 0;
+ return buf;
+ }
+ if (len >= *lenp) {
+ buf += *lenp;
+ *lenp = 0;
+ return buf;
+ }
+ *lenp -= len;
+ buf += len;
+ len = *lenp;
+ nbuf = buf;
+ while (len > SIZEOF(xReply)) {
+ if (*buf == X_Reply)
+ return nbuf;
+ buf += SIZEOF(xReply);
+ len -= SIZEOF(xReply);
+ }
+ if (len > 0 && len < SIZEOF(xReply)) {
+ buf = nbuf;
+ len = SIZEOF(xReply) - len;
+ nbuf -= len;
+ memmove(nbuf, buf, *lenp);
+ (void) _XRead(dpy, nbuf + *lenp, (long)len);
+ *lenp += len;
+ }
+ return nbuf;
+}
+#endif /* !USE_XCB */
+
+/*
+ * Support for internal connections, such as an IM might use.
+ * By Stephen Gildea, X Consortium, September 1993
+ */
+
+/* _XRegisterInternalConnection
+ * Each IM (or Xlib extension) that opens a file descriptor that Xlib should
+ * include in its select/poll mask must call this function to register the
+ * fd with Xlib. Any XConnectionWatchProc registered by XAddConnectionWatch
+ * will also be called.
+ *
+ * Whenever Xlib detects input available on fd, it will call callback
+ * with call_data to process it. If non-Xlib code calls select/poll
+ * and detects input available, it must call XProcessInternalConnection,
+ * which will call the associated callback.
+ *
+ * Non-Xlib code can learn about these additional fds by calling
+ * XInternalConnectionNumbers or, more typically, by registering
+ * a XConnectionWatchProc with XAddConnectionWatch
+ * to be called when fds are registered or unregistered.
+ *
+ * Returns True if registration succeeded, False if not, typically
+ * because could not allocate memory.
+ * Assumes Display locked when called.
+ */
+Status
+_XRegisterInternalConnection(
+ Display* dpy,
+ int fd,
+ _XInternalConnectionProc callback,
+ XPointer call_data
+)
+{
+ struct _XConnectionInfo *new_conni, **iptr;
+ struct _XConnWatchInfo *watchers;
+ XPointer *wd;
+
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG)
+ fprintf(stderr, "_XRegisterInternalConnection: Got called.\n");
+#endif
+ new_conni = Xmalloc(sizeof(struct _XConnectionInfo));
+ if (!new_conni)
+ return 0;
+ new_conni->watch_data = Xmalloc(dpy->watcher_count * sizeof(XPointer));
+ if (!new_conni->watch_data) {
+ Xfree(new_conni);
+ return 0;
+ }
+ new_conni->fd = fd;
+ new_conni->read_callback = callback;
+ new_conni->call_data = call_data;
+ new_conni->next = NULL;
+ /* link new structure onto end of list */
+ for (iptr = &dpy->im_fd_info; *iptr; iptr = &(*iptr)->next)
+ ;
+ *iptr = new_conni;
+ dpy->im_fd_length++;
+ _XPollfdCacheAdd(dpy, fd);
+
+ for (watchers=dpy->conn_watchers, wd=new_conni->watch_data;
+ watchers;
+ watchers=watchers->next, wd++) {
+ *wd = NULL; /* for cleanliness */
+ (*watchers->fn) (dpy, watchers->client_data, fd, True, wd);
+ }
+
+ return 1;
+}
+
+/* _XUnregisterInternalConnection
+ * Each IM (or Xlib extension) that closes a file descriptor previously
+ * registered with _XRegisterInternalConnection must call this function.
+ * Any XConnectionWatchProc registered by XAddConnectionWatch
+ * will also be called.
+ *
+ * Assumes Display locked when called.
+ */
+void
+_XUnregisterInternalConnection(
+ Display* dpy,
+ int fd
+)
+{
+ struct _XConnectionInfo *info_list, **prev;
+ struct _XConnWatchInfo *watch;
+ XPointer *wd;
+
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG)
+ fprintf(stderr, "_XUnregisterInternalConnection: Got called.\n");
+#endif
+ for (prev = &dpy->im_fd_info; (info_list = *prev);
+ prev = &info_list->next) {
+ if (info_list->fd == fd) {
+ *prev = info_list->next;
+ dpy->im_fd_length--;
+ for (watch=dpy->conn_watchers, wd=info_list->watch_data;
+ watch;
+ watch=watch->next, wd++) {
+ (*watch->fn) (dpy, watch->client_data, fd, False, wd);
+ }
+ Xfree (info_list->watch_data);
+ Xfree (info_list);
+ break;
+ }
+ }
+ _XPollfdCacheDel(dpy, fd);
+}
+
+/* XInternalConnectionNumbers
+ * Returns an array of fds and an array of corresponding call data.
+ * Typically a XConnectionWatchProc registered with XAddConnectionWatch
+ * will be used instead of this function to discover
+ * additional fds to include in the select/poll mask.
+ *
+ * The list is allocated with Xmalloc and should be freed by the caller
+ * with Xfree;
+ */
+Status
+XInternalConnectionNumbers(
+ Display *dpy,
+ int **fd_return,
+ int *count_return
+)
+{
+ int count;
+ struct _XConnectionInfo *info_list;
+ int *fd_list;
+
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG)
+ fprintf(stderr, "XInternalConnectionNumbers: Got called.\n");
+#endif
+ LockDisplay(dpy);
+ count = 0;
+ for (info_list=dpy->im_fd_info; info_list; info_list=info_list->next)
+ count++;
+ fd_list = Xmalloc (count * sizeof(int));
+ if (!fd_list) {
+ UnlockDisplay(dpy);
+ return 0;
+ }
+ count = 0;
+ for (info_list=dpy->im_fd_info; info_list; info_list=info_list->next) {
+ fd_list[count] = info_list->fd;
+ count++;
+ }
+ UnlockDisplay(dpy);
+
+ *fd_return = fd_list;
+ *count_return = count;
+ return 1;
+}
+
+void _XProcessInternalConnection(
+ Display *dpy,
+ struct _XConnectionInfo *conn_info)
+{
+ dpy->flags |= XlibDisplayProcConni;
+#if defined(XTHREADS) && !USE_XCB
+ if (dpy->lock) {
+ /* check cache to avoid call to thread_self */
+ if (xthread_have_id(dpy->lock->reading_thread))
+ dpy->lock->conni_thread = dpy->lock->reading_thread;
+ else
+ dpy->lock->conni_thread = XThread_Self();
+ }
+#endif /* XTHREADS && !USE_XCB */
+ UnlockDisplay(dpy);
+ (*conn_info->read_callback) (dpy, conn_info->fd, conn_info->call_data);
+ LockDisplay(dpy);
+#if defined(XTHREADS) && !USE_XCB
+ if (dpy->lock)
+ xthread_clear_id(dpy->lock->conni_thread);
+#endif /* XTHREADS && !USE_XCB */
+ dpy->flags &= ~XlibDisplayProcConni;
+}
+
+/* XProcessInternalConnection
+ * Call the _XInternalConnectionProc registered by _XRegisterInternalConnection
+ * for this fd.
+ * The Display is NOT locked during the call.
+ */
+void
+XProcessInternalConnection(
+ Display* dpy,
+ int fd
+)
+{
+ struct _XConnectionInfo *info_list;
+
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG)
+ fprintf(stderr, "XProcessInternalConnection: Got called.\n");
+#endif
+
+ LockDisplay(dpy);
+ for (info_list=dpy->im_fd_info; info_list; info_list=info_list->next) {
+ if (info_list->fd == fd) {
+ _XProcessInternalConnection(dpy, info_list);
+ break;
+ }
+ }
+ UnlockDisplay(dpy);
+}
+
+/* XAddConnectionWatch
+ * Register a callback to be called whenever _XRegisterInternalConnection
+ * or _XUnregisterInternalConnection is called.
+ * Callbacks are called with the Display locked.
+ * If any connections are already registered, the callback is immediately
+ * called for each of them.
+ */
+Status
+XAddConnectionWatch(
+ Display* dpy,
+ XConnectionWatchProc callback,
+ XPointer client_data
+)
+{
+ struct _XConnWatchInfo *new_watcher, **wptr;
+ struct _XConnectionInfo *info_list;
+ XPointer *wd_array;
+
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG)
+ fprintf(stderr, "XAddConnectionWatch: Got called.\n");
+#endif
+ LockDisplay(dpy);
+
+ /* allocate new watch data */
+ for (info_list=dpy->im_fd_info; info_list; info_list=info_list->next) {
+ wd_array = Xrealloc(info_list->watch_data,
+ (dpy->watcher_count + 1) * sizeof(XPointer));
+ if (!wd_array) {
+ UnlockDisplay(dpy);
+ return 0;
+ }
+ info_list->watch_data = wd_array;
+ wd_array[dpy->watcher_count] = NULL; /* for cleanliness */
+ }
+
+ new_watcher = Xmalloc(sizeof(struct _XConnWatchInfo));
+ if (!new_watcher) {
+ UnlockDisplay(dpy);
+ return 0;
+ }
+ new_watcher->fn = callback;
+ new_watcher->client_data = client_data;
+ new_watcher->next = NULL;
+
+ /* link new structure onto end of list */
+ for (wptr = &dpy->conn_watchers; *wptr; wptr = &(*wptr)->next)
+ ;
+ *wptr = new_watcher;
+ dpy->watcher_count++;
+
+ /* call new watcher on all currently registered fds */
+ for (info_list=dpy->im_fd_info; info_list; info_list=info_list->next) {
+ (*callback) (dpy, client_data, info_list->fd, True,
+ info_list->watch_data + dpy->watcher_count - 1);
+ }
+
+ UnlockDisplay(dpy);
+ return 1;
+}
+
+/* XRemoveConnectionWatch
+ * Unregister a callback registered by XAddConnectionWatch.
+ * Both callback and client_data must match what was passed to
+ * XAddConnectionWatch.
+ */
+void
+XRemoveConnectionWatch(
+ Display* dpy,
+ XConnectionWatchProc callback,
+ XPointer client_data
+)
+{
+ struct _XConnWatchInfo *watch;
+ struct _XConnWatchInfo *previous = NULL;
+ struct _XConnectionInfo *conni;
+ int counter = 0;
+
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG)
+ fprintf(stderr, "XRemoveConnectionWatch: Got called.\n");
+#endif
+ LockDisplay(dpy);
+ for (watch=dpy->conn_watchers; watch; watch=watch->next) {
+ if (watch->fn == callback && watch->client_data == client_data) {
+ if (previous)
+ previous->next = watch->next;
+ else
+ dpy->conn_watchers = watch->next;
+ Xfree (watch);
+ dpy->watcher_count--;
+ /* remove our watch_data for each connection */
+ for (conni=dpy->im_fd_info; conni; conni=conni->next) {
+ /* don't bother realloc'ing; these arrays are small anyway */
+ /* overlapping */
+ memmove(conni->watch_data+counter,
+ conni->watch_data+counter+1,
+ dpy->watcher_count - counter);
+ }
+ break;
+ }
+ previous = watch;
+ counter++;
+ }
+ UnlockDisplay(dpy);
+}
+
+/* end of internal connections support */
+
+
+#if !USE_XCB
+/* Read and discard "n" 8-bit bytes of data */
+
+void _XEatData(
+ Display *dpy,
+ register unsigned long n)
+{
+#define SCRATCHSIZE 2048
+ char buf[SCRATCHSIZE];
+
+#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG)
+ fprintf(stderr, "_XEatData: Going to eat [%ld] bytes of data from descriptor [%d].\n",
+ n, dpy->fd);
+#endif
+ while (n > 0) {
+ register long bytes_read = (n > SCRATCHSIZE) ? SCRATCHSIZE : n;
+ (void) _XRead (dpy, buf, bytes_read);
+ n -= bytes_read;
+ }
+#undef SCRATCHSIZE
+}
+
+/*
+ Port from libXfixes commit
+ b031e3b60fa1af9e49449f23d4a84395868be3ab We need this here to
+ enable linking of current libXrender against libNX_X11 instead of
+ the system's libX11
+
+ The original implementation of this function (libX11 commit
+ 9f5d83706543696fc944c1835a403938c06f2cc5) uses xcb stuff which we
+ do not have in libNX_X11. So we take a workaround from another
+ lib. This workaround had been implemented temporarily in a couple
+ of X libs, see e.g. https://lists.x.org/archives/xorg-devel/2013-July/036763.html.
+*/
+#include <nx-X11/Xmd.h> /* for LONG64 on 64-bit platforms */
+#include <limits.h>
+
+void _XEatDataWords(Display *dpy, unsigned long n)
+{
+#ifndef LONG64
+ if (n >= (ULONG_MAX >> 2))
+ _XIOError(dpy);
+#endif
+ _XEatData (dpy, n << 2);
+}
+#endif /* !USE_XCB */
+
+/* Cookie jar implementation
+ dpy->cookiejar is a linked list. _XEnq receives the events but leaves
+ them in the normal EQ. _XStoreEvent returns the cookie event (minus
+ data pointer) and adds it to the cookiejar. _XDeq just removes
+ the entry like any other event but resets the data pointer for
+ cookie events (to avoid double-free, the memory is re-used by Xlib).
+
+ _XFetchEventCookie (called from XGetEventData) removes a cookie from the
+ jar. _XFreeEventCookies removes all unclaimed cookies from the jar
+ (called by XNextEvent).
+
+ _XFreeDisplayStructure calls _XFreeEventCookies for each cookie in the
+ normal EQ.
+ */
+
+#include "utlist.h"
+struct stored_event {
+ XGenericEventCookie ev;
+ struct stored_event *prev;
+ struct stored_event *next;
+};
+
+Bool
+_XIsEventCookie(Display *dpy, XEvent *ev)
+{
+ return (ev->xcookie.type == GenericEvent &&
+ dpy->generic_event_vec[ev->xcookie.extension & 0x7F] != NULL);
+}
+
+/**
+ * Free all events in the event list.
+ */
+void
+_XFreeEventCookies(Display *dpy)
+{
+ struct stored_event **head, *e, *tmp;
+
+ if (!dpy->cookiejar)
+ return;
+
+ head = (struct stored_event**)&dpy->cookiejar;
+
+ DL_FOREACH_SAFE(*head, e, tmp) {
+ if (dpy->cookiejar == e)
+ dpy->cookiejar = NULL;
+ XFree(e->ev.data);
+ XFree(e);
+ }
+}
+
+/**
+ * Add an event to the display's event list. This event must be freed on the
+ * next call to XNextEvent().
+ */
+void
+_XStoreEventCookie(Display *dpy, XEvent *event)
+{
+ XGenericEventCookie* cookie = &event->xcookie;
+ struct stored_event **head, *add;
+
+ if (!_XIsEventCookie(dpy, event))
+ return;
+
+ head = (struct stored_event**)(&dpy->cookiejar);
+
+ add = Xmalloc(sizeof(struct stored_event));
+ if (!add) {
+ ESET(ENOMEM);
+ _XIOError(dpy);
+ }
+ add->ev = *cookie;
+ DL_APPEND(*head, add);
+ cookie->data = NULL; /* don't return data yet, must be claimed */
+}
+
+/**
+ * Return the event with the given cookie and remove it from the list.
+ */
+Bool
+_XFetchEventCookie(Display *dpy, XGenericEventCookie* ev)
+{
+ Bool ret = False;
+ struct stored_event **head, *event;
+ head = (struct stored_event**)&dpy->cookiejar;
+
+ if (!_XIsEventCookie(dpy, (XEvent*)ev))
+ return ret;
+
+ DL_FOREACH(*head, event) {
+ if (event->ev.cookie == ev->cookie &&
+ event->ev.extension == ev->extension &&
+ event->ev.evtype == ev->evtype) {
+ *ev = event->ev;
+ DL_DELETE(*head, event);
+ Xfree(event);
+ ret = True;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+Bool
+_XCopyEventCookie(Display *dpy, XGenericEventCookie *in, XGenericEventCookie *out)
+{
+ Bool ret = False;
+ int extension;
+
+ if (!_XIsEventCookie(dpy, (XEvent*)in) || !out)
+ return ret;
+
+ extension = in->extension & 0x7F;
+
+ if (!dpy->generic_event_copy_vec[extension])
+ return ret;
+
+ ret = ((*dpy->generic_event_copy_vec[extension])(dpy, in, out));
+ out->cookie = ret ? ++dpy->next_cookie : 0;
+ return ret;
+}
+
+
+/*
+ * _XEnq - Place event packets on the display's queue.
+ * note that no squishing of move events in V11, since there
+ * is pointer motion hints....
+ */
+void _XEnq(
+ register Display *dpy,
+ register xEvent *event)
+{
+ register _XQEvent *qelt;
+ int type, extension;
+
+ if ((qelt = dpy->qfree)) {
+ /* If dpy->qfree is non-NULL do this, else malloc a new one. */
+ dpy->qfree = qelt->next;
+ }
+ else if ((qelt = Xmalloc(sizeof(_XQEvent))) == NULL) {
+ /* Malloc call failed! */
+ ESET(ENOMEM);
+#ifdef NX_TRANS_SOCKET
+ _XIOError(dpy);
+
+ return;
+#else
+ _XIOError(dpy);
+#endif
+ }
+ qelt->next = NULL;
+
+ type = event->u.u.type & 0177;
+ extension = ((xGenericEvent*)event)->extension;
+
+ qelt->event.type = type;
+ /* If an extension has registered a generic_event_vec handler, then
+ * it can handle event cookies. Otherwise, proceed with the normal
+ * event handlers.
+ *
+ * If the generic_event_vec is called, qelt->event is a event cookie
+ * with the data pointer and the "free" pointer set. Data pointer is
+ * some memory allocated by the extension.
+ */
+ if (type == GenericEvent && dpy->generic_event_vec[extension & 0x7F]) {
+ XGenericEventCookie *cookie = &qelt->event.xcookie;
+ (*dpy->generic_event_vec[extension & 0x7F])(dpy, cookie, event);
+ cookie->cookie = ++dpy->next_cookie;
+
+ qelt->qserial_num = dpy->next_event_serial_num++;
+ if (dpy->tail) dpy->tail->next = qelt;
+ else dpy->head = qelt;
+
+ dpy->tail = qelt;
+ dpy->qlen++;
+ } else if ((*dpy->event_vec[type])(dpy, &qelt->event, event)) {
+ qelt->qserial_num = dpy->next_event_serial_num++;
+ 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 = dpy->qfree;
+ dpy->qfree = qelt;
+ }
+}
+
+/*
+ * _XDeq - Remove event packet from the display's queue.
+ */
+void _XDeq(
+ register Display *dpy,
+ register _XQEvent *prev, /* element before qelt */
+ register _XQEvent *qelt) /* element to be unlinked */
+{
+ if (prev) {
+ if ((prev->next = qelt->next) == NULL)
+ dpy->tail = prev;
+ } else {
+ /* no prev, so removing first elt */
+ if ((dpy->head = qelt->next) == NULL)
+ dpy->tail = NULL;
+ }
+ qelt->qserial_num = 0;
+ qelt->next = dpy->qfree;
+ dpy->qfree = qelt;
+ dpy->qlen--;
+
+ if (_XIsEventCookie(dpy, &qelt->event)) {
+ XGenericEventCookie* cookie = &qelt->event.xcookie;
+ /* dpy->qfree is re-used, reset memory to avoid double free on
+ * _XFreeDisplayStructure */
+ cookie->data = NULL;
+ }
+}
+
+/*
+ * EventToWire in separate file in that often not needed.
+ */
+
+/*ARGSUSED*/
+Bool
+_XUnknownWireEvent(
+ 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);
+}
+
+Bool
+_XUnknownWireEventCookie(
+ Display *dpy, /* pointer to display structure */
+ XGenericEventCookie *re, /* pointer to where event should be reformatted */
+ xEvent *event) /* wire protocol event */
+{
+#ifdef notdef
+ fprintf(stderr,
+ "Xlib: unhandled wire cookie event! extension number = %d, display = %x\n.",
+ ((xGenericEvent*)event)->extension, dpy);
+#endif
+ return(False);
+}
+
+Bool
+_XUnknownCopyEventCookie(
+ Display *dpy, /* pointer to display structure */
+ XGenericEventCookie *in, /* source */
+ XGenericEventCookie *out) /* destination */
+{
+#ifdef notdef
+ fprintf(stderr,
+ "Xlib: unhandled cookie event copy! extension number = %d, display = %x\n.",
+ in->extension, dpy);
+#endif
+ return(False);
+}
+
+/*ARGSUSED*/
+Status
+_XUnknownNativeEvent(
+ 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(
+ 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 = _XSetLastRequestRead(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 = cvtINT16toInt(event->u.keyButtonPointer.eventX);
+ ev->y = cvtINT16toInt(event->u.keyButtonPointer.eventY);
+ ev->x_root = cvtINT16toInt(event->u.keyButtonPointer.rootX);
+ ev->y_root = cvtINT16toInt(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 = cvtINT16toInt(event->u.keyButtonPointer.eventX);
+ ev->y = cvtINT16toInt(event->u.keyButtonPointer.eventY);
+ ev->x_root = cvtINT16toInt(event->u.keyButtonPointer.rootX);
+ ev->y_root = cvtINT16toInt(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 = cvtINT16toInt(event->u.keyButtonPointer.eventX);
+ ev->y = cvtINT16toInt(event->u.keyButtonPointer.eventY);
+ ev->x_root = cvtINT16toInt(event->u.keyButtonPointer.rootX);
+ ev->y_root = cvtINT16toInt(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 = cvtINT16toInt(event->u.enterLeave.eventX);
+ ev->y = cvtINT16toInt(event->u.enterLeave.eventY);
+ ev->x_root = cvtINT16toInt(event->u.enterLeave.rootX);
+ ev->y_root = cvtINT16toInt(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 = None;
+ memcpy(&ev->key_vector[1],
+ (char *)((xKeymapEvent *) event)->map,
+ 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 = cvtINT16toInt(event->u.createNotify.x);
+ ev->y = cvtINT16toInt(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 = cvtINT16toInt(event->u.reparent.x);
+ ev->y = cvtINT16toInt(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 = cvtINT16toInt(event->u.configureNotify.x);
+ ev->y = cvtINT16toInt(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 = cvtINT16toInt(event->u.configureRequest.x);
+ ev->y = cvtINT16toInt(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 = cvtINT16toInt(event->u.gravity.x);
+ ev->y = cvtINT16toInt(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] = cvtINT16toShort(event->u.clientMessage.u.s.shorts0);
+ ev->data.s[1] = cvtINT16toShort(event->u.clientMessage.u.s.shorts1);
+ ev->data.s[2] = cvtINT16toShort(event->u.clientMessage.u.s.shorts2);
+ ev->data.s[3] = cvtINT16toShort(event->u.clientMessage.u.s.shorts3);
+ ev->data.s[4] = cvtINT16toShort(event->u.clientMessage.u.s.shorts4);
+ ev->data.s[5] = cvtINT16toShort(event->u.clientMessage.u.s.shorts5);
+ ev->data.s[6] = cvtINT16toShort(event->u.clientMessage.u.s.shorts6);
+ ev->data.s[7] = cvtINT16toShort(event->u.clientMessage.u.s.shorts7);
+ ev->data.s[8] = cvtINT16toShort(event->u.clientMessage.u.s.shorts8);
+ ev->data.s[9] = cvtINT16toShort(event->u.clientMessage.u.s.shorts9);
+ break;
+ case 32:
+ ev->message_type = event->u.clientMessage.u.l.type;
+ ev->data.l[0] = cvtINT32toLong(event->u.clientMessage.u.l.longs0);
+ ev->data.l[1] = cvtINT32toLong(event->u.clientMessage.u.l.longs1);
+ ev->data.l[2] = cvtINT32toLong(event->u.clientMessage.u.l.longs2);
+ ev->data.l[3] = cvtINT32toLong(event->u.clientMessage.u.l.longs3);
+ ev->data.l[4] = cvtINT32toLong(event->u.clientMessage.u.l.longs4);
+ break;
+ default: /* XXX should never occur */
+ break;
+ }
+ }
+ break;
+ case MappingNotify:
+ {
+ register XMappingEvent *ev = (XMappingEvent *)re;
+ ev->window = 0;
+ 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);
+}
+
+
+/*
+ * _XDefaultIOError - Default fatal system error reporting routine. Called
+ * when an X internal system error is encountered.
+ */
+int _XDefaultIOError(
+ Display *dpy)
+{
+ if (ECHECK(EPIPE)) {
+ (void) fprintf (stderr,
+ "X connection to %s broken (explicit kill or server shutdown).\r\n",
+ DisplayString (dpy));
+ } else {
+ (void) fprintf (stderr,
+ "XIO: fatal IO error %d (%s) on X server \"%s\"\r\n",
+#ifdef WIN32
+ WSAGetLastError(), strerror(WSAGetLastError()),
+#else
+ errno, strerror (errno),
+#endif
+ DisplayString (dpy));
+ (void) fprintf (stderr,
+ " after %lu requests (%lu known processed) with %d events remaining.\r\n",
+ NextRequest(dpy) - 1, LastKnownRequestProcessed(dpy),
+ QLength(dpy));
+
+ }
+#ifdef NX_TRANS_SOCKET
+ if (_NXHandleDisplayError == 1)
+ {
+#ifdef NX_TRANS_TEST
+ fprintf(stderr, "_XDefaultIOError: Going to return from the error handler.\n");
+#endif
+ return 0;
+ }
+ else
+ {
+#ifdef NX_TRANS_TEST
+ fprintf(stderr, "_XDefaultIOError: Going to exit from the program.\n");
+#endif
+#ifdef NX_TRANS_EXIT
+ NXTransExit(1);
+#else
+ exit(1);
+#endif
+ }
+#else
+ exit(1);
+#endif /* #ifdef NX_TRANS_SOCKET */
+ /*NOTREACHED*/
+}
+
+
+static int _XPrintDefaultError(
+ Display *dpy,
+ XErrorEvent *event,
+ FILE *fp)
+{
+ char buffer[BUFSIZ];
+ char mesg[BUFSIZ];
+ char number[32];
+ const char *mtype = "XlibMessage";
+ register _XExtension *ext = (_XExtension *)NULL;
+ _XExtension *bext = (_XExtension *)NULL;
+ 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);
+ if (event->request_code < 128) {
+ snprintf(number, sizeof(number), "%d", event->request_code);
+ XGetErrorDatabaseText(dpy, "XRequest", number, "", buffer, BUFSIZ);
+ } else {
+ for (ext = dpy->ext_procs;
+ ext && (ext->codes.major_opcode != event->request_code);
+ ext = ext->next)
+ ;
+ if (ext) {
+ strncpy(buffer, ext->name, BUFSIZ);
+ buffer[BUFSIZ - 1] = '\0';
+ } else
+ buffer[0] = '\0';
+ }
+ (void) fprintf(fp, " (%s)\n", buffer);
+ if (event->request_code >= 128) {
+ XGetErrorDatabaseText(dpy, mtype, "MinorCode", "Request Minor code %d",
+ mesg, BUFSIZ);
+ fputs(" ", fp);
+ (void) fprintf(fp, mesg, event->minor_code);
+ if (ext) {
+ snprintf(mesg, sizeof(mesg), "%s.%d", ext->name, event->minor_code);
+ XGetErrorDatabaseText(dpy, "XRequest", mesg, "", buffer, BUFSIZ);
+ (void) fprintf(fp, " (%s)", buffer);
+ }
+ fputs("\n", fp);
+ }
+ if (event->error_code >= 128) {
+ /* kludge, try to find the extension that caused it */
+ buffer[0] = '\0';
+ for (ext = dpy->ext_procs; ext; ext = ext->next) {
+ if (ext->error_string)
+ (*ext->error_string)(dpy, event->error_code, &ext->codes,
+ buffer, BUFSIZ);
+ if (buffer[0]) {
+ bext = ext;
+ break;
+ }
+ if (ext->codes.first_error &&
+ ext->codes.first_error < (int)event->error_code &&
+ (!bext || ext->codes.first_error > bext->codes.first_error))
+ bext = ext;
+ }
+ if (bext)
+ snprintf(buffer, sizeof(buffer), "%s.%d", bext->name,
+ event->error_code - bext->codes.first_error);
+ else
+ strcpy(buffer, "Value");
+ XGetErrorDatabaseText(dpy, mtype, buffer, "", mesg, BUFSIZ);
+ if (mesg[0]) {
+ fputs(" ", fp);
+ (void) fprintf(fp, mesg, event->resourceid);
+ fputs("\n", fp);
+ }
+ /* let extensions try to print the values */
+ for (ext = dpy->ext_procs; ext; ext = ext->next) {
+ if (ext->error_values)
+ (*ext->error_values)(dpy, event, fp);
+ }
+ } else if ((event->error_code == BadWindow) ||
+ (event->error_code == BadPixmap) ||
+ (event->error_code == BadCursor) ||
+ (event->error_code == BadFont) ||
+ (event->error_code == BadDrawable) ||
+ (event->error_code == BadColor) ||
+ (event->error_code == BadGC) ||
+ (event->error_code == BadIDChoice) ||
+ (event->error_code == BadValue) ||
+ (event->error_code == BadAtom)) {
+ if (event->error_code == BadValue)
+ XGetErrorDatabaseText(dpy, mtype, "Value", "Value 0x%x",
+ mesg, BUFSIZ);
+ else if (event->error_code == BadAtom)
+ XGetErrorDatabaseText(dpy, mtype, "AtomID", "AtomID 0x%x",
+ mesg, BUFSIZ);
+ else
+ XGetErrorDatabaseText(dpy, mtype, "ResourceID", "ResourceID 0x%x",
+ mesg, BUFSIZ);
+ fputs(" ", fp);
+ (void) fprintf(fp, mesg, event->resourceid);
+ fputs("\n", fp);
+ }
+ XGetErrorDatabaseText(dpy, mtype, "ErrorSerial", "Error Serial #%d",
+ mesg, BUFSIZ);
+ fputs(" ", fp);
+ (void) fprintf(fp, mesg, event->serial);
+ XGetErrorDatabaseText(dpy, mtype, "CurrentSerial", "Current Serial #%d",
+ mesg, BUFSIZ);
+ fputs("\n ", fp);
+ (void) fprintf(fp, mesg, dpy->request);
+ fputs("\n", fp);
+ if (event->error_code == BadImplementation) return 0;
+ return 1;
+}
+
+int _XDefaultError(
+ Display *dpy,
+ XErrorEvent *event)
+{
+ if (_XPrintDefaultError (dpy, event, stderr) == 0) return 0;
+
+ /*
+ * Store in dpy flags that the client is exiting on an unhandled XError
+ * (pretend it is an IOError, since the application is dying anyway it
+ * does not make a difference).
+ * This is useful for _XReply not to hang if the application makes Xlib
+ * calls in _fini as part of process termination.
+ */
+ dpy->flags |= XlibDisplayIOError;
+
+ exit(1);
+ /*NOTREACHED*/
+}
+
+/*ARGSUSED*/
+Bool _XDefaultWireError(Display *display, XErrorEvent *he, xError *we)
+{
+ return True;
+}
+
+/*
+ * _XError - upcall internal or user protocol error handler
+ */
+int _XError (
+ Display *dpy,
+ register xError *rep)
+{
+ /*
+ * X_Error packet encountered! We need to unpack the error before
+ * giving it to the user.
+ */
+ XEvent event; /* make it a large event */
+ register _XAsyncHandler *async, *next;
+
+ event.xerror.serial = _XSetLastRequestRead(dpy, (xGenericReply *)rep);
+
+ for (async = dpy->async_handlers; async; async = next) {
+ next = async->next;
+ if ((*async->handler)(dpy, (xReply *)rep,
+ (char *)rep, SIZEOF(xError), async->data))
+ return 0;
+ }
+
+ event.xerror.display = dpy;
+ event.xerror.type = X_Error;
+ event.xerror.resourceid = rep->resourceID;
+ event.xerror.error_code = rep->errorCode;
+ event.xerror.request_code = rep->majorCode;
+ event.xerror.minor_code = rep->minorCode;
+ if (dpy->error_vec &&
+ !(*dpy->error_vec[rep->errorCode])(dpy, &event.xerror, rep))
+ return 0;
+ if (_XErrorFunction != NULL) {
+ int rtn_val;
+#if defined(XTHREADS) && !USE_XCB
+ if (dpy->lock)
+ (*dpy->lock->user_lock_display)(dpy);
+ UnlockDisplay(dpy);
+#endif /* XTHREADS && !USE_XCB */
+ rtn_val = (*_XErrorFunction)(dpy, (XErrorEvent *)&event); /* upcall */
+#if defined(XTHREADS) && !USE_XCB
+ LockDisplay(dpy);
+ if (dpy->lock)
+ (*dpy->lock->user_unlock_display)(dpy);
+#endif /* XTHREADS && !USE_XCB */
+ return rtn_val;
+ } else {
+ return _XDefaultError(dpy, (XErrorEvent *)&event);
+ }
+}
+
+/*
+ * _XIOError - call user connection error handler and exit
+ */
+int
+_XIOError (
+ Display *dpy)
+{
+ dpy->flags |= XlibDisplayIOError;
+#ifdef WIN32
+ errno = WSAGetLastError();
+#endif
+
+ /* This assumes that the thread calling exit will call any atexit handlers.
+ * If this does not hold, then an alternate solution would involve
+ * registering an atexit handler to take over the lock, which would only
+ * assume that the same thread calls all the atexit handlers. */
+#ifdef XTHREADS
+ if (dpy->lock)
+ (*dpy->lock->user_lock_display)(dpy);
+#endif
+ UnlockDisplay(dpy);
+
+ if (_XIOErrorFunction != NULL)
+ (*_XIOErrorFunction)(dpy);
+ else
+ _XDefaultIOError(dpy);
+#ifdef NX_TRANS_SOCKET
+ /*
+ * Check if we are supposed to return in the case
+ * of a display failure. The client which originated
+ * the X operation will have to check the value of
+ * the XlibDisplayIOError flag and handle appropria-
+ * tely the display disconnection.
+ */
+
+ if (_NXHandleDisplayError == 0)
+ {
+#ifdef NX_TRANS_EXIT
+ NXTransExit(1);
+#else
+ exit(1);
+#endif
+ }
+
+ /*
+ * We are going to return. Reset the display
+ * buffers. Further writes will be discarded.
+ */
+
+#ifdef NX_TRANS_TEST
+ fprintf(stderr, "_XIOError: Resetting the display buffer.\n");
+#endif
+
+ dpy->bufptr = dpy->buffer;
+ dpy->last_req = (char *) &_dummy_request;
+
+#ifdef NX_TRANS_TEST
+ fprintf(stderr, "_XIOError: Resetting the display flags.\n");
+#endif
+
+ dpy->flags &= ~XlibDisplayProcConni;
+ dpy->flags &= ~XlibDisplayPrivSync;
+ dpy->flags &= ~XlibDisplayReadEvents;
+ dpy->flags &= ~XlibDisplayWriting;
+ dpy->flags &= ~XlibDisplayReply;
+ /* shut up the compiler by returning something */
+ return 0;
+#else
+ exit (1);
+#endif
+ /*NOTREACHED*/
+}
+
+
+/*
+ * This routine can be used to (cheaply) get some memory within a single
+ * Xlib routine for scratch space. A single buffer is reused each time
+ * if possible. To be MT safe, you can only call this between a call to
+ * GetReq* and a call to Data* or _XSend*, or in a context when the thread
+ * is guaranteed to not unlock the display.
+ */
+char *_XAllocScratch(
+ register Display *dpy,
+ unsigned long nbytes)
+{
+ if (nbytes > dpy->scratch_length) {
+ Xfree (dpy->scratch_buffer);
+ dpy->scratch_buffer = Xmalloc(nbytes);
+ if (dpy->scratch_buffer)
+ dpy->scratch_length = nbytes;
+ else dpy->scratch_length = 0;
+ }
+ return (dpy->scratch_buffer);
+}
+
+/*
+ * Scratch space allocator you can call any time, multiple times, and be
+ * MT safe, but you must hand the buffer back with _XFreeTemp.
+ */
+char *_XAllocTemp(
+ register Display *dpy,
+ unsigned long nbytes)
+{
+ char *buf;
+
+ buf = _XAllocScratch(dpy, nbytes);
+ dpy->scratch_buffer = NULL;
+ dpy->scratch_length = 0;
+ return buf;
+}
+
+void _XFreeTemp(
+ register Display *dpy,
+ char *buf,
+ unsigned long nbytes)
+{
+
+ Xfree(dpy->scratch_buffer);
+ dpy->scratch_buffer = buf;
+ dpy->scratch_length = nbytes;
+}
+
+/*
+ * Given a visual id, find the visual structure for this id on this display.
+ */
+Visual *_XVIDtoVisual(
+ 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];
+ /* if nvisuals == 0 then visuals will be NULL */
+ for (k = 0; k < dp->nvisuals; k++) {
+ vp = &dp->visuals[k];
+ if (vp->visualid == id) return (vp);
+ }
+ }
+ }
+ return (NULL);
+}
+
+int
+XFree (void *data)
+{
+ Xfree (data);
+ return 1;
+}
+
+#ifdef _XNEEDBCOPYFUNC
+void _Xbcopy(b1, b2, length)
+ register char *b1, *b2;
+ register length;
+{
+ if (b1 < b2) {
+ b2 += length;
+ b1 += length;
+ while (length--)
+ *--b2 = *--b1;
+ } else {
+ while (length--)
+ *b2++ = *b1++;
+ }
+}
+#endif
+
+#ifdef DataRoutineIsProcedure
+void Data(
+ Display *dpy,
+ _Xconst char *data,
+ long len)
+{
+ if (dpy->bufptr + (len) <= dpy->bufmax) {
+ memcpy(dpy->bufptr, data, (int)len);
+ dpy->bufptr += ((len) + 3) & ~3;
+ } else {
+ _XSend(dpy, data, len);
+ }
+}
+#endif /* DataRoutineIsProcedure */
+
+
+#ifdef LONG64
+int
+_XData32(
+ Display *dpy,
+ register _Xconst long *data,
+ unsigned len)
+{
+ register int *buf;
+ register long i;
+
+ while (len) {
+ buf = (int *)dpy->bufptr;
+ i = dpy->bufmax - (char *)buf;
+ if (!i) {
+ _XFlush(dpy);
+ continue;
+ }
+ if (len < i)
+ i = len;
+ dpy->bufptr = (char *)buf + i;
+ len -= i;
+ i >>= 2;
+ while (--i >= 0)
+ *buf++ = *data++;
+ }
+ return 0;
+}
+#endif /* LONG64 */
+
+
+
+/* Make sure this produces the same string as DefineLocal/DefineSelf in xdm.
+ * Otherwise, Xau will not be able to find your cookies in the Xauthority file.
+ *
+ * Note: POSIX says that the ``nodename'' member of utsname does _not_ have
+ * to have sufficient information for interfacing to the network,
+ * and so, you may be better off using gethostname (if it exists).
+ */
+
+#if defined(_POSIX_SOURCE) || defined(SVR4)
+#define NEED_UTSNAME
+#include <sys/utsname.h>
+#else
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#endif
+
+/*
+ * _XGetHostname - similar to gethostname but allows special processing.
+ */
+int _XGetHostname (
+ char *buf,
+ int maxlen)
+{
+ int len;
+
+#ifdef NEED_UTSNAME
+ struct utsname name;
+
+ if (maxlen <= 0 || buf == NULL)
+ return 0;
+
+ uname (&name);
+ len = strlen (name.nodename);
+ if (len >= maxlen) len = maxlen - 1;
+ strncpy (buf, name.nodename, len);
+ buf[len] = '\0';
+#else
+ if (maxlen <= 0 || buf == NULL)
+ return 0;
+
+ buf[0] = '\0';
+ (void) gethostname (buf, maxlen);
+ buf [maxlen - 1] = '\0';
+ len = strlen(buf);
+#endif /* NEED_UTSNAME */
+ return len;
+}
+
+
+/*
+ * _XScreenOfWindow - get the Screen of a given window
+ */
+
+Screen *_XScreenOfWindow(Display *dpy, Window w)
+{
+ register int i;
+ Window root;
+ int x, y; /* dummy variables */
+ unsigned int width, height, bw, depth; /* dummy variables */
+
+ if (XGetGeometry (dpy, w, &root, &x, &y, &width, &height,
+ &bw, &depth) == False) {
+ return NULL;
+ }
+ for (i = 0; i < ScreenCount (dpy); i++) { /* find root from list */
+ if (root == RootWindow (dpy, i)) {
+ return ScreenOfDisplay (dpy, i);
+ }
+ }
+ return NULL;
+}
+
+/*
+ * WARNING: This implementation's pre-conditions and post-conditions
+ * must remain compatible with the old macro-based implementations of
+ * GetReq, GetReqExtra, GetResReq, and GetEmptyReq. The portions of the
+ * Display structure affected by those macros are part of libX11's
+ * ABI.
+ */
+void *_XGetRequest(Display *dpy, CARD8 type, size_t len)
+{
+ xReq *req;
+
+ if (dpy->bufptr + len > dpy->bufmax)
+ _XFlush(dpy);
+ /* Request still too large, so do not allow it to overflow. */
+ if (dpy->bufptr + len > dpy->bufmax) {
+ fprintf(stderr,
+ "Xlib: request %d length %zd would exceed buffer size.\n",
+ type, len);
+ /* Changes failure condition from overflow to NULL dereference. */
+ return NULL;
+ }
+
+ if (len % 4)
+ fprintf(stderr,
+ "Xlib: request %d length %zd not a multiple of 4.\n",
+ type, len);
+
+ dpy->last_req = dpy->bufptr;
+
+ req = (xReq*)dpy->bufptr;
+ req->reqType = type;
+ req->length = len / 4;
+ dpy->bufptr += len;
+ dpy->request++;
+ return req;
+}
+
+#if defined(WIN32)
+
+/*
+ * These functions are intended to be used internally to Xlib only.
+ * These functions will always prefix the path with a DOS drive in the
+ * form "<drive-letter>:". As such, these functions are only suitable
+ * for use by Xlib function that supply a root-based path to some
+ * particular file, e.g. <ProjectRoot>/lib/X11/locale/locale.dir will
+ * be converted to "C:/usr/X11R6.3/lib/X11/locale/locale.dir".
+ */
+
+static int access_file (path, pathbuf, len_pathbuf, pathret)
+ char* path;
+ char* pathbuf;
+ int len_pathbuf;
+ char** pathret;
+{
+ if (access (path, F_OK) == 0) {
+ if (strlen (path) < len_pathbuf)
+ *pathret = pathbuf;
+ else
+ *pathret = Xmalloc (strlen (path) + 1);
+ if (*pathret) {
+ strcpy (*pathret, path);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int AccessFile (path, pathbuf, len_pathbuf, pathret)
+ char* path;
+ char* pathbuf;
+ int len_pathbuf;
+ char** pathret;
+{
+ unsigned long drives;
+ int i, len;
+ char* drive;
+ char buf[MAX_PATH];
+ char* bufp;
+
+ /* just try the "raw" name first and see if it works */
+ if (access_file (path, pathbuf, len_pathbuf, pathret))
+ return 1;
+
+ /* try the places set in the environment */
+ drive = getenv ("_XBASEDRIVE");
+ if (!drive)
+ drive = "C:";
+ len = strlen (drive) + strlen (path);
+ if (len < MAX_PATH) bufp = buf;
+ else bufp = Xmalloc (len + 1);
+ strcpy (bufp, drive);
+ strcat (bufp, path);
+ if (access_file (bufp, pathbuf, len_pathbuf, pathret)) {
+ if (bufp != buf) Xfree (bufp);
+ return 1;
+ }
+
+ /* one last place to look */
+ drive = getenv ("HOMEDRIVE");
+ if (drive) {
+ len = strlen (drive) + strlen (path);
+ if (len < MAX_PATH) bufp = buf;
+ else bufp = Xmalloc (len + 1);
+ strcpy (bufp, drive);
+ strcat (bufp, path);
+ if (access_file (bufp, pathbuf, len_pathbuf, pathret)) {
+ if (bufp != buf) Xfree (bufp);
+ return 1;
+ }
+ }
+
+ /* tried everywhere else, go fishing */
+#define C_DRIVE ('C' - 'A')
+#define Z_DRIVE ('Z' - 'A')
+ /* does OS/2 (with or with gcc-emx) have getdrives? */
+ drives = _getdrives ();
+ for (i = C_DRIVE; i <= Z_DRIVE; i++) { /* don't check on A: or B: */
+ if ((1 << i) & drives) {
+ len = 2 + strlen (path);
+ if (len < MAX_PATH) bufp = buf;
+ else bufp = Xmalloc (len + 1);
+ *bufp = 'A' + i;
+ *(bufp + 1) = ':';
+ *(bufp + 2) = '\0';
+ strcat (bufp, path);
+ if (access_file (bufp, pathbuf, len_pathbuf, pathret)) {
+ if (bufp != buf) Xfree (bufp);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+int _XOpenFile(path, flags)
+ _Xconst char* path;
+ int flags;
+{
+ char buf[MAX_PATH];
+ char* bufp = NULL;
+ int ret = -1;
+ UINT olderror = SetErrorMode (SEM_FAILCRITICALERRORS);
+
+ if (AccessFile (path, buf, MAX_PATH, &bufp))
+ ret = open (bufp, flags);
+
+ (void) SetErrorMode (olderror);
+
+ if (bufp != buf) Xfree (bufp);
+
+ return ret;
+}
+
+int _XOpenFileMode(path, flags, mode)
+ _Xconst char* path;
+ int flags;
+ mode_t mode;
+{
+ char buf[MAX_PATH];
+ char* bufp = NULL;
+ int ret = -1;
+ UINT olderror = SetErrorMode (SEM_FAILCRITICALERRORS);
+
+ if (AccessFile (path, buf, MAX_PATH, &bufp))
+ ret = open (bufp, flags, mode);
+
+ (void) SetErrorMode (olderror);
+
+ if (bufp != buf) Xfree (bufp);
+
+ return ret;
+}
+
+void* _XFopenFile(path, mode)
+ _Xconst char* path;
+ _Xconst char* mode;
+{
+ char buf[MAX_PATH];
+ char* bufp = NULL;
+ void* ret = NULL;
+ UINT olderror = SetErrorMode (SEM_FAILCRITICALERRORS);
+
+ if (AccessFile (path, buf, MAX_PATH, &bufp))
+ ret = fopen (bufp, mode);
+
+ (void) SetErrorMode (olderror);
+
+ if (bufp != buf) Xfree (bufp);
+
+ return ret;
+}
+
+int _XAccessFile(path)
+ _Xconst char* path;
+{
+ char buf[MAX_PATH];
+ char* bufp;
+ int ret = -1;
+ UINT olderror = SetErrorMode (SEM_FAILCRITICALERRORS);
+
+ ret = AccessFile (path, buf, MAX_PATH, &bufp);
+
+ (void) SetErrorMode (olderror);
+
+ if (bufp != buf) Xfree (bufp);
+
+ return ret;
+}
+
+#endif
+
+#ifdef WIN32
+#undef _Xdebug
+int _Xdebug = 0;
+int *_Xdebug_p = &_Xdebug;
+void (**_XCreateMutex_fn_p)(LockInfoPtr) = &_XCreateMutex_fn;
+void (**_XFreeMutex_fn_p)(LockInfoPtr) = &_XFreeMutex_fn;
+void (**_XLockMutex_fn_p)(LockInfoPtr
+#if defined(XTHREADS_WARN) || defined(XTHREADS_FILE_LINE)
+ , char * /* file */
+ , int /* line */
+#endif
+ ) = &_XLockMutex_fn;
+void (**_XUnlockMutex_fn_p)(LockInfoPtr
+#if defined(XTHREADS_WARN) || defined(XTHREADS_FILE_LINE)
+ , char * /* file */
+ , int /* line */
+#endif
+ ) = &_XUnlockMutex_fn;
+LockInfoPtr *_Xglobal_lock_p = &_Xglobal_lock;
+#endif