XlibInt.c revision 61b2299d
1/* $Xorg: XlibInt.c,v 1.8 2001/02/09 02:03:38 xorgcvs Exp $ */
2/*
3
4Copyright 1985, 1986, 1987, 1998  The Open Group
5
6Permission to use, copy, modify, distribute, and sell this software and its
7documentation for any purpose is hereby granted without fee, provided that
8the above copyright notice appear in all copies and that both that
9copyright notice and this permission notice appear in supporting
10documentation.
11
12The above copyright notice and this permission notice shall be included
13in all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
19OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21OTHER DEALINGS IN THE SOFTWARE.
22
23Except as contained in this notice, the name of The Open Group shall
24not be used in advertising or otherwise to promote the sale, use or
25other dealings in this Software without prior written authorization
26from The Open Group.
27
28*/
29/* $XFree86: xc/lib/X11/XlibInt.c,v 3.38 2003/10/30 21:55:05 alanh Exp $ */
30
31/*
32 *	XlibInt.c - Internal support routines for the C subroutine
33 *	interface library (Xlib) to the X Window System Protocol V11.0.
34 */
35#define NEED_EVENTS
36#define NEED_REPLIES
37
38#ifdef WIN32
39#define _XLIBINT_
40#endif
41#ifdef HAVE_CONFIG_H
42#include <config.h>
43#endif
44#include "Xlibint.h"
45#include "Xprivate.h"
46#include <X11/Xpoll.h>
47#if !USE_XCB
48#include <X11/Xtrans/Xtrans.h>
49#include <X11/extensions/xcmiscstr.h>
50#endif /* !USE_XCB */
51#include <assert.h>
52#include <stdio.h>
53#ifdef WIN32
54#include <direct.h>
55#endif
56
57#ifdef XTHREADS
58#include "locking.h"
59
60/* these pointers get initialized by XInitThreads */
61LockInfoPtr _Xglobal_lock = NULL;
62void (*_XCreateMutex_fn)(LockInfoPtr) = NULL;
63/* struct _XCVList *(*_XCreateCVL_fn)() = NULL; */
64void (*_XFreeMutex_fn)(LockInfoPtr) = NULL;
65void (*_XLockMutex_fn)(
66    LockInfoPtr /* lock */
67#if defined(XTHREADS_WARN) || defined(XTHREADS_FILE_LINE)
68    , char * /* file */
69    , int /* line */
70#endif
71    ) = NULL;
72void (*_XUnlockMutex_fn)(
73    LockInfoPtr /* lock */
74#if defined(XTHREADS_WARN) || defined(XTHREADS_FILE_LINE)
75    , char * /* file */
76    , int /* line */
77#endif
78    ) = NULL;
79xthread_t (*_Xthread_self_fn)(void) = NULL;
80
81#define XThread_Self()	((*_Xthread_self_fn)())
82
83#if !USE_XCB
84#define UnlockNextReplyReader(d) if ((d)->lock) \
85    (*(d)->lock->pop_reader)((d),&(d)->lock->reply_awaiters,&(d)->lock->reply_awaiters_tail)
86
87#define QueueReplyReaderLock(d) ((d)->lock ? \
88    (*(d)->lock->push_reader)(d,&(d)->lock->reply_awaiters_tail) : NULL)
89#define QueueEventReaderLock(d) ((d)->lock ? \
90    (*(d)->lock->push_reader)(d,&(d)->lock->event_awaiters_tail) : NULL)
91
92#if defined(XTHREADS_WARN) || defined(XTHREADS_FILE_LINE)
93#define InternalLockDisplay(d,wskip) if ((d)->lock) \
94    (*(d)->lock->internal_lock_display)(d,wskip,__FILE__,__LINE__)
95#else
96#define InternalLockDisplay(d,wskip) if ((d)->lock) \
97    (*(d)->lock->internal_lock_display)(d,wskip)
98#endif
99#endif /* !USE_XCB */
100
101#else /* XTHREADS else */
102
103#if !USE_XCB
104#define UnlockNextReplyReader(d)
105#define UnlockNextEventReader(d)
106#define InternalLockDisplay(d,wskip)
107#endif /* !USE_XCB */
108
109#endif /* XTHREADS else */
110
111/* check for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX
112 * systems are broken and return EWOULDBLOCK when they should return EAGAIN
113 */
114#ifdef WIN32
115#define ETEST() (WSAGetLastError() == WSAEWOULDBLOCK)
116#else
117#ifdef __CYGWIN__ /* Cygwin uses ENOBUFS to signal socket is full */
118#define ETEST() (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
119#else
120#if defined(EAGAIN) && defined(EWOULDBLOCK)
121#define ETEST() (errno == EAGAIN || errno == EWOULDBLOCK)
122#else
123#ifdef EAGAIN
124#define ETEST() (errno == EAGAIN)
125#else
126#define ETEST() (errno == EWOULDBLOCK)
127#endif /* EAGAIN */
128#endif /* EAGAIN && EWOULDBLOCK */
129#endif /* __CYGWIN__ */
130#endif /* WIN32 */
131
132#ifdef WIN32
133#define ECHECK(err) (WSAGetLastError() == err)
134#define ESET(val) WSASetLastError(val)
135#else
136#ifdef __UNIXOS2__
137#define ECHECK(err) (errno == err)
138#define ESET(val)
139#else
140#ifdef ISC
141#define ECHECK(err) ((errno == err) || ETEST())
142#else
143#define ECHECK(err) (errno == err)
144#endif
145#define ESET(val) errno = val
146#endif
147#endif
148
149#if defined(LOCALCONN) || defined(LACHMAN)
150#ifdef EMSGSIZE
151#define ESZTEST() (ECHECK(EMSGSIZE) || ECHECK(ERANGE))
152#else
153#define ESZTEST() ECHECK(ERANGE)
154#endif
155#else
156#ifdef EMSGSIZE
157#define ESZTEST() ECHECK(EMSGSIZE)
158#endif
159#endif
160
161#ifdef __UNIXOS2__
162#if !USE_XCB
163#define select(n,r,w,x,t) os2ClientSelect(n,r,w,x,t)
164#endif /* !USE_XCB */
165#include <limits.h>
166#define MAX_PATH _POSIX_PATH_MAX
167#endif
168
169#if !USE_XCB
170#ifdef MUSTCOPY
171
172#define STARTITERATE(tpvar,type,start,endcond) \
173  { register char *cpvar; \
174  for (cpvar = (char *) (start); endcond; ) { \
175    type dummy; memcpy ((char *) &dummy, cpvar, SIZEOF(type)); \
176    tpvar = &dummy;
177#define ITERPTR(tpvar) cpvar
178#define RESETITERPTR(tpvar,type,start) cpvar = start
179#define INCITERPTR(tpvar,type) cpvar += SIZEOF(type)
180#define ENDITERATE }}
181
182#else
183
184#define STARTITERATE(tpvar,type,start,endcond) \
185  for (tpvar = (type *) (start); endcond; )
186#define ITERPTR(tpvar) (char *)tpvar
187#define RESETITERPTR(tpvar,type,start) tpvar = (type *) (start)
188#define INCITERPTR(tpvar,type) tpvar++
189#define ENDITERATE
190
191#endif /* MUSTCOPY */
192
193typedef union {
194    xReply rep;
195    char buf[BUFSIZE];
196} _XAlignedBuffer;
197
198static char *_XAsyncReply(
199    Display *dpy,
200    register xReply *rep,
201    char *buf,
202    register int *lenp,
203    Bool discard);
204#endif /* !USE_XCB */
205
206/*
207 * The following routines are internal routines used by Xlib for protocol
208 * packet transmission and reception.
209 *
210 * _XIOError(Display *) will be called if any sort of system call error occurs.
211 * This is assumed to be a fatal condition, i.e., XIOError should not return.
212 *
213 * _XError(Display *, xError *) will be called whenever an X_Error event is
214 * received.  This is not assumed to be a fatal condition, i.e., it is
215 * acceptable for this procedure to return.  However, XError should NOT
216 * perform any operations (directly or indirectly) on the DISPLAY.
217 *
218 * Routines declared with a return type of 'Status' return 0 on failure,
219 * and non 0 on success.  Routines with no declared return type don't
220 * return anything.  Whenever possible routines that create objects return
221 * the object they have created.
222 */
223
224#if !USE_XCB
225static xReq _dummy_request = {
226	0, 0, 0
227};
228
229/*
230 * This is an OS dependent routine which:
231 * 1) returns as soon as the connection can be written on....
232 * 2) if the connection can be read, must enqueue events and handle errors,
233 * until the connection is writable.
234 */
235static void
236_XWaitForWritable(
237    Display *dpy
238#ifdef XTHREADS
239    ,
240    xcondition_t cv		/* our reading condition variable */
241#endif
242    )
243{
244#ifdef USE_POLL
245    struct pollfd filedes;
246#else
247    fd_set r_mask;
248    fd_set w_mask;
249#endif
250    int nfound;
251
252#ifdef USE_POLL
253    filedes.fd = dpy->fd;
254    filedes.events = 0;
255#else
256    FD_ZERO(&r_mask);
257    FD_ZERO(&w_mask);
258#endif
259
260    for (;;) {
261#ifdef XTHREADS
262	/* We allow only one thread at a time to read, to minimize
263	   passing of read data between threads.
264	   Now, who is it?  If there is a non-NULL reply_awaiters and
265	   we (i.e., our cv) are not at the head of it, then whoever
266	   is at the head is the reader, and we don't read.
267	   Otherwise there is no reply_awaiters or we are at the
268	   head, having just appended ourselves.
269	   In this case, if there is a event_awaiters, then whoever
270	   is at the head of it got there before we did, and they are the
271	   reader.
272
273	   Last cases: no event_awaiters and we are at the head of
274	   reply_awaiters or reply_awaiters is NULL: we are the reader,
275	   since there is obviously no one else involved.
276
277	   XXX - what if cv is NULL and someone else comes along after
278	   us while we are waiting?
279	   */
280
281	if (!dpy->lock ||
282	    (!dpy->lock->event_awaiters &&
283	     (!dpy->lock->reply_awaiters ||
284	      dpy->lock->reply_awaiters->cv == cv)))
285#endif
286#ifdef USE_POLL
287	    filedes.events = POLLIN;
288	filedes.events |= POLLOUT;
289#else
290	FD_SET(dpy->fd, &r_mask);
291        FD_SET(dpy->fd, &w_mask);
292#endif
293
294	do {
295	    UnlockDisplay(dpy);
296#ifdef USE_POLL
297	    nfound = poll (&filedes, 1, -1);
298#else
299	    nfound = Select (dpy->fd + 1, &r_mask, &w_mask, NULL, NULL);
300#endif
301	    InternalLockDisplay(dpy, cv != NULL);
302	    if (nfound < 0 && !ECHECK(EINTR))
303		_XIOError(dpy);
304	} while (nfound <= 0);
305
306	if (
307#ifdef USE_POLL
308	    filedes.revents & POLLIN
309#else
310	    FD_ISSET(dpy->fd, &r_mask)
311#endif
312	    )
313	{
314	    _XAlignedBuffer buf;
315	    BytesReadable_t pend;
316	    register int len;
317	    register xReply *rep;
318
319	    /* find out how much data can be read */
320	    if (_X11TransBytesReadable(dpy->trans_conn, &pend) < 0)
321		_XIOError(dpy);
322	    len = pend;
323
324	    /* must read at least one xEvent; if none is pending, then
325	       we'll just block waiting for it */
326	    if (len < SIZEOF(xReply)
327#ifdef XTHREADS
328		|| dpy->async_handlers
329#endif
330		)
331		len = SIZEOF(xReply);
332
333	    /* but we won't read more than the max buffer size */
334	    if (len > BUFSIZE) len = BUFSIZE;
335
336	    /* round down to an integral number of XReps */
337	    len = (len / SIZEOF(xReply)) * SIZEOF(xReply);
338
339	    (void) _XRead (dpy, buf.buf, (long) len);
340
341	    STARTITERATE(rep,xReply,buf.buf,len > 0) {
342		if (rep->generic.type == X_Reply) {
343                    int tmp = len;
344		    RESETITERPTR(rep,xReply,
345				 _XAsyncReply (dpy, rep,
346					       ITERPTR(rep), &tmp, True));
347                    len = tmp;
348		    pend = len;
349		} else {
350		    if (rep->generic.type == X_Error)
351			_XError (dpy, (xError *)rep);
352		    else	/* must be an event packet */
353			_XEnq (dpy, (xEvent *)rep);
354		    INCITERPTR(rep,xReply);
355		    len -= SIZEOF(xReply);
356		}
357	    } ENDITERATE
358#ifdef XTHREADS
359	    if (dpy->lock && dpy->lock->event_awaiters)
360		ConditionSignal(dpy, dpy->lock->event_awaiters->cv);
361#endif
362	}
363#ifdef USE_POLL
364	if (filedes.revents & (POLLOUT|POLLHUP|POLLERR))
365#else
366	if (FD_ISSET(dpy->fd, &w_mask))
367#endif
368	{
369#ifdef XTHREADS
370	    if (dpy->lock) {
371		ConditionBroadcast(dpy, dpy->lock->writers);
372	    }
373#endif
374	    return;
375	}
376    }
377}
378#endif /* !USE_XCB */
379
380
381#define POLLFD_CACHE_SIZE 5
382
383/* initialize the struct array passed to poll() below */
384Bool _XPollfdCacheInit(
385    Display *dpy)
386{
387#ifdef USE_POLL
388    struct pollfd *pfp;
389
390    pfp = (struct pollfd *)Xmalloc(POLLFD_CACHE_SIZE * sizeof(struct pollfd));
391    if (!pfp)
392	return False;
393    pfp[0].fd = dpy->fd;
394    pfp[0].events = POLLIN;
395
396    dpy->filedes = (XPointer)pfp;
397#endif
398    return True;
399}
400
401void _XPollfdCacheAdd(
402    Display *dpy,
403    int fd)
404{
405#ifdef USE_POLL
406    struct pollfd *pfp = (struct pollfd *)dpy->filedes;
407
408    if (dpy->im_fd_length <= POLLFD_CACHE_SIZE) {
409	pfp[dpy->im_fd_length].fd = fd;
410	pfp[dpy->im_fd_length].events = POLLIN;
411    }
412#endif
413}
414
415/* ARGSUSED */
416void _XPollfdCacheDel(
417    Display *dpy,
418    int fd)			/* not used */
419{
420#ifdef USE_POLL
421    struct pollfd *pfp = (struct pollfd *)dpy->filedes;
422    struct _XConnectionInfo *conni;
423
424    /* just recalculate whole list */
425    if (dpy->im_fd_length <= POLLFD_CACHE_SIZE) {
426	int loc = 1;
427	for (conni = dpy->im_fd_info; conni; conni=conni->next) {
428	    pfp[loc].fd = conni->fd;
429	    pfp[loc].events = POLLIN;
430	    loc++;
431	}
432    }
433#endif
434}
435
436#if !USE_XCB
437/* returns True iff there is an event in the queue newer than serial_num */
438
439static Bool
440_XNewerQueuedEvent(
441    Display *dpy,
442    int serial_num)
443{
444    _XQEvent *qev;
445
446    if (dpy->next_event_serial_num == serial_num)
447	return False;
448
449    qev = dpy->head;
450    while (qev) {
451	if (qev->qserial_num >= serial_num) {
452	    return True;
453	}
454	qev = qev->next;
455    }
456    return False;
457}
458
459static int
460_XWaitForReadable(
461  Display *dpy)
462{
463    int result;
464    int fd = dpy->fd;
465    struct _XConnectionInfo *ilist;
466    register int saved_event_serial = 0;
467    int in_read_events = 0;
468    register Bool did_proc_conni = False;
469#ifdef USE_POLL
470    struct pollfd *filedes;
471#else
472    fd_set r_mask;
473    int highest_fd = fd;
474#endif
475
476#ifdef USE_POLL
477    if (dpy->im_fd_length + 1 > POLLFD_CACHE_SIZE
478	&& !(dpy->flags & XlibDisplayProcConni)) {
479	/* XXX - this fallback is gross */
480	int i;
481
482	filedes = (struct pollfd *)Xmalloc(dpy->im_fd_length * sizeof(struct pollfd));
483	filedes[0].fd = fd;
484	filedes[0].events = POLLIN;
485	for (ilist=dpy->im_fd_info, i=1; ilist; ilist=ilist->next, i++) {
486	    filedes[i].fd = ilist->fd;
487	    filedes[i].events = POLLIN;
488	}
489    } else {
490	filedes = (struct pollfd *)dpy->filedes;
491    }
492#else
493    FD_ZERO(&r_mask);
494#endif
495    for (;;) {
496#ifndef USE_POLL
497	FD_SET(fd, &r_mask);
498	if (!(dpy->flags & XlibDisplayProcConni))
499	    for (ilist=dpy->im_fd_info; ilist; ilist=ilist->next) {
500		FD_SET(ilist->fd, &r_mask);
501		if (ilist->fd > highest_fd)
502		    highest_fd = ilist->fd;
503	    }
504#endif
505	UnlockDisplay(dpy);
506#ifdef USE_POLL
507	result = poll(filedes,
508		      (dpy->flags & XlibDisplayProcConni) ? 1 : 1+dpy->im_fd_length,
509		      -1);
510#else
511	result = Select(highest_fd + 1, &r_mask, NULL, NULL, NULL);
512#endif
513	InternalLockDisplay(dpy, dpy->flags & XlibDisplayReply);
514	if (result == -1 && !ECHECK(EINTR)) _XIOError(dpy);
515	if (result <= 0)
516	    continue;
517#ifdef USE_POLL
518	if (filedes[0].revents & (POLLIN|POLLHUP|POLLERR))
519#else
520	if (FD_ISSET(fd, &r_mask))
521#endif
522	    break;
523	if (!(dpy->flags & XlibDisplayProcConni)) {
524	    int i;
525
526	    saved_event_serial = dpy->next_event_serial_num;
527	    /* dpy flags can be clobbered by internal connection callback */
528	    in_read_events = dpy->flags & XlibDisplayReadEvents;
529	    for (ilist=dpy->im_fd_info, i=1; ilist; ilist=ilist->next, i++) {
530#ifdef USE_POLL
531		if (filedes[i].revents & POLLIN)
532#else
533		if (FD_ISSET(ilist->fd, &r_mask))
534#endif
535		{
536		    _XProcessInternalConnection(dpy, ilist);
537		    did_proc_conni = True;
538		}
539	    }
540#ifdef USE_POLL
541	    if (dpy->im_fd_length + 1 > POLLFD_CACHE_SIZE)
542		Xfree(filedes);
543#endif
544	}
545	if (did_proc_conni) {
546	    /* some internal connection callback might have done an
547	       XPutBackEvent.  We notice it here and if we needed an event,
548	       we can return all the way. */
549	    if (_XNewerQueuedEvent(dpy, saved_event_serial)
550		&& (in_read_events
551#ifdef XTHREADS
552		    || (dpy->lock && dpy->lock->event_awaiters)
553#endif
554		    ))
555		return -2;
556	    did_proc_conni = False;
557	}
558    }
559#ifdef XTHREADS
560#ifdef XTHREADS_DEBUG
561    printf("thread %x _XWaitForReadable returning\n", XThread_Self());
562#endif
563#endif
564    return 0;
565}
566#endif /* !USE_XCB */
567
568static int sync_hazard(Display *dpy)
569{
570    unsigned long span = dpy->request - dpy->last_request_read;
571    unsigned long hazard = min((dpy->bufmax - dpy->buffer) / SIZEOF(xReq), 65535 - 10);
572    return span >= 65535 - hazard - 10;
573}
574
575static
576int _XSeqSyncFunction(
577    register Display *dpy)
578{
579    xGetInputFocusReply rep;
580    register xReq *req;
581    int sent_sync = 0;
582
583    LockDisplay(dpy);
584    if ((dpy->request - dpy->last_request_read) >= (65535 - BUFSIZE/SIZEOF(xReq))) {
585	GetEmptyReq(GetInputFocus, req);
586	(void) _XReply (dpy, (xReply *)&rep, 0, xTrue);
587	sent_sync = 1;
588    } else if (sync_hazard(dpy))
589	_XSetPrivSyncFunction(dpy);
590    UnlockDisplay(dpy);
591    if (sent_sync)
592        SyncHandle();
593    return 0;
594}
595
596static int
597_XPrivSyncFunction (Display *dpy)
598{
599    assert(dpy->synchandler == _XPrivSyncFunction);
600    assert((dpy->flags & XlibDisplayPrivSync) != 0);
601    dpy->synchandler = dpy->savedsynchandler;
602    dpy->savedsynchandler = NULL;
603    dpy->flags &= ~XlibDisplayPrivSync;
604    _XIDHandler(dpy);
605    _XSeqSyncFunction(dpy);
606    return 0;
607}
608
609void _XSetPrivSyncFunction(Display *dpy)
610{
611    if (!(dpy->flags & XlibDisplayPrivSync)) {
612	dpy->savedsynchandler = dpy->synchandler;
613	dpy->synchandler = _XPrivSyncFunction;
614	dpy->flags |= XlibDisplayPrivSync;
615    }
616}
617
618void _XSetSeqSyncFunction(Display *dpy)
619{
620    if (sync_hazard(dpy))
621	_XSetPrivSyncFunction (dpy);
622}
623
624#if !USE_XCB
625#ifdef XTHREADS
626static void _XFlushInt(
627        register Display *dpy,
628        register xcondition_t cv);
629#endif
630
631/*
632 * _XFlush - Flush the X request buffer.  If the buffer is empty, no
633 * action is taken.  This routine correctly handles incremental writes.
634 * This routine may have to be reworked if int < long.
635 */
636void _XFlush(
637	register Display *dpy)
638{
639#ifdef XTHREADS
640    /* With multi-threading we introduce an internal routine to which
641       we can pass a condition variable to do locking correctly. */
642
643    _XFlushInt(dpy, NULL);
644}
645
646/* _XFlushInt - Internal version of _XFlush used to do multi-threaded
647 * locking correctly.
648 */
649
650static void _XFlushInt(
651	register Display *dpy,
652        register xcondition_t cv)
653{
654#endif /* XTHREADS*/
655	register long size, todo;
656	register int write_stat;
657	register char *bufindex;
658	_XExtension *ext;
659
660	/* This fix resets the bufptr to the front of the buffer so
661	 * additional appends to the bufptr will not corrupt memory. Since
662	 * the server is down, these appends are no-op's anyway but
663	 * callers of _XFlush() are not verifying this before they call it.
664	 */
665	if (dpy->flags & XlibDisplayIOError)
666	{
667	    dpy->bufptr = dpy->buffer;
668	    dpy->last_req = (char *)&_dummy_request;
669	    return;
670	}
671
672#ifdef XTHREADS
673	while (dpy->flags & XlibDisplayWriting) {
674	    if (dpy->lock) {
675		ConditionWait(dpy, dpy->lock->writers);
676	    } else {
677		_XWaitForWritable (dpy, cv);
678	    }
679	}
680#endif
681	size = todo = dpy->bufptr - dpy->buffer;
682	if (!size) return;
683#ifdef XTHREADS
684	dpy->flags |= XlibDisplayWriting;
685	/* make sure no one else can put in data */
686	dpy->bufptr = dpy->bufmax;
687#endif
688	for (ext = dpy->flushes; ext; ext = ext->next_flush)
689	    (*ext->before_flush)(dpy, &ext->codes, dpy->buffer, size);
690	bufindex = dpy->buffer;
691	/*
692	 * While write has not written the entire buffer, keep looping
693	 * until the entire buffer is written.  bufindex will be
694	 * incremented and size decremented as buffer is written out.
695	 */
696	while (size) {
697	    ESET(0);
698	    write_stat = _X11TransWrite(dpy->trans_conn,
699					bufindex, (int) todo);
700	    if (write_stat >= 0) {
701		size -= write_stat;
702		todo = size;
703		bufindex += write_stat;
704	    } else if (ETEST()) {
705		_XWaitForWritable(dpy
706#ifdef XTHREADS
707				  , cv
708#endif
709				  );
710#ifdef SUNSYSV
711	    } else if (ECHECK(0)) {
712		_XWaitForWritable(dpy
713#ifdef XTHREADS
714				  , cv
715#endif
716				  );
717#endif
718#ifdef ESZTEST
719	    } else if (ESZTEST()) {
720		if (todo > 1)
721		    todo >>= 1;
722		else {
723		    _XWaitForWritable(dpy
724#ifdef XTHREADS
725				      , cv
726#endif
727				      );
728		}
729#endif
730	    } else if (!ECHECK(EINTR)) {
731		/* Write failed! */
732		/* errno set by write system call. */
733		_XIOError(dpy);
734	    }
735	}
736	dpy->last_req = (char *)&_dummy_request;
737	_XSetSeqSyncFunction(dpy);
738	dpy->bufptr = dpy->buffer;
739#ifdef XTHREADS
740	dpy->flags &= ~XlibDisplayWriting;
741#endif
742}
743
744int
745_XEventsQueued(
746    register Display *dpy,
747    int mode)
748{
749	register int len;
750	BytesReadable_t pend;
751	_XAlignedBuffer buf;
752	register xReply *rep;
753	char *read_buf;
754#ifdef XTHREADS
755	int entry_event_serial_num;
756	struct _XCVList *cvl = NULL;
757	xthread_t self;
758
759#ifdef XTHREADS_DEBUG
760	printf("_XEventsQueued called in thread %x\n", XThread_Self());
761#endif
762#endif /* XTHREADS*/
763
764	if (mode == QueuedAfterFlush)
765	{
766	    _XFlush(dpy);
767	    if (dpy->qlen)
768		return(dpy->qlen);
769	}
770	if (dpy->flags & XlibDisplayIOError) return(dpy->qlen);
771
772#ifdef XTHREADS
773	/* create our condition variable and append to list,
774	 * unless we were called from within XProcessInternalConnection
775	 * or XLockDisplay
776	 */
777	xthread_clear_id(self);
778	if (dpy->lock && (xthread_have_id (dpy->lock->conni_thread)
779			  || xthread_have_id (dpy->lock->locking_thread)))
780	    /* some thread is in XProcessInternalConnection or XLockDisplay
781	       so we have to see if we are it */
782	    self = XThread_Self();
783	if (!xthread_have_id(self)
784	    || (!xthread_equal(self, dpy->lock->conni_thread)
785		&& !xthread_equal(self, dpy->lock->locking_thread))) {
786	    /* In the multi-threaded case, if there is someone else
787	       reading events, then there aren't any available, so
788	       we just return.  If we waited we would block.
789	       */
790	    if (dpy->lock && dpy->lock->event_awaiters)
791		return dpy->qlen;
792	    /* nobody here but us, so lock out any newcomers */
793	    cvl = QueueEventReaderLock(dpy);
794	}
795
796	while (dpy->lock && cvl && dpy->lock->reply_first) {
797	    /* note which events we have already seen so we'll know
798	       if _XReply (in another thread) reads one */
799	    entry_event_serial_num = dpy->next_event_serial_num;
800	    ConditionWait(dpy, cvl->cv);
801	    /* did _XReply read an event we can return? */
802	    if (_XNewerQueuedEvent(dpy, entry_event_serial_num))
803	    {
804		UnlockNextEventReader(dpy);
805		return 0;
806	    }
807	}
808#endif /* XTHREADS*/
809
810	if (_X11TransBytesReadable(dpy->trans_conn, &pend) < 0)
811	    _XIOError(dpy);
812#ifdef XCONN_CHECK_FREQ
813	/* This is a crock, required because FIONREAD or equivalent is
814	 * not guaranteed to detect a broken connection.
815	 */
816	if (!pend && !dpy->qlen && ++dpy->conn_checker >= XCONN_CHECK_FREQ)
817	{
818	    int	result;
819#ifdef USE_POLL
820	    struct pollfd filedes;
821#else
822	    fd_set r_mask;
823	    static struct timeval zero_time;
824#endif
825
826	    dpy->conn_checker = 0;
827#ifdef USE_POLL
828	    filedes.fd = dpy->fd;
829	    filedes.events = POLLIN;
830	    if ((result = poll(&filedes, 1, 0)))
831#else
832	    FD_ZERO(&r_mask);
833	    FD_SET(dpy->fd, &r_mask);
834	    if ((result = Select(dpy->fd + 1, &r_mask, NULL, NULL, &zero_time)))
835#endif
836	    {
837		if (result > 0)
838		{
839		    if (_X11TransBytesReadable(dpy->trans_conn, &pend) < 0)
840			_XIOError(dpy);
841		    /* we should not get zero, if we do, force a read */
842		    if (!pend)
843			pend = SIZEOF(xReply);
844		}
845		else if (result < 0 && !ECHECK(EINTR))
846		    _XIOError(dpy);
847	    }
848	}
849#endif /* XCONN_CHECK_FREQ */
850	if (!(len = pend)) {
851	    /* _XFlush can enqueue events */
852#ifdef XTHREADS
853	    if (cvl)
854#endif
855	    {
856		UnlockNextEventReader(dpy);
857	    }
858	    return(dpy->qlen);
859	}
860      /* Force a read if there is not enough data.  Otherwise,
861       * a select() loop at a higher-level will spin undesirably,
862       * and we've seen at least one OS that appears to not update
863       * the result from FIONREAD once it has returned nonzero.
864       */
865#ifdef XTHREADS
866	if (dpy->lock && dpy->lock->reply_awaiters) {
867	    read_buf = (char *)dpy->lock->reply_awaiters->buf;
868	    len = SIZEOF(xReply);
869	} else
870#endif /* XTHREADS*/
871	{
872	    read_buf = buf.buf;
873
874	    if (len < SIZEOF(xReply)
875#ifdef XTHREADS
876		|| dpy->async_handlers
877#endif
878		)
879		len = SIZEOF(xReply);
880	    else if (len > BUFSIZE)
881		len = BUFSIZE;
882	    len = (len / SIZEOF(xReply)) * SIZEOF(xReply);
883	}
884#ifdef XCONN_CHECK_FREQ
885	dpy->conn_checker = 0;
886#endif
887
888	(void) _XRead (dpy, read_buf, (long) len);
889
890#ifdef XTHREADS
891	/* what did we actually read: reply or event? */
892	if (dpy->lock && dpy->lock->reply_awaiters) {
893	    if (((xReply *)read_buf)->generic.type == X_Reply ||
894		((xReply *)read_buf)->generic.type == X_Error)
895	    {
896		dpy->lock->reply_was_read = True;
897		dpy->lock->reply_first = True;
898		if (read_buf != (char *)dpy->lock->reply_awaiters->buf)
899		    memcpy(dpy->lock->reply_awaiters->buf, read_buf,
900			   len);
901		if (cvl) {
902		    UnlockNextEventReader(dpy);
903		}
904		return(dpy->qlen); /* we read, so we can return */
905	    } else if (read_buf != buf.buf)
906		memcpy(buf.buf, read_buf, len);
907	}
908#endif /* XTHREADS*/
909
910	STARTITERATE(rep,xReply,buf.buf,len > 0) {
911	    if (rep->generic.type == X_Reply) {
912                int tmp = len;
913		RESETITERPTR(rep,xReply,
914			     _XAsyncReply (dpy, rep,
915					   ITERPTR(rep), &tmp, True));
916                len = tmp;
917		pend = len;
918	    } else {
919		if (rep->generic.type == X_Error)
920		    _XError (dpy, (xError *)rep);
921		else   /* must be an event packet */
922		    _XEnq (dpy, (xEvent *)rep);
923		INCITERPTR(rep,xReply);
924		len -= SIZEOF(xReply);
925	    }
926	} ENDITERATE
927
928#ifdef XTHREADS
929	if (cvl)
930#endif
931	{
932	    UnlockNextEventReader(dpy);
933	}
934	return(dpy->qlen);
935}
936
937/* _XReadEvents - Flush the output queue,
938 * then read as many events as possible (but at least 1) and enqueue them
939 */
940void _XReadEvents(
941	register Display *dpy)
942{
943	_XAlignedBuffer buf;
944	BytesReadable_t pend;
945	int len;
946	register xReply *rep;
947	Bool not_yet_flushed = True;
948	char *read_buf;
949	int i;
950	int entry_event_serial_num = dpy->next_event_serial_num;
951#ifdef XTHREADS
952	struct _XCVList *cvl = NULL;
953	xthread_t self;
954
955#ifdef XTHREADS_DEBUG
956	printf("_XReadEvents called in thread %x\n",
957	       XThread_Self());
958#endif
959	/* create our condition variable and append to list,
960	 * unless we were called from within XProcessInternalConnection
961	 * or XLockDisplay
962	 */
963	xthread_clear_id(self);
964	if (dpy->lock && (xthread_have_id (dpy->lock->conni_thread)
965			  || xthread_have_id (dpy->lock->locking_thread)))
966	    /* some thread is in XProcessInternalConnection or XLockDisplay
967	       so we have to see if we are it */
968	    self = XThread_Self();
969	if (!xthread_have_id(self)
970	    || (!xthread_equal(self, dpy->lock->conni_thread)
971		&& !xthread_equal(self, dpy->lock->locking_thread)))
972	    cvl = QueueEventReaderLock(dpy);
973#endif /* XTHREADS */
974
975	do {
976#ifdef XTHREADS
977	    /* if it is not our turn to read an event off the wire,
978	       wait til we're at head of list */
979	    if (dpy->lock && cvl &&
980		(dpy->lock->event_awaiters != cvl ||
981		 dpy->lock->reply_first)) {
982		ConditionWait(dpy, cvl->cv);
983		continue;
984	    }
985#endif /* XTHREADS */
986	    /* find out how much data can be read */
987	    if (_X11TransBytesReadable(dpy->trans_conn, &pend) < 0)
988	    	_XIOError(dpy);
989	    len = pend;
990
991	    /* must read at least one xEvent; if none is pending, then
992	       we'll just flush and block waiting for it */
993	    if (len < SIZEOF(xEvent)
994#ifdef XTHREADS
995		|| dpy->async_handlers
996#endif
997		) {
998	    	len = SIZEOF(xEvent);
999		/* don't flush until the first time we would block */
1000		if (not_yet_flushed) {
1001		    _XFlush (dpy);
1002		    if (_XNewerQueuedEvent(dpy, entry_event_serial_num)) {
1003			/* _XReply has read an event for us */
1004			goto got_event;
1005		    }
1006		    not_yet_flushed = False;
1007		}
1008	    }
1009
1010#ifdef XTHREADS
1011	    /* If someone is waiting for a reply, gamble that
1012	       the reply will be the next thing on the wire
1013	       and read it into their buffer. */
1014	    if (dpy->lock && dpy->lock->reply_awaiters) {
1015		read_buf = (char *)dpy->lock->reply_awaiters->buf;
1016		len = SIZEOF(xReply);
1017	    } else
1018#endif /* XTHREADS*/
1019	    {
1020		read_buf = buf.buf;
1021
1022		/* but we won't read more than the max buffer size */
1023		if (len > BUFSIZE)
1024		    len = BUFSIZE;
1025
1026		/* round down to an integral number of XReps */
1027		len = (len / SIZEOF(xEvent)) * SIZEOF(xEvent);
1028	    }
1029
1030#ifdef XTHREADS
1031	    if (xthread_have_id(self))
1032		/* save value we may have to stick in conni_thread */
1033		dpy->lock->reading_thread = self;
1034#endif /* XTHREADS */
1035	    dpy->flags |= XlibDisplayReadEvents;
1036	    i = _XRead (dpy, read_buf, (long) len);
1037	    dpy->flags &= ~XlibDisplayReadEvents;
1038	    if (i == -2) {
1039		/* special flag from _XRead to say that internal connection has
1040		   done XPutBackEvent.  Which we can use so we're done. */
1041	      got_event:
1042#ifdef XTHREADS
1043		if (dpy->lock && dpy->lock->lock_wait) {
1044		    if (dpy->lock->event_awaiters != cvl)
1045			/* since it is not us, must be user lock thread */
1046			ConditionSignal(dpy,
1047					dpy->lock->event_awaiters->cv);
1048		    (*dpy->lock->lock_wait)(dpy);
1049		    continue;
1050		}
1051#endif
1052		break;
1053	    }
1054#ifdef XTHREADS
1055	    if (xthread_have_id(self))
1056		xthread_clear_id(dpy->lock->reading_thread);
1057
1058	    /* what did we actually read: reply or event? */
1059	    if (dpy->lock && dpy->lock->reply_awaiters) {
1060		if (((xReply *)read_buf)->generic.type == X_Reply ||
1061		    ((xReply *)read_buf)->generic.type == X_Error)
1062		{
1063		    dpy->lock->reply_was_read = True;
1064		    dpy->lock->reply_first = True;
1065		    if (read_buf != (char *)dpy->lock->reply_awaiters->buf)
1066			memcpy(dpy->lock->reply_awaiters->buf,
1067			       read_buf, len);
1068		    ConditionSignal(dpy, dpy->lock->reply_awaiters->cv);
1069		    continue;
1070		} else if (read_buf != buf.buf)
1071		    memcpy(buf.buf, read_buf, len);
1072	    }
1073#endif /* XTHREADS */
1074
1075	    STARTITERATE(rep,xReply,buf.buf,len > 0) {
1076		if (rep->generic.type == X_Reply) {
1077		    RESETITERPTR(rep,xReply,
1078				 _XAsyncReply (dpy, rep,
1079					       ITERPTR(rep), &len, True));
1080		    pend = len;
1081		} else {
1082		    if (rep->generic.type == X_Error)
1083			_XError (dpy, (xError *) rep);
1084		    else   /* must be an event packet */
1085                    {
1086                        if (rep->generic.type == GenericEvent)
1087                        {
1088                            int evlen;
1089                            evlen = (rep->generic.length << 2);
1090                            if (_XRead(dpy, &read_buf[len], evlen) == -2)
1091                                goto got_event; /* XXX: aargh! */
1092                        }
1093
1094                        _XEnq (dpy, (xEvent *)rep);
1095                    }
1096		    INCITERPTR(rep,xReply);
1097		    len -= SIZEOF(xReply);
1098		}
1099	    } ENDITERATE;
1100	} while (!_XNewerQueuedEvent(dpy, entry_event_serial_num));
1101
1102	UnlockNextEventReader(dpy);
1103}
1104
1105/*
1106 * _XRead - Read bytes from the socket taking into account incomplete
1107 * reads.  This routine may have to be reworked if int < long.
1108 */
1109int _XRead(
1110	register Display *dpy,
1111	register char *data,
1112	register long size)
1113{
1114	register long bytes_read;
1115#ifdef XTHREADS
1116	int original_size = size;
1117#endif
1118
1119	if ((dpy->flags & XlibDisplayIOError) || size == 0)
1120	    return 0;
1121	ESET(0);
1122	while ((bytes_read = _X11TransRead(dpy->trans_conn, data, (int)size))
1123		!= size) {
1124
1125	    	if (bytes_read > 0) {
1126		    size -= bytes_read;
1127		    data += bytes_read;
1128		    }
1129		else if (ETEST()) {
1130		    if (_XWaitForReadable(dpy) == -2)
1131			return -2; /* internal connection did XPutBackEvent */
1132		    ESET(0);
1133		}
1134#ifdef SUNSYSV
1135		else if (ECHECK(0)) {
1136		    if (_XWaitForReadable(dpy) == -2)
1137			return -2; /* internal connection did XPutBackEvent */
1138		}
1139#endif
1140		else if (bytes_read == 0) {
1141		    /* Read failed because of end of file! */
1142		    ESET(EPIPE);
1143		    _XIOError(dpy);
1144		    }
1145
1146		else  /* bytes_read is less than 0; presumably -1 */ {
1147		    /* If it's a system call interrupt, it's not an error. */
1148		    if (!ECHECK(EINTR))
1149		    	_XIOError(dpy);
1150		    }
1151	    	 }
1152#ifdef XTHREADS
1153       if (dpy->lock && dpy->lock->reply_bytes_left > 0)
1154       {
1155           dpy->lock->reply_bytes_left -= original_size;
1156           if (dpy->lock->reply_bytes_left == 0) {
1157	       dpy->flags &= ~XlibDisplayReply;
1158               UnlockNextReplyReader(dpy);
1159	   }
1160       }
1161#endif /* XTHREADS*/
1162	return 0;
1163}
1164#endif /* !USE_XCB */
1165
1166#ifdef LONG64
1167void _XRead32(
1168    Display *dpy,
1169    register long *data,
1170    long len)
1171{
1172    register int *buf;
1173    register long i;
1174
1175    if (len) {
1176	(void) _XRead(dpy, (char *)data, len);
1177	i = len >> 2;
1178	buf = (int *)data + i;
1179	data += i;
1180	while (--i >= 0)
1181	    *--data = *--buf;
1182    }
1183}
1184#endif /* LONG64 */
1185
1186#ifdef WORD64
1187
1188/*
1189 * XXX This is a *really* stupid way of doing this....
1190 * PACKBUFFERSIZE must be a multiple of 4.
1191 */
1192
1193#define PACKBUFFERSIZE 4096
1194
1195
1196/*
1197 * _XRead32 - Read bytes from the socket unpacking each 32 bits
1198 *            into a long (64 bits on a CRAY computer).
1199 *
1200 */
1201static void _doXRead32(
1202        register Display *dpy,
1203        register long *data
1204        register long size,
1205	register char *packbuffer)
1206{
1207 long *lpack,*lp;
1208 long mask32 = 0x00000000ffffffff;
1209 long maskw, nwords, i, bits;
1210
1211        _XReadPad (dpy, packbuffer, size);
1212
1213        lp = data;
1214        lpack = (long *) packbuffer;
1215        nwords = size >> 2;
1216        bits = 32;
1217
1218        for(i=0;i<nwords;i++){
1219            maskw = mask32 << bits;
1220           *lp++ = ( *lpack & maskw ) >> bits;
1221            bits = bits ^32;
1222            if(bits){
1223               lpack++;
1224            }
1225        }
1226}
1227
1228void _XRead32(
1229    Display *dpy,
1230    long *data,
1231    long len)
1232{
1233    char packbuffer[PACKBUFFERSIZE];
1234    unsigned nunits = PACKBUFFERSIZE >> 2;
1235
1236    for (; len > PACKBUFFERSIZE; len -= PACKBUFFERSIZE, data += nunits) {
1237	_doXRead32 (dpy, data, PACKBUFFERSIZE, packbuffer);
1238    }
1239    if (len) _doXRead32 (dpy, data, len, packbuffer);
1240}
1241
1242
1243
1244/*
1245 * _XRead16 - Read bytes from the socket unpacking each 16 bits
1246 *            into a long (64 bits on a CRAY computer).
1247 *
1248 */
1249static _doXRead16(
1250        register Display *dpy,
1251        register short *data,
1252        register long size,
1253	char *packbuffer)
1254{
1255	long *lpack,*lp;
1256	long mask16 = 0x000000000000ffff;
1257	long maskw, nwords, i, bits;
1258
1259        (void) _XRead(dpy,packbuffer,size);	/* don't do a padded read... */
1260
1261        lp = (long *) data;
1262        lpack = (long *) packbuffer;
1263        nwords = size >> 1;  /* number of 16 bit words to be unpacked */
1264        bits = 48;
1265        for(i=0;i<nwords;i++){
1266            maskw = mask16 << bits;
1267           *lp++ = ( *lpack & maskw ) >> bits;
1268            bits -= 16;
1269            if(bits < 0){
1270               lpack++;
1271               bits = 48;
1272            }
1273        }
1274}
1275
1276void _XRead16(
1277    Display *dpy,
1278    short *data,
1279    long len)
1280{
1281    char packbuffer[PACKBUFFERSIZE];
1282    unsigned nunits = PACKBUFFERSIZE >> 1;
1283
1284    for (; len > PACKBUFFERSIZE; len -= PACKBUFFERSIZE, data += nunits) {
1285	_doXRead16 (dpy, data, PACKBUFFERSIZE, packbuffer);
1286    }
1287    if (len) _doXRead16 (dpy, data, len, packbuffer);
1288}
1289
1290void _XRead16Pad(
1291    Display *dpy,
1292    short *data,
1293    long size)
1294{
1295    int slop = (size & 3);
1296    short slopbuf[3];
1297
1298    _XRead16 (dpy, data, size);
1299    if (slop > 0) {
1300	_XRead16 (dpy, slopbuf, 4 - slop);
1301    }
1302}
1303#endif /* WORD64 */
1304
1305
1306#if !USE_XCB
1307/*
1308 * _XReadPad - Read bytes from the socket taking into account incomplete
1309 * reads.  If the number of bytes is not 0 mod 4, read additional pad
1310 * bytes. This routine may have to be reworked if int < long.
1311 */
1312void _XReadPad(
1313    	register Display *dpy,
1314	register char *data,
1315	register long size)
1316{
1317    	register long bytes_read;
1318	struct iovec iov[2];
1319	char pad[3];
1320#ifdef XTHREADS
1321        int original_size;
1322#endif
1323
1324	if ((dpy->flags & XlibDisplayIOError) || size == 0) return;
1325	iov[0].iov_len = (int)size;
1326	iov[0].iov_base = data;
1327	/*
1328	 * The following hack is used to provide 32 bit long-word
1329	 * aligned padding.  The [1] vector is of length 0, 1, 2, or 3,
1330	 * whatever is needed.
1331	 */
1332
1333	iov[1].iov_len = -size & 3;
1334	iov[1].iov_base = pad;
1335	size += iov[1].iov_len;
1336#ifdef XTHREADS
1337	original_size = size;
1338#endif
1339	ESET(0);
1340	while ((bytes_read = _X11TransReadv (dpy->trans_conn, iov, 2)) != size) {
1341
1342	    if (bytes_read > 0) {
1343		size -= bytes_read;
1344		if (iov[0].iov_len < bytes_read) {
1345		    int pad_bytes_read = bytes_read - iov[0].iov_len;
1346		    iov[1].iov_len -= pad_bytes_read;
1347		    iov[1].iov_base =
1348			(char *)iov[1].iov_base + pad_bytes_read;
1349		    iov[0].iov_len = 0;
1350		    }
1351	    	else {
1352		    iov[0].iov_len -= bytes_read;
1353	    	    iov[0].iov_base = (char *)iov[0].iov_base + bytes_read;
1354	    	}
1355	    }
1356	    else if (ETEST()) {
1357		_XWaitForReadable(dpy);
1358		ESET(0);
1359	    }
1360#ifdef SUNSYSV
1361	    else if (ECHECK(0)) {
1362		_XWaitForReadable(dpy);
1363	    }
1364#endif
1365	    else if (bytes_read == 0) {
1366		/* Read failed because of end of file! */
1367		ESET(EPIPE);
1368		_XIOError(dpy);
1369		}
1370
1371	    else  /* bytes_read is less than 0; presumably -1 */ {
1372		/* If it's a system call interrupt, it's not an error. */
1373		if (!ECHECK(EINTR))
1374		    _XIOError(dpy);
1375		}
1376	    }
1377#ifdef XTHREADS
1378       if (dpy->lock && dpy->lock->reply_bytes_left > 0)
1379       {
1380           dpy->lock->reply_bytes_left -= original_size;
1381           if (dpy->lock->reply_bytes_left == 0) {
1382	       dpy->flags &= ~XlibDisplayReply;
1383               UnlockNextReplyReader(dpy);
1384	   }
1385       }
1386#endif /* XTHREADS*/
1387}
1388
1389/*
1390 * _XSend - Flush the buffer and send the client data. 32 bit word aligned
1391 * transmission is used, if size is not 0 mod 4, extra bytes are transmitted.
1392 * This routine may have to be reworked if int < long;
1393 */
1394void
1395_XSend (
1396	register Display *dpy,
1397	_Xconst char *data,
1398	register long size)
1399{
1400	struct iovec iov[3];
1401	static char const pad[3] = {0, 0, 0};
1402           /* XText8 and XText16 require that the padding bytes be zero! */
1403
1404	long skip, dbufsize, padsize, total, todo;
1405	_XExtension *ext;
1406
1407	if (!size || (dpy->flags & XlibDisplayIOError)) return;
1408	dbufsize = dpy->bufptr - dpy->buffer;
1409#ifdef XTHREADS
1410	dpy->flags |= XlibDisplayWriting;
1411	/* make sure no one else can put in data */
1412	dpy->bufptr = dpy->bufmax;
1413#endif
1414	padsize = -size & 3;
1415	for (ext = dpy->flushes; ext; ext = ext->next_flush) {
1416	    (*ext->before_flush)(dpy, &ext->codes, dpy->buffer, dbufsize);
1417	    (*ext->before_flush)(dpy, &ext->codes, (char *)data, size);
1418	    if (padsize)
1419		(*ext->before_flush)(dpy, &ext->codes, pad, padsize);
1420	}
1421	skip = 0;
1422	todo = total = dbufsize + size + padsize;
1423
1424	/*
1425	 * There are 3 pieces that may need to be written out:
1426	 *
1427	 *     o  whatever is in the display buffer
1428	 *     o  the data passed in by the user
1429	 *     o  any padding needed to 32bit align the whole mess
1430	 *
1431	 * This loop looks at all 3 pieces each time through.  It uses skip
1432	 * to figure out whether or not a given piece is needed.
1433	 */
1434	while (total) {
1435	    long before = skip;		/* amount of whole thing written */
1436	    long remain = todo;		/* amount to try this time, <= total */
1437	    int i = 0;
1438	    long len;
1439
1440	    /* You could be very general here and have "in" and "out" iovecs
1441	     * and write a loop without using a macro, but what the heck.  This
1442	     * translates to:
1443	     *
1444	     *     how much of this piece is new?
1445	     *     if more new then we are trying this time, clamp
1446	     *     if nothing new
1447	     *         then bump down amount already written, for next piece
1448	     *         else put new stuff in iovec, will need all of next piece
1449	     *
1450	     * Note that todo had better be at least 1 or else we'll end up
1451	     * writing 0 iovecs.
1452	     */
1453#define InsertIOV(pointer, length) \
1454	    len = (length) - before; \
1455	    if (len > remain) \
1456		len = remain; \
1457	    if (len <= 0) { \
1458		before = (-len); \
1459	    } else { \
1460		iov[i].iov_len = len; \
1461		iov[i].iov_base = (pointer) + before; \
1462		i++; \
1463		remain -= len; \
1464		before = 0; \
1465	    }
1466
1467	    InsertIOV (dpy->buffer, dbufsize)
1468	    InsertIOV ((char *)data, size)
1469	    InsertIOV ((char *)pad, padsize)
1470
1471	    ESET(0);
1472	    if ((len = _X11TransWritev(dpy->trans_conn, iov, i)) >= 0) {
1473		skip += len;
1474		total -= len;
1475		todo = total;
1476	    } else if (ETEST()) {
1477		_XWaitForWritable(dpy
1478#ifdef XTHREADS
1479				  , NULL
1480#endif
1481				  );
1482#ifdef SUNSYSV
1483	    } else if (ECHECK(0)) {
1484		_XWaitForWritable(dpy
1485#ifdef XTHREADS
1486				  , NULL
1487#endif
1488				  );
1489#endif
1490#ifdef ESZTEST
1491	    } else if (ESZTEST()) {
1492		if (todo > 1)
1493		  todo >>= 1;
1494		else {
1495		    _XWaitForWritable(dpy
1496#ifdef XTHREADS
1497				      , NULL
1498#endif
1499				      );
1500		}
1501#endif
1502	    } else if (!ECHECK(EINTR)) {
1503		_XIOError(dpy);
1504	    }
1505	}
1506	dpy->last_req = (char *) & _dummy_request;
1507	_XSetSeqSyncFunction(dpy);
1508	dpy->bufptr = dpy->buffer;
1509#ifdef XTHREADS
1510	dpy->flags &= ~XlibDisplayWriting;
1511#endif
1512	return;
1513}
1514
1515static void
1516_XGetMiscCode(
1517    register Display *dpy)
1518{
1519    xQueryExtensionReply qrep;
1520    register xQueryExtensionReq *qreq;
1521    xXCMiscGetVersionReply vrep;
1522    register xXCMiscGetVersionReq *vreq;
1523
1524    if (dpy->xcmisc_opcode)
1525	return;
1526    GetReq(QueryExtension, qreq);
1527    qreq->nbytes = sizeof(XCMiscExtensionName) - 1;
1528    qreq->length += (qreq->nbytes+(unsigned)3)>>2;
1529    _XSend(dpy, XCMiscExtensionName, (long)qreq->nbytes);
1530    if (!_XReply (dpy, (xReply *)&qrep, 0, xTrue))
1531	dpy->xcmisc_opcode = -1;
1532    else {
1533	GetReq(XCMiscGetVersion, vreq);
1534	vreq->reqType = qrep.major_opcode;
1535	vreq->miscReqType = X_XCMiscGetVersion;
1536	vreq->majorVersion = XCMiscMajorVersion;
1537	vreq->minorVersion = XCMiscMinorVersion;
1538	if (!_XReply (dpy, (xReply *)&vrep, 0, xTrue))
1539	    dpy->xcmisc_opcode = -1;
1540	else
1541	    dpy->xcmisc_opcode = qrep.major_opcode;
1542    }
1543}
1544
1545int
1546_XIDHandler(
1547    register Display *dpy)
1548{
1549    xXCMiscGetXIDRangeReply grep;
1550    register xXCMiscGetXIDRangeReq *greq;
1551    int sent_req = 0;
1552
1553    LockDisplay(dpy);
1554    if (dpy->resource_max == dpy->resource_mask + 1) {
1555	_XGetMiscCode(dpy);
1556	if (dpy->xcmisc_opcode > 0) {
1557	    GetReq(XCMiscGetXIDRange, greq);
1558	    greq->reqType = dpy->xcmisc_opcode;
1559	    greq->miscReqType = X_XCMiscGetXIDRange;
1560	    if (_XReply (dpy, (xReply *)&grep, 0, xTrue) && grep.count) {
1561		dpy->resource_id = ((grep.start_id - dpy->resource_base) >>
1562				    dpy->resource_shift);
1563		dpy->resource_max = dpy->resource_id;
1564		if (grep.count > 5)
1565		    dpy->resource_max += grep.count - 6;
1566		dpy->resource_max <<= dpy->resource_shift;
1567	    }
1568	    sent_req = 1;
1569	}
1570    }
1571    UnlockDisplay(dpy);
1572    if (sent_req)
1573	SyncHandle();
1574    return 0;
1575}
1576
1577/*
1578 * _XAllocID - resource ID allocation routine.
1579 */
1580XID _XAllocID(
1581    register Display *dpy)
1582{
1583   XID id;
1584
1585   id = dpy->resource_id << dpy->resource_shift;
1586   if (id >= dpy->resource_max) {
1587	_XSetPrivSyncFunction(dpy);
1588       dpy->resource_max = dpy->resource_mask + 1;
1589   }
1590   if (id <= dpy->resource_mask) {
1591       dpy->resource_id++;
1592       return (dpy->resource_base + id);
1593   }
1594   if (id != 0x10000000) {
1595       (void) fprintf(stderr,
1596		      "Xlib: resource ID allocation space exhausted!\n");
1597       id = 0x10000000;
1598       dpy->resource_id = id >> dpy->resource_shift;
1599   }
1600   return id;
1601}
1602
1603/*
1604 * _XAllocIDs - multiple resource ID allocation routine.
1605 */
1606void _XAllocIDs(
1607    register Display *dpy,
1608    XID *ids,
1609    int count)
1610{
1611    XID id;
1612    int i;
1613    xXCMiscGetXIDListReply grep;
1614    register xXCMiscGetXIDListReq *greq;
1615
1616    id = dpy->resource_id << dpy->resource_shift;
1617    if (dpy->resource_max <= dpy->resource_mask &&
1618	id <= dpy->resource_mask &&
1619	(dpy->resource_max - id) > ((count - 1) << dpy->resource_shift)) {
1620	id += dpy->resource_base;
1621	for (i = 0; i < count; i++) {
1622	    ids[i] = id;
1623	    id += (1 << dpy->resource_shift);
1624	    dpy->resource_id++;
1625	}
1626	return;
1627    }
1628    grep.count = 0;
1629    _XGetMiscCode(dpy);
1630    if (dpy->xcmisc_opcode > 0) {
1631	GetReq(XCMiscGetXIDList, greq);
1632	greq->reqType = dpy->xcmisc_opcode;
1633	greq->miscReqType = X_XCMiscGetXIDList;
1634	greq->count = count;
1635	if (_XReply(dpy, (xReply *)&grep, 0, xFalse) && grep.count) {
1636	    _XRead32(dpy, (long *) ids, 4L * (long) (grep.count));
1637	    for (i = 0; i < grep.count; i++) {
1638		id = (ids[i] - dpy->resource_base) >> dpy->resource_shift;
1639		if (id >= dpy->resource_id)
1640		    dpy->resource_id = id;
1641	    }
1642	    if (id >= dpy->resource_max) {
1643		_XSetPrivSyncFunction(dpy);
1644		dpy->resource_max = dpy->resource_mask + 1;
1645	    }
1646	}
1647    }
1648    for (i = grep.count; i < count; i++)
1649	ids[i] = XAllocID(dpy);
1650}
1651#endif /* !USE_XCB */
1652
1653/*
1654 * The hard part about this is that we only get 16 bits from a reply.
1655 * We have three values that will march along, with the following invariant:
1656 *	dpy->last_request_read <= rep->sequenceNumber <= dpy->request
1657 * We have to keep
1658 *	dpy->request - dpy->last_request_read < 2^16
1659 * or else we won't know for sure what value to use in events.  We do this
1660 * by forcing syncs when we get close.
1661 */
1662
1663unsigned long
1664_XSetLastRequestRead(
1665    register Display *dpy,
1666    register xGenericReply *rep)
1667{
1668    register unsigned long	newseq, lastseq;
1669
1670    lastseq = dpy->last_request_read;
1671    /*
1672     * KeymapNotify has no sequence number, but is always guaranteed
1673     * to immediately follow another event, except when generated via
1674     * SendEvent (hmmm).
1675     */
1676    if ((rep->type & 0x7f) == KeymapNotify)
1677	return(lastseq);
1678
1679    newseq = (lastseq & ~((unsigned long)0xffff)) | rep->sequenceNumber;
1680
1681    if (newseq < lastseq) {
1682	newseq += 0x10000;
1683	if (newseq > dpy->request) {
1684	    (void) fprintf (stderr,
1685	    "Xlib: sequence lost (0x%lx > 0x%lx) in reply type 0x%x!\n",
1686			    newseq, dpy->request,
1687			    (unsigned int) rep->type);
1688	    newseq -= 0x10000;
1689	}
1690    }
1691
1692    dpy->last_request_read = newseq;
1693    return(newseq);
1694}
1695
1696#if !USE_XCB
1697/*
1698 * _XReply - Wait for a reply packet and copy its contents into the
1699 * specified rep.  Meanwhile we must handle error and event packets that
1700 * we may encounter.
1701 */
1702Status
1703_XReply (
1704    register Display *dpy,
1705    register xReply *rep,
1706    int extra,		/* number of 32-bit words expected after the reply */
1707    Bool discard)	/* should I discard data following "extra" words? */
1708{
1709    /* Pull out the serial number now, so that (currently illegal) requests
1710     * generated by an error handler don't confuse us.
1711     */
1712    unsigned long cur_request = dpy->request;
1713#ifdef XTHREADS
1714    struct _XCVList *cvl;
1715#endif
1716
1717    if (dpy->flags & XlibDisplayIOError)
1718	return 0;
1719
1720#ifdef XTHREADS
1721    /* create our condition variable and append to list */
1722    cvl = QueueReplyReaderLock(dpy);
1723    if (cvl) {
1724	cvl->buf = rep;
1725	if (dpy->lock->reply_awaiters == cvl && !dpy->lock->event_awaiters)
1726	    dpy->lock->reply_first = True;
1727    }
1728
1729#ifdef XTHREADS_DEBUG
1730    printf("_XReply called in thread %x, adding %x to cvl\n",
1731	   XThread_Self(), cvl);
1732#endif
1733
1734    _XFlushInt(dpy, cvl ? cvl->cv : NULL);
1735    /* if it is not our turn to read a reply off the wire,
1736     * wait til we're at head of list.  if there is an event waiter,
1737     * and our reply hasn't been read, they'll be in select and will
1738     * hand control back to us next.
1739     */
1740    if(dpy->lock &&
1741       (dpy->lock->reply_awaiters != cvl || !dpy->lock->reply_first)) {
1742	ConditionWait(dpy, cvl->cv);
1743    }
1744    dpy->flags |= XlibDisplayReply;
1745#else /* XTHREADS else */
1746    _XFlush(dpy);
1747#endif
1748
1749    for (;;) {
1750#ifdef XTHREADS
1751	/* Did another thread's _XReadEvents get our reply by accident? */
1752	if (!dpy->lock || !dpy->lock->reply_was_read)
1753#endif
1754	    (void) _XRead(dpy, (char *)rep, (long)SIZEOF(xReply));
1755#ifdef XTHREADS
1756	if (dpy->lock)
1757	    dpy->lock->reply_was_read = False;
1758#endif
1759
1760	switch ((int)rep->generic.type) {
1761
1762	    case X_Reply:
1763	        /* Reply received.  Fast update for synchronous replies,
1764		 * but deal with multiple outstanding replies.
1765		 */
1766	        if (rep->generic.sequenceNumber == (cur_request & 0xffff))
1767		    dpy->last_request_read = cur_request;
1768		else {
1769		    int pend = SIZEOF(xReply);
1770		    if (_XAsyncReply(dpy, rep, (char *)rep, &pend, False)
1771			!= (char *)rep)
1772			continue;
1773		}
1774		if (extra <= rep->generic.length) {
1775		    if (extra > 0)
1776			/*
1777			 * Read the extra data into storage immediately
1778			 * following the GenericReply structure.
1779			 */
1780			(void) _XRead (dpy, (char *) (NEXTPTR(rep,xReply)),
1781				((long)extra) << 2);
1782		    if (discard) {
1783			if (extra < rep->generic.length)
1784			    _XEatData(dpy, (rep->generic.length - extra) << 2);
1785		    }
1786#ifdef XTHREADS
1787		    if (dpy->lock) {
1788			if (discard) {
1789			    dpy->lock->reply_bytes_left = 0;
1790			} else {
1791			    dpy->lock->reply_bytes_left =
1792				(rep->generic.length - extra) << 2;
1793			}
1794			if (dpy->lock->reply_bytes_left == 0) {
1795			    dpy->flags &= ~XlibDisplayReply;
1796			    UnlockNextReplyReader(dpy);
1797			}
1798		    } else
1799			dpy->flags &= ~XlibDisplayReply;
1800#endif
1801		    return 1;
1802		}
1803		/*
1804		 *if we get here, then extra > rep->generic.length--meaning we
1805		 * read a reply that's shorter than we expected.  This is an
1806		 * error,  but we still need to figure out how to handle it...
1807		 */
1808		(void) _XRead (dpy, (char *) (NEXTPTR(rep,xReply)),
1809			((long) rep->generic.length) << 2);
1810		dpy->flags &= ~XlibDisplayReply;
1811		UnlockNextReplyReader(dpy);
1812		_XIOError (dpy);
1813		return (0);
1814
1815    	    case X_Error:
1816	    	{
1817	        register _XExtension *ext;
1818		register Bool ret = False;
1819		int ret_code;
1820		xError *err = (xError *) rep;
1821		unsigned long serial;
1822
1823		dpy->flags &= ~XlibDisplayReply;
1824		serial = _XSetLastRequestRead(dpy, (xGenericReply *)rep);
1825		if (serial == cur_request)
1826			/* do not die on "no such font", "can't allocate",
1827			   "can't grab" failures */
1828			switch ((int)err->errorCode) {
1829			case BadName:
1830			    switch (err->majorCode) {
1831				case X_LookupColor:
1832				case X_AllocNamedColor:
1833				    UnlockNextReplyReader(dpy);
1834				    return(0);
1835			    }
1836			    break;
1837			case BadFont:
1838			    if (err->majorCode == X_QueryFont) {
1839				UnlockNextReplyReader(dpy);
1840				return (0);
1841			    }
1842			    break;
1843			case BadAlloc:
1844			case BadAccess:
1845			    UnlockNextReplyReader(dpy);
1846			    return (0);
1847			}
1848		/*
1849		 * we better see if there is an extension who may
1850		 * want to suppress the error.
1851		 */
1852		for (ext = dpy->ext_procs; !ret && ext; ext = ext->next) {
1853		    if (ext->error)
1854		       ret = (*ext->error)(dpy, err, &ext->codes, &ret_code);
1855		}
1856		if (!ret) {
1857		    _XError(dpy, err);
1858		    ret_code = 0;
1859		}
1860		if (serial == cur_request) {
1861		    UnlockNextReplyReader(dpy);
1862		    return(ret_code);
1863		}
1864
1865		} /* case X_Error */
1866		break;
1867	    default:
1868		_XEnq(dpy, (xEvent *) rep);
1869#ifdef XTHREADS
1870		if (dpy->lock && dpy->lock->event_awaiters)
1871		    ConditionSignal(dpy, dpy->lock->event_awaiters->cv);
1872#endif
1873		break;
1874	    }
1875	}
1876}
1877
1878static char *
1879_XAsyncReply(
1880    Display *dpy,
1881    register xReply *rep,
1882    char *buf,
1883    register int *lenp,
1884    Bool discard)
1885{
1886    register _XAsyncHandler *async, *next;
1887    register int len;
1888    register Bool consumed = False;
1889    char *nbuf;
1890
1891    (void) _XSetLastRequestRead(dpy, &rep->generic);
1892    len = SIZEOF(xReply) + (rep->generic.length << 2);
1893    if (len < SIZEOF(xReply)) {
1894	_XIOError (dpy);
1895	buf += *lenp;
1896	*lenp = 0;
1897	return buf;
1898    }
1899
1900    for (async = dpy->async_handlers; async; async = next) {
1901	next = async->next;
1902	if ((consumed = (*async->handler)(dpy, rep, buf, *lenp, async->data)))
1903	    break;
1904    }
1905    if (!consumed) {
1906	if (!discard)
1907	    return buf;
1908	(void) fprintf(stderr,
1909		       "Xlib: unexpected async reply (sequence 0x%lx)!\n",
1910		       dpy->last_request_read);
1911#ifdef XTHREADS
1912#ifdef XTHREADS_DEBUG
1913	printf("thread %x, unexpected async reply\n", XThread_Self());
1914#endif
1915#endif
1916	if (len > *lenp)
1917	    _XEatData(dpy, len - *lenp);
1918    }
1919    if (len < SIZEOF(xReply))
1920    {
1921	_XIOError (dpy);
1922	buf += *lenp;
1923	*lenp = 0;
1924	return buf;
1925    }
1926    if (len >= *lenp) {
1927	buf += *lenp;
1928	*lenp = 0;
1929	return buf;
1930    }
1931    *lenp -= len;
1932    buf += len;
1933    len = *lenp;
1934    nbuf = buf;
1935    while (len > SIZEOF(xReply)) {
1936	if (*buf == X_Reply)
1937	    return nbuf;
1938	buf += SIZEOF(xReply);
1939	len -= SIZEOF(xReply);
1940    }
1941    if (len > 0 && len < SIZEOF(xReply)) {
1942	buf = nbuf;
1943	len = SIZEOF(xReply) - len;
1944	nbuf -= len;
1945	memmove(nbuf, buf, *lenp);
1946	(void) _XRead(dpy, nbuf + *lenp, (long)len);
1947	*lenp += len;
1948    }
1949    return nbuf;
1950}
1951#endif /* !USE_XCB */
1952
1953/*
1954 * Support for internal connections, such as an IM might use.
1955 * By Stephen Gildea, X Consortium, September 1993
1956 */
1957
1958/* _XRegisterInternalConnection
1959 * Each IM (or Xlib extension) that opens a file descriptor that Xlib should
1960 * include in its select/poll mask must call this function to register the
1961 * fd with Xlib.  Any XConnectionWatchProc registered by XAddConnectionWatch
1962 * will also be called.
1963 *
1964 * Whenever Xlib detects input available on fd, it will call callback
1965 * with call_data to process it.  If non-Xlib code calls select/poll
1966 * and detects input available, it must call XProcessInternalConnection,
1967 * which will call the associated callback.
1968 *
1969 * Non-Xlib code can learn about these additional fds by calling
1970 * XInternalConnectionNumbers or, more typically, by registering
1971 * a XConnectionWatchProc with XAddConnectionWatch
1972 * to be called when fds are registered or unregistered.
1973 *
1974 * Returns True if registration succeeded, False if not, typically
1975 * because could not allocate memory.
1976 * Assumes Display locked when called.
1977 */
1978Status
1979_XRegisterInternalConnection(
1980    Display* dpy,
1981    int fd,
1982    _XInternalConnectionProc callback,
1983    XPointer call_data
1984)
1985{
1986    struct _XConnectionInfo *new_conni, **iptr;
1987    struct _XConnWatchInfo *watchers;
1988    XPointer *wd;
1989
1990    new_conni = (struct _XConnectionInfo*)Xmalloc(sizeof(struct _XConnectionInfo));
1991    if (!new_conni)
1992	return 0;
1993    new_conni->watch_data = (XPointer *)Xmalloc(dpy->watcher_count * sizeof(XPointer));
1994    if (!new_conni->watch_data) {
1995	Xfree(new_conni);
1996	return 0;
1997    }
1998    new_conni->fd = fd;
1999    new_conni->read_callback = callback;
2000    new_conni->call_data = call_data;
2001    new_conni->next = NULL;
2002    /* link new structure onto end of list */
2003    for (iptr = &dpy->im_fd_info; *iptr; iptr = &(*iptr)->next)
2004	;
2005    *iptr = new_conni;
2006    dpy->im_fd_length++;
2007    _XPollfdCacheAdd(dpy, fd);
2008
2009    for (watchers=dpy->conn_watchers, wd=new_conni->watch_data;
2010	 watchers;
2011	 watchers=watchers->next, wd++) {
2012	*wd = NULL;		/* for cleanliness */
2013	(*watchers->fn) (dpy, watchers->client_data, fd, True, wd);
2014    }
2015
2016    return 1;
2017}
2018
2019/* _XUnregisterInternalConnection
2020 * Each IM (or Xlib extension) that closes a file descriptor previously
2021 * registered with _XRegisterInternalConnection must call this function.
2022 * Any XConnectionWatchProc registered by XAddConnectionWatch
2023 * will also be called.
2024 *
2025 * Assumes Display locked when called.
2026 */
2027void
2028_XUnregisterInternalConnection(
2029    Display* dpy,
2030    int fd
2031)
2032{
2033    struct _XConnectionInfo *info_list, **prev;
2034    struct _XConnWatchInfo *watch;
2035    XPointer *wd;
2036
2037    for (prev = &dpy->im_fd_info; (info_list = *prev);
2038	 prev = &info_list->next) {
2039	if (info_list->fd == fd) {
2040	    *prev = info_list->next;
2041	    dpy->im_fd_length--;
2042	    for (watch=dpy->conn_watchers, wd=info_list->watch_data;
2043		 watch;
2044		 watch=watch->next, wd++) {
2045		(*watch->fn) (dpy, watch->client_data, fd, False, wd);
2046	    }
2047	    if (info_list->watch_data)
2048		Xfree (info_list->watch_data);
2049	    Xfree (info_list);
2050	    break;
2051	}
2052    }
2053    _XPollfdCacheDel(dpy, fd);
2054}
2055
2056/* XInternalConnectionNumbers
2057 * Returns an array of fds and an array of corresponding call data.
2058 * Typically a XConnectionWatchProc registered with XAddConnectionWatch
2059 * will be used instead of this function to discover
2060 * additional fds to include in the select/poll mask.
2061 *
2062 * The list is allocated with Xmalloc and should be freed by the caller
2063 * with Xfree;
2064 */
2065Status
2066XInternalConnectionNumbers(
2067    Display *dpy,
2068    int **fd_return,
2069    int *count_return
2070)
2071{
2072    int count;
2073    struct _XConnectionInfo *info_list;
2074    int *fd_list;
2075
2076    LockDisplay(dpy);
2077    count = 0;
2078    for (info_list=dpy->im_fd_info; info_list; info_list=info_list->next)
2079	count++;
2080    fd_list = (int*) Xmalloc (count * sizeof(int));
2081    if (!fd_list) {
2082	UnlockDisplay(dpy);
2083	return 0;
2084    }
2085    count = 0;
2086    for (info_list=dpy->im_fd_info; info_list; info_list=info_list->next) {
2087	fd_list[count] = info_list->fd;
2088	count++;
2089    }
2090    UnlockDisplay(dpy);
2091
2092    *fd_return = fd_list;
2093    *count_return = count;
2094    return 1;
2095}
2096
2097void _XProcessInternalConnection(
2098    Display *dpy,
2099    struct _XConnectionInfo *conn_info)
2100{
2101    dpy->flags |= XlibDisplayProcConni;
2102#if defined(XTHREADS) && !USE_XCB
2103    if (dpy->lock) {
2104	/* check cache to avoid call to thread_self */
2105	if (xthread_have_id(dpy->lock->reading_thread))
2106	    dpy->lock->conni_thread = dpy->lock->reading_thread;
2107	else
2108	    dpy->lock->conni_thread = XThread_Self();
2109    }
2110#endif /* XTHREADS && !USE_XCB */
2111    UnlockDisplay(dpy);
2112    (*conn_info->read_callback) (dpy, conn_info->fd, conn_info->call_data);
2113    LockDisplay(dpy);
2114#if defined(XTHREADS) && !USE_XCB
2115    if (dpy->lock)
2116	xthread_clear_id(dpy->lock->conni_thread);
2117#endif /* XTHREADS && !USE_XCB */
2118    dpy->flags &= ~XlibDisplayProcConni;
2119}
2120
2121/* XProcessInternalConnection
2122 * Call the _XInternalConnectionProc registered by _XRegisterInternalConnection
2123 * for this fd.
2124 * The Display is NOT locked during the call.
2125 */
2126void
2127XProcessInternalConnection(
2128    Display* dpy,
2129    int fd
2130)
2131{
2132    struct _XConnectionInfo *info_list;
2133
2134    LockDisplay(dpy);
2135    for (info_list=dpy->im_fd_info; info_list; info_list=info_list->next) {
2136	if (info_list->fd == fd) {
2137	    _XProcessInternalConnection(dpy, info_list);
2138	    break;
2139	}
2140    }
2141    UnlockDisplay(dpy);
2142}
2143
2144/* XAddConnectionWatch
2145 * Register a callback to be called whenever _XRegisterInternalConnection
2146 * or _XUnregisterInternalConnection is called.
2147 * Callbacks are called with the Display locked.
2148 * If any connections are already registered, the callback is immediately
2149 * called for each of them.
2150 */
2151Status
2152XAddConnectionWatch(
2153    Display* dpy,
2154    XConnectionWatchProc callback,
2155    XPointer client_data
2156)
2157{
2158    struct _XConnWatchInfo *new_watcher, **wptr;
2159    struct _XConnectionInfo *info_list;
2160    XPointer *wd_array;
2161
2162    LockDisplay(dpy);
2163
2164    /* allocate new watch data */
2165    for (info_list=dpy->im_fd_info; info_list; info_list=info_list->next) {
2166	wd_array = (XPointer *)Xrealloc((char *)info_list->watch_data,
2167					(dpy->watcher_count + 1) *
2168					sizeof(XPointer));
2169	if (!wd_array) {
2170	    UnlockDisplay(dpy);
2171	    return 0;
2172	}
2173	wd_array[dpy->watcher_count] = NULL;	/* for cleanliness */
2174    }
2175
2176    new_watcher = (struct _XConnWatchInfo*)Xmalloc(sizeof(struct _XConnWatchInfo));
2177    if (!new_watcher) {
2178	UnlockDisplay(dpy);
2179	return 0;
2180    }
2181    new_watcher->fn = callback;
2182    new_watcher->client_data = client_data;
2183    new_watcher->next = NULL;
2184
2185    /* link new structure onto end of list */
2186    for (wptr = &dpy->conn_watchers; *wptr; wptr = &(*wptr)->next)
2187	;
2188    *wptr = new_watcher;
2189    dpy->watcher_count++;
2190
2191    /* call new watcher on all currently registered fds */
2192    for (info_list=dpy->im_fd_info; info_list; info_list=info_list->next) {
2193	(*callback) (dpy, client_data, info_list->fd, True,
2194		     info_list->watch_data + dpy->watcher_count - 1);
2195    }
2196
2197    UnlockDisplay(dpy);
2198    return 1;
2199}
2200
2201/* XRemoveConnectionWatch
2202 * Unregister a callback registered by XAddConnectionWatch.
2203 * Both callback and client_data must match what was passed to
2204 * XAddConnectionWatch.
2205 */
2206void
2207XRemoveConnectionWatch(
2208    Display* dpy,
2209    XConnectionWatchProc callback,
2210    XPointer client_data
2211)
2212{
2213    struct _XConnWatchInfo *watch;
2214    struct _XConnWatchInfo *previous = NULL;
2215    struct _XConnectionInfo *conni;
2216    int counter = 0;
2217
2218    LockDisplay(dpy);
2219    for (watch=dpy->conn_watchers; watch; watch=watch->next) {
2220	if (watch->fn == callback  &&  watch->client_data == client_data) {
2221	    if (previous)
2222		previous->next = watch->next;
2223	    else
2224		dpy->conn_watchers = watch->next;
2225	    Xfree (watch);
2226	    dpy->watcher_count--;
2227	    /* remove our watch_data for each connection */
2228	    for (conni=dpy->im_fd_info; conni; conni=conni->next) {
2229		/* don't bother realloc'ing; these arrays are small anyway */
2230		/* overlapping */
2231		memmove(conni->watch_data+counter,
2232			conni->watch_data+counter+1,
2233			dpy->watcher_count - counter);
2234	    }
2235	    break;
2236	}
2237	previous = watch;
2238	counter++;
2239    }
2240    UnlockDisplay(dpy);
2241}
2242
2243/* end of internal connections support */
2244
2245
2246#if !USE_XCB
2247/* Read and discard "n" 8-bit bytes of data */
2248
2249void _XEatData(
2250    Display *dpy,
2251    register unsigned long n)
2252{
2253#define SCRATCHSIZE 2048
2254    char buf[SCRATCHSIZE];
2255
2256    while (n > 0) {
2257	register long bytes_read = (n > SCRATCHSIZE) ? SCRATCHSIZE : n;
2258	(void) _XRead (dpy, buf, bytes_read);
2259	n -= bytes_read;
2260    }
2261#undef SCRATCHSIZE
2262}
2263#endif /* !USE_XCB */
2264
2265
2266/*
2267 * _XEnq - Place event packets on the display's queue.
2268 * note that no squishing of move events in V11, since there
2269 * is pointer motion hints....
2270 */
2271void _XEnq(
2272	register Display *dpy,
2273	register xEvent *event)
2274{
2275	register _XQEvent *qelt;
2276
2277	if ((qelt = dpy->qfree)) {
2278		/* If dpy->qfree is non-NULL do this, else malloc a new one. */
2279		dpy->qfree = qelt->next;
2280	}
2281	else if ((qelt =
2282	    (_XQEvent *) Xmalloc((unsigned)sizeof(_XQEvent))) == NULL) {
2283		/* Malloc call failed! */
2284		ESET(ENOMEM);
2285		_XIOError(dpy);
2286	}
2287	qelt->next = NULL;
2288	/* go call through display to find proper event reformatter */
2289	if ((*dpy->event_vec[event->u.u.type & 0177])(dpy, &qelt->event, event)) {
2290	    qelt->qserial_num = dpy->next_event_serial_num++;
2291	    if (dpy->tail)	dpy->tail->next = qelt;
2292	    else 		dpy->head = qelt;
2293
2294	    dpy->tail = qelt;
2295	    dpy->qlen++;
2296	} else {
2297	    /* ignored, or stashed away for many-to-one compression */
2298	    qelt->next = dpy->qfree;
2299	    dpy->qfree = qelt;
2300	}
2301}
2302
2303/*
2304 * _XDeq - Remove event packet from the display's queue.
2305 */
2306void _XDeq(
2307    register Display *dpy,
2308    register _XQEvent *prev,	/* element before qelt */
2309    register _XQEvent *qelt)	/* element to be unlinked */
2310{
2311    if (prev) {
2312	if ((prev->next = qelt->next) == NULL)
2313	    dpy->tail = prev;
2314    } else {
2315	/* no prev, so removing first elt */
2316	if ((dpy->head = qelt->next) == NULL)
2317	    dpy->tail = NULL;
2318    }
2319    qelt->qserial_num = 0;
2320    qelt->next = dpy->qfree;
2321    dpy->qfree = qelt;
2322    dpy->qlen--;
2323}
2324
2325/*
2326 * EventToWire in separate file in that often not needed.
2327 */
2328
2329/*ARGSUSED*/
2330Bool
2331_XUnknownWireEvent(
2332    register Display *dpy,	/* pointer to display structure */
2333    register XEvent *re,	/* pointer to where event should be reformatted */
2334    register xEvent *event)	/* wire protocol event */
2335{
2336#ifdef notdef
2337	(void) fprintf(stderr,
2338	    "Xlib: unhandled wire event! event number = %d, display = %x\n.",
2339			event->u.u.type, dpy);
2340#endif
2341	return(False);
2342}
2343
2344/*ARGSUSED*/
2345Status
2346_XUnknownNativeEvent(
2347    register Display *dpy,	/* pointer to display structure */
2348    register XEvent *re,	/* pointer to where event should be reformatted */
2349    register xEvent *event)	/* wire protocol event */
2350{
2351#ifdef notdef
2352	(void) fprintf(stderr,
2353 	   "Xlib: unhandled native event! event number = %d, display = %x\n.",
2354			re->type, dpy);
2355#endif
2356	return(0);
2357}
2358/*
2359 * reformat a wire event into an XEvent structure of the right type.
2360 */
2361Bool
2362_XWireToEvent(
2363    register Display *dpy,	/* pointer to display structure */
2364    register XEvent *re,	/* pointer to where event should be reformatted */
2365    register xEvent *event)	/* wire protocol event */
2366{
2367
2368	re->type = event->u.u.type & 0x7f;
2369	((XAnyEvent *)re)->serial = _XSetLastRequestRead(dpy,
2370					(xGenericReply *)event);
2371	((XAnyEvent *)re)->send_event = ((event->u.u.type & 0x80) != 0);
2372	((XAnyEvent *)re)->display = dpy;
2373
2374	/* Ignore the leading bit of the event type since it is set when a
2375		client sends an event rather than the server. */
2376
2377	switch (event-> u.u.type & 0177) {
2378	      case KeyPress:
2379	      case KeyRelease:
2380	        {
2381			register XKeyEvent *ev = (XKeyEvent*) re;
2382			ev->root 	= event->u.keyButtonPointer.root;
2383			ev->window 	= event->u.keyButtonPointer.event;
2384			ev->subwindow 	= event->u.keyButtonPointer.child;
2385			ev->time 	= event->u.keyButtonPointer.time;
2386			ev->x 		= cvtINT16toInt(event->u.keyButtonPointer.eventX);
2387			ev->y 		= cvtINT16toInt(event->u.keyButtonPointer.eventY);
2388			ev->x_root 	= cvtINT16toInt(event->u.keyButtonPointer.rootX);
2389			ev->y_root 	= cvtINT16toInt(event->u.keyButtonPointer.rootY);
2390			ev->state	= event->u.keyButtonPointer.state;
2391			ev->same_screen	= event->u.keyButtonPointer.sameScreen;
2392			ev->keycode 	= event->u.u.detail;
2393		}
2394	      	break;
2395	      case ButtonPress:
2396	      case ButtonRelease:
2397	        {
2398			register XButtonEvent *ev =  (XButtonEvent *) re;
2399			ev->root 	= event->u.keyButtonPointer.root;
2400			ev->window 	= event->u.keyButtonPointer.event;
2401			ev->subwindow 	= event->u.keyButtonPointer.child;
2402			ev->time 	= event->u.keyButtonPointer.time;
2403			ev->x 		= cvtINT16toInt(event->u.keyButtonPointer.eventX);
2404			ev->y 		= cvtINT16toInt(event->u.keyButtonPointer.eventY);
2405			ev->x_root 	= cvtINT16toInt(event->u.keyButtonPointer.rootX);
2406			ev->y_root 	= cvtINT16toInt(event->u.keyButtonPointer.rootY);
2407			ev->state	= event->u.keyButtonPointer.state;
2408			ev->same_screen	= event->u.keyButtonPointer.sameScreen;
2409			ev->button 	= event->u.u.detail;
2410		}
2411	        break;
2412	      case MotionNotify:
2413	        {
2414			register XMotionEvent *ev =   (XMotionEvent *)re;
2415			ev->root 	= event->u.keyButtonPointer.root;
2416			ev->window 	= event->u.keyButtonPointer.event;
2417			ev->subwindow 	= event->u.keyButtonPointer.child;
2418			ev->time 	= event->u.keyButtonPointer.time;
2419			ev->x 		= cvtINT16toInt(event->u.keyButtonPointer.eventX);
2420			ev->y 		= cvtINT16toInt(event->u.keyButtonPointer.eventY);
2421			ev->x_root 	= cvtINT16toInt(event->u.keyButtonPointer.rootX);
2422			ev->y_root 	= cvtINT16toInt(event->u.keyButtonPointer.rootY);
2423			ev->state	= event->u.keyButtonPointer.state;
2424			ev->same_screen	= event->u.keyButtonPointer.sameScreen;
2425			ev->is_hint 	= event->u.u.detail;
2426		}
2427	        break;
2428	      case EnterNotify:
2429	      case LeaveNotify:
2430		{
2431			register XCrossingEvent *ev   = (XCrossingEvent *) re;
2432			ev->root	= event->u.enterLeave.root;
2433			ev->window	= event->u.enterLeave.event;
2434			ev->subwindow	= event->u.enterLeave.child;
2435			ev->time	= event->u.enterLeave.time;
2436			ev->x		= cvtINT16toInt(event->u.enterLeave.eventX);
2437			ev->y		= cvtINT16toInt(event->u.enterLeave.eventY);
2438			ev->x_root	= cvtINT16toInt(event->u.enterLeave.rootX);
2439			ev->y_root	= cvtINT16toInt(event->u.enterLeave.rootY);
2440			ev->state	= event->u.enterLeave.state;
2441			ev->mode	= event->u.enterLeave.mode;
2442			ev->same_screen = (event->u.enterLeave.flags &
2443				ELFlagSameScreen) && True;
2444			ev->focus	= (event->u.enterLeave.flags &
2445			  	ELFlagFocus) && True;
2446			ev->detail	= event->u.u.detail;
2447		}
2448		  break;
2449	      case FocusIn:
2450	      case FocusOut:
2451		{
2452			register XFocusChangeEvent *ev = (XFocusChangeEvent *) re;
2453			ev->window 	= event->u.focus.window;
2454			ev->mode	= event->u.focus.mode;
2455			ev->detail	= event->u.u.detail;
2456		}
2457		  break;
2458	      case KeymapNotify:
2459		{
2460			register XKeymapEvent *ev = (XKeymapEvent *) re;
2461			ev->window	= None;
2462			memcpy(&ev->key_vector[1],
2463			       (char *)((xKeymapEvent *) event)->map,
2464			       sizeof (((xKeymapEvent *) event)->map));
2465		}
2466		break;
2467	      case Expose:
2468		{
2469			register XExposeEvent *ev = (XExposeEvent *) re;
2470			ev->window	= event->u.expose.window;
2471			ev->x		= event->u.expose.x;
2472			ev->y		= event->u.expose.y;
2473			ev->width	= event->u.expose.width;
2474			ev->height	= event->u.expose.height;
2475			ev->count	= event->u.expose.count;
2476		}
2477		break;
2478	      case GraphicsExpose:
2479		{
2480		    register XGraphicsExposeEvent *ev =
2481			(XGraphicsExposeEvent *) re;
2482		    ev->drawable	= event->u.graphicsExposure.drawable;
2483		    ev->x		= event->u.graphicsExposure.x;
2484		    ev->y		= event->u.graphicsExposure.y;
2485		    ev->width		= event->u.graphicsExposure.width;
2486		    ev->height		= event->u.graphicsExposure.height;
2487		    ev->count		= event->u.graphicsExposure.count;
2488		    ev->major_code	= event->u.graphicsExposure.majorEvent;
2489		    ev->minor_code	= event->u.graphicsExposure.minorEvent;
2490		}
2491		break;
2492	      case NoExpose:
2493		{
2494		    register XNoExposeEvent *ev = (XNoExposeEvent *) re;
2495		    ev->drawable	= event->u.noExposure.drawable;
2496		    ev->major_code	= event->u.noExposure.majorEvent;
2497		    ev->minor_code	= event->u.noExposure.minorEvent;
2498		}
2499		break;
2500	      case VisibilityNotify:
2501		{
2502		    register XVisibilityEvent *ev = (XVisibilityEvent *) re;
2503		    ev->window		= event->u.visibility.window;
2504		    ev->state		= event->u.visibility.state;
2505		}
2506		break;
2507	      case CreateNotify:
2508		{
2509		    register XCreateWindowEvent *ev =
2510			 (XCreateWindowEvent *) re;
2511		    ev->window		= event->u.createNotify.window;
2512		    ev->parent		= event->u.createNotify.parent;
2513		    ev->x		= cvtINT16toInt(event->u.createNotify.x);
2514		    ev->y		= cvtINT16toInt(event->u.createNotify.y);
2515		    ev->width		= event->u.createNotify.width;
2516		    ev->height		= event->u.createNotify.height;
2517		    ev->border_width	= event->u.createNotify.borderWidth;
2518		    ev->override_redirect	= event->u.createNotify.override;
2519		}
2520		break;
2521	      case DestroyNotify:
2522		{
2523		    register XDestroyWindowEvent *ev =
2524				(XDestroyWindowEvent *) re;
2525		    ev->window		= event->u.destroyNotify.window;
2526		    ev->event		= event->u.destroyNotify.event;
2527		}
2528		break;
2529	      case UnmapNotify:
2530		{
2531		    register XUnmapEvent *ev = (XUnmapEvent *) re;
2532		    ev->window		= event->u.unmapNotify.window;
2533		    ev->event		= event->u.unmapNotify.event;
2534		    ev->from_configure	= event->u.unmapNotify.fromConfigure;
2535		}
2536		break;
2537	      case MapNotify:
2538		{
2539		    register XMapEvent *ev = (XMapEvent *) re;
2540		    ev->window		= event->u.mapNotify.window;
2541		    ev->event		= event->u.mapNotify.event;
2542		    ev->override_redirect	= event->u.mapNotify.override;
2543		}
2544		break;
2545	      case MapRequest:
2546		{
2547		    register XMapRequestEvent *ev = (XMapRequestEvent *) re;
2548		    ev->window		= event->u.mapRequest.window;
2549		    ev->parent		= event->u.mapRequest.parent;
2550		}
2551		break;
2552	      case ReparentNotify:
2553		{
2554		    register XReparentEvent *ev = (XReparentEvent *) re;
2555		    ev->event		= event->u.reparent.event;
2556		    ev->window		= event->u.reparent.window;
2557		    ev->parent		= event->u.reparent.parent;
2558		    ev->x		= cvtINT16toInt(event->u.reparent.x);
2559		    ev->y		= cvtINT16toInt(event->u.reparent.y);
2560		    ev->override_redirect	= event->u.reparent.override;
2561		}
2562		break;
2563	      case ConfigureNotify:
2564		{
2565		    register XConfigureEvent *ev = (XConfigureEvent *) re;
2566		    ev->event	= event->u.configureNotify.event;
2567		    ev->window	= event->u.configureNotify.window;
2568		    ev->above	= event->u.configureNotify.aboveSibling;
2569		    ev->x	= cvtINT16toInt(event->u.configureNotify.x);
2570		    ev->y	= cvtINT16toInt(event->u.configureNotify.y);
2571		    ev->width	= event->u.configureNotify.width;
2572		    ev->height	= event->u.configureNotify.height;
2573		    ev->border_width  = event->u.configureNotify.borderWidth;
2574		    ev->override_redirect = event->u.configureNotify.override;
2575		}
2576		break;
2577	      case ConfigureRequest:
2578		{
2579		    register XConfigureRequestEvent *ev =
2580		        (XConfigureRequestEvent *) re;
2581		    ev->window		= event->u.configureRequest.window;
2582		    ev->parent		= event->u.configureRequest.parent;
2583		    ev->above		= event->u.configureRequest.sibling;
2584		    ev->x		= cvtINT16toInt(event->u.configureRequest.x);
2585		    ev->y		= cvtINT16toInt(event->u.configureRequest.y);
2586		    ev->width		= event->u.configureRequest.width;
2587		    ev->height		= event->u.configureRequest.height;
2588		    ev->border_width	= event->u.configureRequest.borderWidth;
2589		    ev->value_mask	= event->u.configureRequest.valueMask;
2590		    ev->detail  	= event->u.u.detail;
2591		}
2592		break;
2593	      case GravityNotify:
2594		{
2595		    register XGravityEvent *ev = (XGravityEvent *) re;
2596		    ev->window		= event->u.gravity.window;
2597		    ev->event		= event->u.gravity.event;
2598		    ev->x		= cvtINT16toInt(event->u.gravity.x);
2599		    ev->y		= cvtINT16toInt(event->u.gravity.y);
2600		}
2601		break;
2602	      case ResizeRequest:
2603		{
2604		    register XResizeRequestEvent *ev =
2605			(XResizeRequestEvent *) re;
2606		    ev->window		= event->u.resizeRequest.window;
2607		    ev->width		= event->u.resizeRequest.width;
2608		    ev->height		= event->u.resizeRequest.height;
2609		}
2610		break;
2611	      case CirculateNotify:
2612		{
2613		    register XCirculateEvent *ev = (XCirculateEvent *) re;
2614		    ev->window		= event->u.circulate.window;
2615		    ev->event		= event->u.circulate.event;
2616		    ev->place		= event->u.circulate.place;
2617		}
2618		break;
2619	      case CirculateRequest:
2620		{
2621		    register XCirculateRequestEvent *ev =
2622		        (XCirculateRequestEvent *) re;
2623		    ev->window		= event->u.circulate.window;
2624		    ev->parent		= event->u.circulate.event;
2625		    ev->place		= event->u.circulate.place;
2626		}
2627		break;
2628	      case PropertyNotify:
2629		{
2630		    register XPropertyEvent *ev = (XPropertyEvent *) re;
2631		    ev->window		= event->u.property.window;
2632		    ev->atom		= event->u.property.atom;
2633		    ev->time		= event->u.property.time;
2634		    ev->state		= event->u.property.state;
2635		}
2636		break;
2637	      case SelectionClear:
2638		{
2639		    register XSelectionClearEvent *ev =
2640			 (XSelectionClearEvent *) re;
2641		    ev->window		= event->u.selectionClear.window;
2642		    ev->selection	= event->u.selectionClear.atom;
2643		    ev->time		= event->u.selectionClear.time;
2644		}
2645		break;
2646	      case SelectionRequest:
2647		{
2648		    register XSelectionRequestEvent *ev =
2649		        (XSelectionRequestEvent *) re;
2650		    ev->owner		= event->u.selectionRequest.owner;
2651		    ev->requestor	= event->u.selectionRequest.requestor;
2652		    ev->selection	= event->u.selectionRequest.selection;
2653		    ev->target		= event->u.selectionRequest.target;
2654		    ev->property	= event->u.selectionRequest.property;
2655		    ev->time		= event->u.selectionRequest.time;
2656		}
2657		break;
2658	      case SelectionNotify:
2659		{
2660		    register XSelectionEvent *ev = (XSelectionEvent *) re;
2661		    ev->requestor	= event->u.selectionNotify.requestor;
2662		    ev->selection	= event->u.selectionNotify.selection;
2663		    ev->target		= event->u.selectionNotify.target;
2664		    ev->property	= event->u.selectionNotify.property;
2665		    ev->time		= event->u.selectionNotify.time;
2666		}
2667		break;
2668	      case ColormapNotify:
2669		{
2670		    register XColormapEvent *ev = (XColormapEvent *) re;
2671		    ev->window		= event->u.colormap.window;
2672		    ev->colormap	= event->u.colormap.colormap;
2673		    ev->new		= event->u.colormap.new;
2674		    ev->state		= event->u.colormap.state;
2675	        }
2676		break;
2677	      case ClientMessage:
2678		{
2679		   register int i;
2680		   register XClientMessageEvent *ev
2681		   			= (XClientMessageEvent *) re;
2682		   ev->window		= event->u.clientMessage.window;
2683		   ev->format		= event->u.u.detail;
2684		   switch (ev->format) {
2685			case 8:
2686			   ev->message_type = event->u.clientMessage.u.b.type;
2687			   for (i = 0; i < 20; i++)
2688			     ev->data.b[i] = event->u.clientMessage.u.b.bytes[i];
2689			   break;
2690			case 16:
2691			   ev->message_type = event->u.clientMessage.u.s.type;
2692			   ev->data.s[0] = cvtINT16toShort(event->u.clientMessage.u.s.shorts0);
2693			   ev->data.s[1] = cvtINT16toShort(event->u.clientMessage.u.s.shorts1);
2694			   ev->data.s[2] = cvtINT16toShort(event->u.clientMessage.u.s.shorts2);
2695			   ev->data.s[3] = cvtINT16toShort(event->u.clientMessage.u.s.shorts3);
2696			   ev->data.s[4] = cvtINT16toShort(event->u.clientMessage.u.s.shorts4);
2697			   ev->data.s[5] = cvtINT16toShort(event->u.clientMessage.u.s.shorts5);
2698			   ev->data.s[6] = cvtINT16toShort(event->u.clientMessage.u.s.shorts6);
2699			   ev->data.s[7] = cvtINT16toShort(event->u.clientMessage.u.s.shorts7);
2700			   ev->data.s[8] = cvtINT16toShort(event->u.clientMessage.u.s.shorts8);
2701			   ev->data.s[9] = cvtINT16toShort(event->u.clientMessage.u.s.shorts9);
2702			   break;
2703			case 32:
2704			   ev->message_type = event->u.clientMessage.u.l.type;
2705			   ev->data.l[0] = cvtINT32toLong(event->u.clientMessage.u.l.longs0);
2706			   ev->data.l[1] = cvtINT32toLong(event->u.clientMessage.u.l.longs1);
2707			   ev->data.l[2] = cvtINT32toLong(event->u.clientMessage.u.l.longs2);
2708			   ev->data.l[3] = cvtINT32toLong(event->u.clientMessage.u.l.longs3);
2709			   ev->data.l[4] = cvtINT32toLong(event->u.clientMessage.u.l.longs4);
2710			   break;
2711			default: /* XXX should never occur */
2712				break;
2713		    }
2714	        }
2715		break;
2716	      case MappingNotify:
2717		{
2718		   register XMappingEvent *ev = (XMappingEvent *)re;
2719		   ev->window		= 0;
2720		   ev->first_keycode 	= event->u.mappingNotify.firstKeyCode;
2721		   ev->request 		= event->u.mappingNotify.request;
2722		   ev->count 		= event->u.mappingNotify.count;
2723		}
2724		break;
2725	      default:
2726		return(_XUnknownWireEvent(dpy, re, event));
2727	}
2728	return(True);
2729}
2730
2731
2732/*
2733 * _XDefaultIOError - Default fatal system error reporting routine.  Called
2734 * when an X internal system error is encountered.
2735 */
2736int _XDefaultIOError(
2737	Display *dpy)
2738{
2739	if (ECHECK(EPIPE)) {
2740	    (void) fprintf (stderr,
2741	"X connection to %s broken (explicit kill or server shutdown).\r\n",
2742			    DisplayString (dpy));
2743	} else {
2744	    (void) fprintf (stderr,
2745			"XIO:  fatal IO error %d (%s) on X server \"%s\"\r\n",
2746#ifdef WIN32
2747			WSAGetLastError(), strerror(WSAGetLastError()),
2748#else
2749			errno, strerror (errno),
2750#endif
2751			DisplayString (dpy));
2752	    (void) fprintf (stderr,
2753	 "      after %lu requests (%lu known processed) with %d events remaining.\r\n",
2754			NextRequest(dpy) - 1, LastKnownRequestProcessed(dpy),
2755			QLength(dpy));
2756
2757	}
2758	exit(1);
2759        return(0); /* dummy - function should never return */
2760}
2761
2762
2763static int _XPrintDefaultError(
2764    Display *dpy,
2765    XErrorEvent *event,
2766    FILE *fp)
2767{
2768    char buffer[BUFSIZ];
2769    char mesg[BUFSIZ];
2770    char number[32];
2771    const char *mtype = "XlibMessage";
2772    register _XExtension *ext = (_XExtension *)NULL;
2773    _XExtension *bext = (_XExtension *)NULL;
2774    XGetErrorText(dpy, event->error_code, buffer, BUFSIZ);
2775    XGetErrorDatabaseText(dpy, mtype, "XError", "X Error", mesg, BUFSIZ);
2776    (void) fprintf(fp, "%s:  %s\n  ", mesg, buffer);
2777    XGetErrorDatabaseText(dpy, mtype, "MajorCode", "Request Major code %d",
2778	mesg, BUFSIZ);
2779    (void) fprintf(fp, mesg, event->request_code);
2780    if (event->request_code < 128) {
2781	sprintf(number, "%d", event->request_code);
2782	XGetErrorDatabaseText(dpy, "XRequest", number, "", buffer, BUFSIZ);
2783    } else {
2784	for (ext = dpy->ext_procs;
2785	     ext && (ext->codes.major_opcode != event->request_code);
2786	     ext = ext->next)
2787	  ;
2788	if (ext)
2789	    strcpy(buffer, ext->name);
2790	else
2791	    buffer[0] = '\0';
2792    }
2793    (void) fprintf(fp, " (%s)\n", buffer);
2794    if (event->request_code >= 128) {
2795	XGetErrorDatabaseText(dpy, mtype, "MinorCode", "Request Minor code %d",
2796			      mesg, BUFSIZ);
2797	fputs("  ", fp);
2798	(void) fprintf(fp, mesg, event->minor_code);
2799	if (ext) {
2800	    sprintf(mesg, "%s.%d", ext->name, event->minor_code);
2801	    XGetErrorDatabaseText(dpy, "XRequest", mesg, "", buffer, BUFSIZ);
2802	    (void) fprintf(fp, " (%s)", buffer);
2803	}
2804	fputs("\n", fp);
2805    }
2806    if (event->error_code >= 128) {
2807	/* kludge, try to find the extension that caused it */
2808	buffer[0] = '\0';
2809	for (ext = dpy->ext_procs; ext; ext = ext->next) {
2810	    if (ext->error_string)
2811		(*ext->error_string)(dpy, event->error_code, &ext->codes,
2812				     buffer, BUFSIZ);
2813	    if (buffer[0]) {
2814		bext = ext;
2815		break;
2816	    }
2817	    if (ext->codes.first_error &&
2818		ext->codes.first_error < (int)event->error_code &&
2819		(!bext || ext->codes.first_error > bext->codes.first_error))
2820		bext = ext;
2821	}
2822	if (bext)
2823	    sprintf(buffer, "%s.%d", bext->name,
2824		    event->error_code - bext->codes.first_error);
2825	else
2826	    strcpy(buffer, "Value");
2827	XGetErrorDatabaseText(dpy, mtype, buffer, "", mesg, BUFSIZ);
2828	if (mesg[0]) {
2829	    fputs("  ", fp);
2830	    (void) fprintf(fp, mesg, event->resourceid);
2831	    fputs("\n", fp);
2832	}
2833	/* let extensions try to print the values */
2834	for (ext = dpy->ext_procs; ext; ext = ext->next) {
2835	    if (ext->error_values)
2836		(*ext->error_values)(dpy, event, fp);
2837	}
2838    } else if ((event->error_code == BadWindow) ||
2839	       (event->error_code == BadPixmap) ||
2840	       (event->error_code == BadCursor) ||
2841	       (event->error_code == BadFont) ||
2842	       (event->error_code == BadDrawable) ||
2843	       (event->error_code == BadColor) ||
2844	       (event->error_code == BadGC) ||
2845	       (event->error_code == BadIDChoice) ||
2846	       (event->error_code == BadValue) ||
2847	       (event->error_code == BadAtom)) {
2848	if (event->error_code == BadValue)
2849	    XGetErrorDatabaseText(dpy, mtype, "Value", "Value 0x%x",
2850				  mesg, BUFSIZ);
2851	else if (event->error_code == BadAtom)
2852	    XGetErrorDatabaseText(dpy, mtype, "AtomID", "AtomID 0x%x",
2853				  mesg, BUFSIZ);
2854	else
2855	    XGetErrorDatabaseText(dpy, mtype, "ResourceID", "ResourceID 0x%x",
2856				  mesg, BUFSIZ);
2857	fputs("  ", fp);
2858	(void) fprintf(fp, mesg, event->resourceid);
2859	fputs("\n", fp);
2860    }
2861    XGetErrorDatabaseText(dpy, mtype, "ErrorSerial", "Error Serial #%d",
2862			  mesg, BUFSIZ);
2863    fputs("  ", fp);
2864    (void) fprintf(fp, mesg, event->serial);
2865    XGetErrorDatabaseText(dpy, mtype, "CurrentSerial", "Current Serial #%d",
2866			  mesg, BUFSIZ);
2867    fputs("\n  ", fp);
2868    (void) fprintf(fp, mesg, dpy->request);
2869    fputs("\n", fp);
2870    if (event->error_code == BadImplementation) return 0;
2871    return 1;
2872}
2873
2874int _XDefaultError(
2875	Display *dpy,
2876	XErrorEvent *event)
2877{
2878    if (_XPrintDefaultError (dpy, event, stderr) == 0) return 0;
2879    exit(1);
2880    /*NOTREACHED*/
2881}
2882
2883/*ARGSUSED*/
2884Bool _XDefaultWireError(Display *display, XErrorEvent *he, xError *we)
2885{
2886    return True;
2887}
2888
2889/*
2890 * _XError - upcall internal or user protocol error handler
2891 */
2892int _XError (
2893    Display *dpy,
2894    register xError *rep)
2895{
2896    /*
2897     * X_Error packet encountered!  We need to unpack the error before
2898     * giving it to the user.
2899     */
2900    XEvent event; /* make it a large event */
2901    register _XAsyncHandler *async, *next;
2902
2903    event.xerror.serial = _XSetLastRequestRead(dpy, (xGenericReply *)rep);
2904
2905    for (async = dpy->async_handlers; async; async = next) {
2906	next = async->next;
2907	if ((*async->handler)(dpy, (xReply *)rep,
2908			      (char *)rep, SIZEOF(xError), async->data))
2909	    return 0;
2910    }
2911
2912    event.xerror.display = dpy;
2913    event.xerror.type = X_Error;
2914    event.xerror.resourceid = rep->resourceID;
2915    event.xerror.error_code = rep->errorCode;
2916    event.xerror.request_code = rep->majorCode;
2917    event.xerror.minor_code = rep->minorCode;
2918    if (dpy->error_vec &&
2919	!(*dpy->error_vec[rep->errorCode])(dpy, &event.xerror, rep))
2920	return 0;
2921    if (_XErrorFunction != NULL) {
2922	int rtn_val;
2923#if defined(XTHREADS) && !USE_XCB
2924	if (dpy->lock)
2925	    (*dpy->lock->user_lock_display)(dpy);
2926	UnlockDisplay(dpy);
2927#endif /* XTHREADS && !USE_XCB */
2928	rtn_val = (*_XErrorFunction)(dpy, (XErrorEvent *)&event); /* upcall */
2929#if defined(XTHREADS) && !USE_XCB
2930	LockDisplay(dpy);
2931	if (dpy->lock)
2932	    (*dpy->lock->user_unlock_display)(dpy);
2933#endif /* XTHREADS && !USE_XCB */
2934	return rtn_val;
2935    } else {
2936	return _XDefaultError(dpy, (XErrorEvent *)&event);
2937    }
2938}
2939
2940/*
2941 * _XIOError - call user connection error handler and exit
2942 */
2943int
2944_XIOError (
2945    Display *dpy)
2946{
2947    dpy->flags |= XlibDisplayIOError;
2948#ifdef WIN32
2949    errno = WSAGetLastError();
2950#endif
2951
2952    /* This assumes that the thread calling exit will call any atexit handlers.
2953     * If this does not hold, then an alternate solution would involve
2954     * registering an atexit handler to take over the lock, which would only
2955     * assume that the same thread calls all the atexit handlers. */
2956#ifdef XTHREADS
2957    if (dpy->lock)
2958	(*dpy->lock->user_lock_display)(dpy);
2959#endif
2960    UnlockDisplay(dpy);
2961
2962    if (_XIOErrorFunction != NULL)
2963	(*_XIOErrorFunction)(dpy);
2964    else
2965	_XDefaultIOError(dpy);
2966    exit (1);
2967    return 0;
2968}
2969
2970
2971/*
2972 * This routine can be used to (cheaply) get some memory within a single
2973 * Xlib routine for scratch space.  A single buffer is reused each time
2974 * if possible.  To be MT safe, you can only call this between a call to
2975 * GetReq* and a call to Data* or _XSend*, or in a context when the thread
2976 * is guaranteed to not unlock the display.
2977 */
2978char *_XAllocScratch(
2979	register Display *dpy,
2980	unsigned long nbytes)
2981{
2982	if (nbytes > dpy->scratch_length) {
2983	    if (dpy->scratch_buffer) Xfree (dpy->scratch_buffer);
2984	    if ((dpy->scratch_buffer = Xmalloc((unsigned) nbytes)))
2985		dpy->scratch_length = nbytes;
2986	    else dpy->scratch_length = 0;
2987	}
2988	return (dpy->scratch_buffer);
2989}
2990
2991/*
2992 * Scratch space allocator you can call any time, multiple times, and be
2993 * MT safe, but you must hand the buffer back with _XFreeTemp.
2994 */
2995char *_XAllocTemp(
2996    register Display *dpy,
2997    unsigned long nbytes)
2998{
2999    char *buf;
3000
3001    buf = _XAllocScratch(dpy, nbytes);
3002    dpy->scratch_buffer = NULL;
3003    dpy->scratch_length = 0;
3004    return buf;
3005}
3006
3007void _XFreeTemp(
3008    register Display *dpy,
3009    char *buf,
3010    unsigned long nbytes)
3011{
3012    if (dpy->scratch_buffer)
3013	Xfree(dpy->scratch_buffer);
3014    dpy->scratch_buffer = buf;
3015    dpy->scratch_length = nbytes;
3016}
3017
3018/*
3019 * Given a visual id, find the visual structure for this id on this display.
3020 */
3021Visual *_XVIDtoVisual(
3022	Display *dpy,
3023	VisualID id)
3024{
3025	register int i, j, k;
3026	register Screen *sp;
3027	register Depth *dp;
3028	register Visual *vp;
3029	for (i = 0; i < dpy->nscreens; i++) {
3030		sp = &dpy->screens[i];
3031		for (j = 0; j < sp->ndepths; j++) {
3032			dp = &sp->depths[j];
3033			/* if nvisuals == 0 then visuals will be NULL */
3034			for (k = 0; k < dp->nvisuals; k++) {
3035				vp = &dp->visuals[k];
3036				if (vp->visualid == id) return (vp);
3037			}
3038		}
3039	}
3040	return (NULL);
3041}
3042
3043int
3044XFree (void *data)
3045{
3046	Xfree (data);
3047	return 1;
3048}
3049
3050#ifdef _XNEEDBCOPYFUNC
3051void _Xbcopy(b1, b2, length)
3052    register char *b1, *b2;
3053    register length;
3054{
3055    if (b1 < b2) {
3056	b2 += length;
3057	b1 += length;
3058	while (length--)
3059	    *--b2 = *--b1;
3060    } else {
3061	while (length--)
3062	    *b2++ = *b1++;
3063    }
3064}
3065#endif
3066
3067#ifdef DataRoutineIsProcedure
3068void Data(
3069	Display *dpy,
3070	char *data,
3071	long len)
3072{
3073	if (dpy->bufptr + (len) <= dpy->bufmax) {
3074		memcpy(dpy->bufptr, data, (int)len);
3075		dpy->bufptr += ((len) + 3) & ~3;
3076	} else {
3077		_XSend(dpy, data, len);
3078	}
3079}
3080#endif /* DataRoutineIsProcedure */
3081
3082
3083#ifdef LONG64
3084int
3085_XData32(
3086    Display *dpy,
3087    register long *data,
3088    unsigned len)
3089{
3090    register int *buf;
3091    register long i;
3092
3093    while (len) {
3094	buf = (int *)dpy->bufptr;
3095	i = dpy->bufmax - (char *)buf;
3096	if (!i) {
3097	    _XFlush(dpy);
3098	    continue;
3099	}
3100	if (len < i)
3101	    i = len;
3102	dpy->bufptr = (char *)buf + i;
3103	len -= i;
3104	i >>= 2;
3105	while (--i >= 0)
3106	    *buf++ = *data++;
3107    }
3108    return 0;
3109}
3110#endif /* LONG64 */
3111
3112#ifdef WORD64
3113
3114/*
3115 * XXX This is a *really* stupid way of doing this.  It should just use
3116 * dpy->bufptr directly, taking into account where in the word it is.
3117 */
3118
3119/*
3120 * Data16 - Place 16 bit data in the buffer.
3121 *
3122 * "dpy" is a pointer to a Display.
3123 * "data" is a pointer to the data.
3124 * "len" is the length in bytes of the data.
3125 */
3126
3127static doData16(
3128    register Display *dpy,
3129    short *data,
3130    unsigned len,
3131    char *packbuffer)
3132{
3133    long *lp,*lpack;
3134    long i, nwords,bits;
3135    long mask16 = 0x000000000000ffff;
3136
3137        lp = (long *)data;
3138        lpack = (long *)packbuffer;
3139
3140/*  nwords is the number of 16 bit values to be packed,
3141 *  the low order 16 bits of each word will be packed
3142 *  into 64 bit words
3143 */
3144        nwords = len >> 1;
3145        bits = 48;
3146
3147        for(i=0;i<nwords;i++){
3148	   if (bits == 48) *lpack = 0;
3149           *lpack ^= (*lp & mask16) << bits;
3150           bits -= 16 ;
3151           lp++;
3152           if(bits < 0){
3153               lpack++;
3154               bits = 48;
3155           }
3156        }
3157        Data(dpy, packbuffer, len);
3158}
3159
3160_XData16 (
3161    Display *dpy,
3162    short *data,
3163    unsigned len)
3164{
3165    char packbuffer[PACKBUFFERSIZE];
3166    unsigned nunits = PACKBUFFERSIZE >> 1;
3167
3168    for (; len > PACKBUFFERSIZE; len -= PACKBUFFERSIZE, data += nunits) {
3169	doData16 (dpy, data, PACKBUFFERSIZE, packbuffer);
3170    }
3171    if (len) doData16 (dpy, data, len, packbuffer);
3172}
3173
3174/*
3175 * Data32 - Place 32 bit data in the buffer.
3176 *
3177 * "dpy" is a pointer to a Display.
3178 * "data" is a pointer to the data.
3179 * "len" is the length in bytes of the data.
3180 */
3181
3182static doData32(
3183    register Display *dpy
3184    long *data,
3185    unsigned len,
3186    char *packbuffer)
3187{
3188    long *lp,*lpack;
3189    long i,bits,nwords;
3190    long mask32 = 0x00000000ffffffff;
3191
3192        lpack = (long *) packbuffer;
3193        lp = data;
3194
3195/*  nwords is the number of 32 bit values to be packed
3196 *  the low order 32 bits of each word will be packed
3197 *  into 64 bit words
3198 */
3199        nwords = len >> 2;
3200        bits = 32;
3201
3202        for(i=0;i<nwords;i++){
3203	   if (bits == 32) *lpack = 0;
3204           *lpack ^= (*lp & mask32) << bits;
3205           bits = bits ^32;
3206           lp++;
3207           if(bits)
3208              lpack++;
3209        }
3210        Data(dpy, packbuffer, len);
3211}
3212
3213void _XData32(
3214    Display *dpy,
3215    long *data,
3216    unsigned len)
3217{
3218    char packbuffer[PACKBUFFERSIZE];
3219    unsigned nunits = PACKBUFFERSIZE >> 2;
3220
3221    for (; len > PACKBUFFERSIZE; len -= PACKBUFFERSIZE, data += nunits) {
3222	doData32 (dpy, data, PACKBUFFERSIZE, packbuffer);
3223    }
3224    if (len) doData32 (dpy, data, len, packbuffer);
3225}
3226
3227#endif /* WORD64 */
3228
3229
3230/* Make sure this produces the same string as DefineLocal/DefineSelf in xdm.
3231 * Otherwise, Xau will not be able to find your cookies in the Xauthority file.
3232 *
3233 * Note: POSIX says that the ``nodename'' member of utsname does _not_ have
3234 *       to have sufficient information for interfacing to the network,
3235 *       and so, you may be better off using gethostname (if it exists).
3236 */
3237
3238#if (defined(_POSIX_SOURCE) && !defined(AIXV3) && !defined(__QNX__)) || defined(hpux) || defined(USG) || defined(SVR4)
3239#define NEED_UTSNAME
3240#include <sys/utsname.h>
3241#endif
3242
3243/*
3244 * _XGetHostname - similar to gethostname but allows special processing.
3245 */
3246int _XGetHostname (
3247    char *buf,
3248    int maxlen)
3249{
3250    int len;
3251
3252#ifdef NEED_UTSNAME
3253    struct utsname name;
3254
3255    if (maxlen <= 0 || buf == NULL)
3256	return 0;
3257
3258    uname (&name);
3259    len = strlen (name.nodename);
3260    if (len >= maxlen) len = maxlen - 1;
3261    strncpy (buf, name.nodename, len);
3262    buf[len] = '\0';
3263#else
3264    if (maxlen <= 0 || buf == NULL)
3265	return 0;
3266
3267    buf[0] = '\0';
3268    (void) gethostname (buf, maxlen);
3269    buf [maxlen - 1] = '\0';
3270    len = strlen(buf);
3271#endif /* NEED_UTSNAME */
3272    return len;
3273}
3274
3275
3276/*
3277 * _XScreenOfWindow - get the Screen of a given window
3278 */
3279
3280Screen *_XScreenOfWindow(Display *dpy, Window w)
3281{
3282    register int i;
3283    Window root;
3284    int x, y;				/* dummy variables */
3285    unsigned int width, height, bw, depth;  /* dummy variables */
3286
3287    if (XGetGeometry (dpy, w, &root, &x, &y, &width, &height,
3288		      &bw, &depth) == False) {
3289	return None;
3290    }
3291    for (i = 0; i < ScreenCount (dpy); i++) {	/* find root from list */
3292	if (root == RootWindow (dpy, i)) {
3293	    return ScreenOfDisplay (dpy, i);
3294	}
3295    }
3296    return NULL;
3297}
3298
3299
3300#if defined(WIN32)
3301
3302/*
3303 * These functions are intended to be used internally to Xlib only.
3304 * These functions will always prefix the path with a DOS drive in the
3305 * form "<drive-letter>:". As such, these functions are only suitable
3306 * for use by Xlib function that supply a root-based path to some
3307 * particular file, e.g. <ProjectRoot>/lib/X11/locale/locale.dir will
3308 * be converted to "C:/usr/X11R6.3/lib/X11/locale/locale.dir".
3309 */
3310
3311static int access_file (path, pathbuf, len_pathbuf, pathret)
3312    char* path;
3313    char* pathbuf;
3314    int len_pathbuf;
3315    char** pathret;
3316{
3317    if (access (path, F_OK) == 0) {
3318	if (strlen (path) < len_pathbuf)
3319	    *pathret = pathbuf;
3320	else
3321	    *pathret = Xmalloc (strlen (path) + 1);
3322	if (*pathret) {
3323	    strcpy (*pathret, path);
3324	    return 1;
3325	}
3326    }
3327    return 0;
3328}
3329
3330static int AccessFile (path, pathbuf, len_pathbuf, pathret)
3331    char* path;
3332    char* pathbuf;
3333    int len_pathbuf;
3334    char** pathret;
3335{
3336    unsigned long drives;
3337    int i, len;
3338    char* drive;
3339    char buf[MAX_PATH];
3340    char* bufp;
3341
3342    /* just try the "raw" name first and see if it works */
3343    if (access_file (path, pathbuf, len_pathbuf, pathret))
3344	return 1;
3345
3346    /* try the places set in the environment */
3347    drive = getenv ("_XBASEDRIVE");
3348#ifdef __UNIXOS2__
3349    if (!drive)
3350	drive = getenv ("X11ROOT");
3351#endif
3352    if (!drive)
3353	drive = "C:";
3354    len = strlen (drive) + strlen (path);
3355    if (len < MAX_PATH) bufp = buf;
3356    else bufp = Xmalloc (len + 1);
3357    strcpy (bufp, drive);
3358    strcat (bufp, path);
3359    if (access_file (bufp, pathbuf, len_pathbuf, pathret)) {
3360	if (bufp != buf) Xfree (bufp);
3361	return 1;
3362    }
3363
3364#ifndef __UNIXOS2__
3365    /* one last place to look */
3366    drive = getenv ("HOMEDRIVE");
3367    if (drive) {
3368	len = strlen (drive) + strlen (path);
3369	if (len < MAX_PATH) bufp = buf;
3370	else bufp = Xmalloc (len + 1);
3371	strcpy (bufp, drive);
3372	strcat (bufp, path);
3373	if (access_file (bufp, pathbuf, len_pathbuf, pathret)) {
3374	    if (bufp != buf) Xfree (bufp);
3375	    return 1;
3376	}
3377    }
3378
3379    /* tried everywhere else, go fishing */
3380#define C_DRIVE ('C' - 'A')
3381#define Z_DRIVE ('Z' - 'A')
3382    /* does OS/2 (with or with gcc-emx) have getdrives? */
3383    drives = _getdrives ();
3384    for (i = C_DRIVE; i <= Z_DRIVE; i++) { /* don't check on A: or B: */
3385	if ((1 << i) & drives) {
3386	    len = 2 + strlen (path);
3387	    if (len < MAX_PATH) bufp = buf;
3388	    else bufp = Xmalloc (len + 1);
3389	    *bufp = 'A' + i;
3390	    *(bufp + 1) = ':';
3391	    *(bufp + 2) = '\0';
3392	    strcat (bufp, path);
3393	    if (access_file (bufp, pathbuf, len_pathbuf, pathret)) {
3394		if (bufp != buf) Xfree (bufp);
3395		return 1;
3396	    }
3397	}
3398    }
3399#endif
3400    return 0;
3401}
3402
3403int _XOpenFile(path, flags)
3404    _Xconst char* path;
3405    int flags;
3406{
3407    char buf[MAX_PATH];
3408    char* bufp = NULL;
3409    int ret = -1;
3410    UINT olderror = SetErrorMode (SEM_FAILCRITICALERRORS);
3411
3412    if (AccessFile (path, buf, MAX_PATH, &bufp))
3413	ret = open (bufp, flags);
3414
3415    (void) SetErrorMode (olderror);
3416
3417    if (bufp != buf) Xfree (bufp);
3418
3419    return ret;
3420}
3421
3422int _XOpenFileMode(path, flags, mode)
3423    _Xconst char* path;
3424    int flags;
3425    mode_t mode;
3426{
3427    char buf[MAX_PATH];
3428    char* bufp = NULL;
3429    int ret = -1;
3430    UINT olderror = SetErrorMode (SEM_FAILCRITICALERRORS);
3431
3432    if (AccessFile (path, buf, MAX_PATH, &bufp))
3433	ret = open (bufp, flags, mode);
3434
3435    (void) SetErrorMode (olderror);
3436
3437    if (bufp != buf) Xfree (bufp);
3438
3439    return ret;
3440}
3441
3442void* _XFopenFile(path, mode)
3443    _Xconst char* path;
3444    _Xconst char* mode;
3445{
3446    char buf[MAX_PATH];
3447    char* bufp = NULL;
3448    void* ret = NULL;
3449    UINT olderror = SetErrorMode (SEM_FAILCRITICALERRORS);
3450
3451    if (AccessFile (path, buf, MAX_PATH, &bufp))
3452	ret = fopen (bufp, mode);
3453
3454    (void) SetErrorMode (olderror);
3455
3456    if (bufp != buf) Xfree (bufp);
3457
3458    return ret;
3459}
3460
3461int _XAccessFile(path)
3462    _Xconst char* path;
3463{
3464    char buf[MAX_PATH];
3465    char* bufp;
3466    int ret = -1;
3467    UINT olderror = SetErrorMode (SEM_FAILCRITICALERRORS);
3468
3469    ret = AccessFile (path, buf, MAX_PATH, &bufp);
3470
3471    (void) SetErrorMode (olderror);
3472
3473    if (bufp != buf) Xfree (bufp);
3474
3475    return ret;
3476}
3477
3478#endif
3479
3480#ifdef WIN32
3481#undef _Xdebug
3482int _Xdebug = 0;
3483int *_Xdebug_p = &_Xdebug;
3484void (**_XCreateMutex_fn_p)(LockInfoPtr) = &_XCreateMutex_fn;
3485void (**_XFreeMutex_fn_p)(LockInfoPtr) = &_XFreeMutex_fn;
3486void (**_XLockMutex_fn_p)(LockInfoPtr
3487#if defined(XTHREADS_WARN) || defined(XTHREADS_FILE_LINE)
3488    , char * /* file */
3489    , int /* line */
3490#endif
3491        ) = &_XLockMutex_fn;
3492void (**_XUnlockMutex_fn_p)(LockInfoPtr
3493#if defined(XTHREADS_WARN) || defined(XTHREADS_FILE_LINE)
3494    , char * /* file */
3495    , int /* line */
3496#endif
3497        ) = &_XUnlockMutex_fn;
3498LockInfoPtr *_Xglobal_lock_p = &_Xglobal_lock;
3499#endif
3500