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