From c350873c7c977efe5210484f04160be45f84ba7e Mon Sep 17 00:00:00 2001 From: Mike Gabriel Date: Fri, 21 Jul 2017 12:31:09 +0200 Subject: Convert nx-X11/lib/ build flow from imake to autotools. --- nx-X11/lib/src/XlibInt.c | 4199 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 4199 insertions(+) create mode 100644 nx-X11/lib/src/XlibInt.c (limited to 'nx-X11/lib/src/XlibInt.c') 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 */ +/* Copyright (c) 2011-2016 Mike Gabriel */ +/* Copyright (c) 2014-2016 Mihai Moldovan */ +/* Copyright (c) 2014-2016 Ulrich Sibiller */ +/* 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 +#endif +#include "Xlibint.h" +#include "Xprivate.h" +#include +#if !USE_XCB +#include +#include +#endif /* !USE_XCB */ +#include +#include +#ifdef WIN32 +#include +#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 +#include + +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 /* for LONG64 on 64-bit platforms */ +#include + +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 +#else +#ifdef HAVE_UNISTD_H +#include +#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 ":". As such, these functions are only suitable + * for use by Xlib function that supply a root-based path to some + * particular file, e.g. /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 -- cgit v1.2.3