/*
 * $XConsortium: XlibInt.c,v 11.90 88/09/30 17:25:18 jim Exp $
 * -- $Header: /cec/src/nestor/servers/R3/shXlib/XlibInt.c,v 1.1.1.1 90/04/23 10:10:08 spanachi Exp $
 * -- $Log:	XlibInt.c,v $
 * Revision 1.1.1.1  90/04/23  10:10:08  spanachi
 * First version of 'shared X' library (X11R3). 
 * 
 * Revision 1.1  90/04/23  10:10:03  spanachi
 * Initial revision
 * 
 * Revision 1.1  89/11/03  14:46:06  neideck
 * Original send to X consortium
 * 
 * Revision 2.6  89/08/23  11:46:27  michael
 * *** empty log message ***
 * 
 * Revision 2.5  89/07/27  18:45:43  michael
 * last version using display loop in _XReadEvents ( anarchy mode ) 
 * 
 * Revision 2.4  89/07/20  20:23:51  michael
 * Some minor changes due to interface cleanup in mapping routines.
 * FIXED BUG :
 * Old version only allows one multiplexed connection (You guess why ?)
 * We're still in a test phase !!
 * 
 * Revision 2.3  89/07/07  08:43:37  michael
 * *** empty log message ***
 * 
 * Revision 2.2  89/06/26  14:43:52  michael
 * _XFlush and _XSend -- the never-ending story !
 * This version (the last concerning XFlush/XSend ?) does an "ordinary"
 * flush on the calling display (like the unextended version does).
 * Then, they loop over all multiplex'ed connections to assemble their
 * output buffers.
 * Other changes :
 *  XEventsQueued has been reworked to block if no event is pending (Old
 *  version does "busy waiting" ).
 * Fixed BUGS :
 *  Let the display pointer in the XEvent union point to the display
 *  that is known by the application (Xt Intrinsics use it ! )
 * 
 * Revision 2.1  89/06/09  13:30:28  michael
 * This new revision uses a new strategy in _XFlush and _XSend :
 * Don't dissamble the incoming buffer in single requests and write each
 * to the socket; instead "prepare" the entire buffer by updating each
 * request and flush the whole buffer at the end. This will minimize the
 * network traffic ( and that's X's intension ! )
 * 
 * Revision 1.2  89/06/09  11:21:52  michael
 * This is the last revision of XlibInt.c that uses _XFlush and _XSend as in 
 * revision 1.1. 
 * Fixed BUG : Blocking in _XReadEvents due to pend < SIZEOF( xEvent ) !
 * Don't set pend to SIZEOF( xEvent ); just try the next connection.
 * 
 * Revision 1.1  89/06/07  17:46:26  michael
 * Initial revision
 * 
 */

#include "copyright.h"
/* Copyright    Massachusetts Institute of Technology    1985, 1986, 1987 */

/*
 *	XlibInternal.c - Internal support routines for the C subroutine
 *	interface library (Xlib) to the X Window System Protocol V11.0.
 * --   
 * --   EXTENSION to support MULTIPLEXING
 */
#define NEED_EVENTS
#define NEED_REPLIES

#include <stdio.h>
#include "Xlibint.h"

/* 
 * -- additional includes
 */
#include "XmuXlibint.h"
#include "X11EventNames.h"
#include "table.h"
#include "multiplex.h"
#include "ApplCtx.h"
#include "resources.h"
#include "io.h"

#ifdef CRAY

/*
 * Cray UniCOS does not have readv and writev so we emulate
 */
#include <sys/socket.h>

static int readv (fd, iov, iovcnt)
int fd;
struct iovec *iov;
int iovcnt;
{
	struct msghdr hdr;

	hdr.msg_iov = iov;
	hdr.msg_iovlen = iovcnt;
	hdr.msg_accrights = 0;
	hdr.msg_accrightslen = 0;
	hdr.msg_name = 0;
	hdr.msg_namelen = 0;

	return (recvmsg (fd, &hdr, 0));
}

static int writev (fd, iov, iovcnt)
int fd;
struct iovec *iov;
int iovcnt;
{
	struct msghdr hdr;

	hdr.msg_iov = iov;
	hdr.msg_iovlen = iovcnt;
	hdr.msg_accrights = 0;
	hdr.msg_accrightslen = 0;
	hdr.msg_name = 0;
	hdr.msg_namelen = 0;

	return (sendmsg (fd, &hdr, 0));
}

#endif /* CRAY */

/*
 * The following routines are internal routines used by Xlib for protocol
 * packet transmission and reception.
 *
 * XIOError(Display *) will be called if any sort of system call error occurs.
 * This is assumed to be a fatal condition, i.e., XIOError should not return.
 *
 * XError(Display *, XErrorEvent *) will be called whenever an X_Error event is
 * received.  This is not assumed to be a fatal condition, i.e., it is
 * acceptable for this procedure to return.  However, XError should NOT
 * perform any operations (directly or indirectly) on the DISPLAY.
 *
 * Routines declared with a return type of 'Status' return 0 on failure,
 * and non 0 on success.  Routines with no declared return type don't 
 * return anything.  Whenever possible routines that create objects return
 * the object they have created.
 */

_XQEvent *_qfree = NULL;			/* NULL _XQEvent. */

static int padlength[4] = {0, 3, 2, 1};
    /* lookup table for adding padding bytes to data that is read from
    	or written to the X socket.  */

static xReq _dummy_request = {
	0, 0, 0
};

/* -- XXX that wasn't done in the original file -- */
static _EatData( ) ;

#define REQUEST_LENGTH( req ) ( req->length << 2 )

/*
 * _XFlush - Flush the X request buffer.  If the buffer is empty, no
 * action is taken.  This routine correctly handles incremental writes.
 * This routine may have to be reworked if int < long.
 * 
 * -- CHANGES :
 * --  First of all store the passed buffer in a intermediate storage and
 * --  then flush the buffer as the original _XFlush would do by calling
 * --  XmuXWriteToServer ( which is the original code of _XFlush ).
 * --  For multiplex'ed connections we disassemble the request buffer into 
 * --  single requests that are passed to the corresponding 
 * --  "request handling routine" (which do the necessary "mapping" ).
 * --  When we're done with the buffer we flush the multiplex'ed connections.
 * --  This technique keeps up with X's goal to "minimize network traffic" .
 * --  NOTE :
 * --  This routine has to be reentrant, since there may be "indirect recursive
 * --  calls" from multiplex'ed connections that are only able to support 
 * --  dump mode (they have to retrieve information from the client connection
 * --  and -since they do this via Xlib calls- call _XFlush again.
 * --  That's why we allocate the intermediate buffer every time we enter
 * --  _XFlush instead of using a preallocated buffer and flush the passed
 * --  output queue before doing anything else.
 */

_XFlush (dpy)
	register Display *dpy;
{
        register Display *curr_dpy ;
	register char *buffer , *bufindex ;
	register xReq *request ;
	register int size , bufsize , req_length , i ;

	bufsize     = dpy->bufptr - dpy->buffer ;

       
	if( bufsize == 0 )
	    /* -- nothing to do -- */
	    return ;

	/* -- first allocate the intermediate buffer, if necessary !! -- */
	if( XmuXMustMultiplex( dpy ) )
	{
	    if( ( buffer = ( char * ) Xmalloc( bufsize ) ) == NULL ) 
	    {
		/* 
		 * -- if we failed here, we would get in serious trouble
		 * -- give up or close all multiplex connections
		 * -- Up to now, we give up !
		 */
		errno = ENOMEM ;
		(*_XIOErrorFunction)( dpy ) ;
	    }

	    /* -- store the incoming output queue -- */
	    bcopy( dpy->buffer , buffer , bufsize ) ;
	    /* -- Now "_XFlush" dpy's output queue -- */
	    XmuXWriteToServer( dpy , dpy->buffer , bufsize ) ;
	    dpy->bufptr = dpy->buffer ;
	    dpy->last_req = ( char * ) &_dummy_request ;

	    /* -- loop over all multiplex'ed displays -- */
	    for( i = 1 ; 
		 ( curr_dpy = XmuXGetDisplay( dpy , i ) ) != NULL ; i++ )
	    {
		bufindex  = buffer ;
		size      = bufsize ;
		/*
		 * -- As long as there are requests in the buffer, 
		 * -- read the next until all are processed. 
		 * -- bufindex will be incremented to point to the 
		 * -- next request, size is decremented to 
		 * -- the remaining buffer size.
		 */
		while( ( request = 
			 ( xReq * ) ReadRequest( bufindex , size ) ) != 
		                       ( xReq * ) NULL )
		{
		    req_length = REQUEST_LENGTH( request ) ;
		
		    /* 
		     * -- call the corresponding request handling routine
		     * -- to do the necessary "mapping"
		     */
		    ( * ( RequestProcVector[ request->reqType ] ) )
			                   ( curr_dpy , ( char * ) request ) ;
						    
		    bufindex += req_length ;
		    size     -= req_length ;
		}

		/* 
		 * -- Now flush the multiplex'ed connection 
		 * -- NOTE : the buffer length may not be the same as for the
		 * --        calling dpy
		 */
		XmuXWriteToServer( curr_dpy , curr_dpy->buffer , 
				   curr_dpy->bufptr - curr_dpy->buffer ) ;
		curr_dpy->bufptr = curr_dpy->buffer ;
		curr_dpy->last_req = ( char * ) &_dummy_request ;
	    }
	    /* 
	     * -- there's at least one multiplex'ed connection (otherwise
	     * -- calls to XmuXCleanupResources would be useless)
	     * -- clean up  the resource list 
	     */
	    XmuXCleanupResources( dpy ) ;
	    Xfree( buffer ) ;
	}
	else
	{
	    /* -- "_XFlush" dpy's output queue -- */
	    XmuXWriteToServer( dpy , dpy->buffer , bufsize ) ;
	    dpy->bufptr = dpy->buffer ;
	    dpy->last_req = ( char * ) &_dummy_request ;
	}
}

/* _XEventsQueued - Return the number of events queued in the display's input 
 *  queue. Flushes the output queue on behalf of the application ( mode == 
 *  QueuedAfterFlush ). 
 * -- CHANGES :
 * --  Pick up events from ALL associated server connections. ALL events
 * --  are enqueued in the input queue of the CALLING display ( application
 * --  should have no idea that they are multiplexed ! See comments in _XEnq. ).
 */
int
_XEventsQueued (dpy, mode)
    register Display *dpy;
    int mode;

{	register int i , len;
	register Display *curr_dpy ;
	int pend;
	char buf[BUFSIZE];
	register xReply *rep;
	
    
	/* 
	 * -- has anything occured during former _XEnq's that 
	 * -- causes additional work 
	 */
	if( XmuXMustDoSomething( dpy ) )
	{
	    XmuXDoSomething( dpy ) ;
	}

	/* -- if the application wants the output queue to be flushed ... */
	if (mode == QueuedAfterFlush)
	    _XFlush(dpy);

	/* -- loop over ALL associated displays -- */
	for( i = 0 ; ( curr_dpy = XmuXGetDisplay( dpy , i ) ) != NULL ; i++ )
	{
	    /* -- how much can we read from the current connection -- */
	    if( BytesReadable( curr_dpy->fd, (char *) &pend ) < 0 )
		(*_XIOErrorFunction)( curr_dpy );
	    if ( ( len = pend ) < SIZEOF(xReply) )
		/* -- try next one -- */
		continue ;
	    else
		/* -- we can't read more that what fits into the buffer -- */
		if (len > BUFSIZE)
		    len = BUFSIZE;
	    /* -- round to an integral number of replies -- */
	    len /= SIZEOF(xReply);
	    pend = len * SIZEOF(xReply);
	    _XRead (curr_dpy, buf, (long) pend);

	    /* no space between comma and type or else macro will die */
	    STARTITERATE (rep,xReply, buf, (len > 0), len--) 
	    {
		if (rep->generic.type == X_Error)
		    _XError(curr_dpy, (xError *)rep);
		else   
		    /* must be an event packet */
		    /* 
		     * -- remember : we "enqueue" in the calling display's
		     * -- input queue !!!
		     */
		    _XEnq(curr_dpy, (xEvent *) rep);
	    }
            ENDITERATE
	}
    
	/* 
	 * -- has anything occured during _XEnq that 
	 * -- causes additional work 
	 */
	if( XmuXMustDoSomething( dpy ) )
	{
	    XmuXDoSomething( dpy ) ;
	}

        /*
	 * -- all events where queued in dpy's input queue, so return
	 * -- it's queue length here 
	 */
	return( dpy->qlen ) ;
}

/* _XReadEvents - Flush the output queue,
 * then read as many events as possible (but at least 1) and enqueue them
 * -- CHANGES :
 * --  As in _XEventsQueued, we examine ALL associated sockets. Since 
 * --  _XReadEvents must read at least one event, we must block if none
 * --  of the sockets is ready. In this case we call XmuXWaitForReadables
 * --  which actually does a select on all sockets. This works finw if we are in
 * --  anarchy mode; chalk passing mode requests some additional work: 
 * --  The socket sampling loop at the beginning may tell us that it has "got one"
 * --  event; unfortunately, this event comes from a non-chalk-holder socket and
 * --  is thrown away during _XEnq, and - even worse - the output queue has not
 * --  been flushed. In this case we'll only be able to break out of this infinite
 * --  loop, if we generate user events on the chalk-holder socket.
 */

_XReadEvents(dpy)
	register Display *dpy;

{	         char      buf[BUFSIZE];
	register Display *curr_dpy ,
		         *chalk_dpy ;
	         long     pend_not_register; /* because can't "&" a register 
						variable */
	register long     pend ,
	                  pending[ MAXSOCKS ] ;	 
	register int      i ;	 
	register xEvent  *ev;
	         Bool     not_yet_flushed = True ,
		          got_one , got_one_from_chalk ;

    
	/* 
	 * -- has anything occured during former _XEnq's that 
	 * -- causes additional work 
	 */
	if( XmuXMustDoSomething( dpy ) )
	{
	    XmuXDoSomething( dpy ) ;
	}
	chalk_dpy = XmuXChalkDisplay( dpy ) ;
	do 
	{
	    got_one            = 
	    got_one_from_chalk = False ;
	    /* 
	     * -- loop over ALL associated displays 
	     * -- and find out how much we can read from each socket
	     */
	    for( i = 0 ; ( curr_dpy = XmuXGetDisplay( dpy , i ) ) != NULL ; i++ )
	    {   
		pending[ curr_dpy->fd ] = 0 ;
		/* -- how much data can be read -- */
		if( BytesReadable( curr_dpy->fd , 
				   (char *) &pend_not_register ) < 0 )
		    (*_XIOErrorFunction)( curr_dpy ) ;

		pending[ curr_dpy->fd ] = pend_not_register ; 
		
		/* -- we got one -- */
		if( pend_not_register >= SIZEOF(xEvent) )
		{
		    got_one = True ;
		    if( chalk_dpy->fd == curr_dpy->fd )
			got_one_from_chalk = True ;
		}
	    }
	    /*
	     * -- non-chalk-holder's will only fool us during our first try
	     */
	    if( !got_one || !got_one_from_chalk )
	    {
		/* 
		 * -- must read at least one xEvent,
		 * -- but none is pending. We'll flush the
		 * -- CALLING dpy's output queue and block .
		 */
		if ( not_yet_flushed ) 
		{   int qlen = dpy->qlen ;
		    /* 
		     * -- flush client's output queue; all multiplex'ed
		     * -- displays are flushed automatically 
		     */
		    _XFlush ( dpy ) ;
		    not_yet_flushed = False;
		    /* -- _XFlush may enqueue events -- */
		    if( qlen != dpy->qlen )
			/* -- found something, exit loop -- */
			break ;
		}
		/*
		 * -- Even flushing the output queues wasn't effective
		 * -- Now, we must block. We will not return until
		 * -- we can read SIZEOF( xEvent ) from one of the sockets
		 */
		if( !got_one )
		    XmuXWaitForReadables( dpy , SIZEOF(xEvent) , pending ) ;
	    }
	    /* -- read ALL events that are pending -- */
	    for( i = 0 ; ( curr_dpy = XmuXGetDisplay( dpy , i ) ) != NULL ; i++ )
	    {
		pend = pending[ curr_dpy->fd ] ;
		
		/* but we won't read more than the max buffer size */
		if (pend > BUFSIZE)
		    pend = BUFSIZE;

		/* round down to an integral number of XReps */
		pend = (pend / SIZEOF(xEvent)) * SIZEOF(xEvent);

		_XRead( curr_dpy , buf , pend ) ;

		/* no space between comma and type or else macro will die */
		STARTITERATE(ev,xEvent, buf, (pend > 0),
			      pend -= SIZEOF(xEvent)) 
		{
		    if (ev->u.u.type == X_Error)
			_XError( curr_dpy , (xError *) ev );
		    else  
			/* 
			 * -- it's an event packet; enqueue it 
			 * -- don't get confused with the first argument :
			 * -- we enqueue the event in that display that is known
			 * -- by the application (i.e. the calling one 
			 */
			_XEnq ( curr_dpy, ev );
		}
		ENDITERATE
	    } 
	}
	while ( dpy->head == NULL );
	    
	/* 
	 * -- has anything occured during _XEnq that 
	 * -- causes additional work 
	 */
	if( XmuXMustDoSomething( dpy ) )
	{
	    XmuXDoSomething( dpy ) ;
	}

}

/* 
 * _XRead - Read bytes from the socket taking into account incomplete
 * reads.  This routine may have to be reworked if int < long.
 */
_XRead (dpy, data, size)
	register Display *dpy;
	register char *data;
	register long size;
{
	register long bytes_read ;

	if (size == 0) return;
	errno = 0;
       
	while ((bytes_read = ReadFromServer(dpy->fd, data, (int)size))
		!= size) {

	    	if (bytes_read > 0) {
		    size -= bytes_read;
		    data += bytes_read;
		    }
#ifdef EWOULDBLOCK
		else if (errno == EWOULDBLOCK) {
		    _XWaitForReadable(dpy);
		    errno = 0;
		}
#endif		
#ifdef SUNSYSV
		else if (errno == 0) {
		    _XWaitForReadable(dpy);
		}
#endif
		else if (bytes_read == 0) {
		    /* Read failed because of end of file! */
		    errno = EPIPE;
		    (*_XIOErrorFunction)(dpy);
		    }

		else  /* bytes_read is less than 0; presumably -1 */ {
		    /* If it's a system call interrupt, it's not an error. */
		    if (errno != EINTR)
		    	(*_XIOErrorFunction)(dpy);
		    }
	    	 }
}

#ifdef WORD64

/*
 * XXX This is a *really* stupid way of doing this....
 */

#define PACKBUFFERSIZE 4096


/*
 * _XRead32 - Read bytes from the socket unpacking each 32 bits
 *            into a long (64 bits on a CRAY computer).
 * 
 */
static _doXRead32 (dpy, data, size, packbuffer)
        register Display *dpy;
        register long *data;
        register long size;
	register char *packbuffer;
{
 long *lpack,*lp;
 long mask32 = 0x00000000ffffffff;
 long maskw, nwords, i, bits;

        _XReadPad (dpy, packbuffer, size);

        lp = data;
        lpack = (long *) packbuffer;
        nwords = size >> 2;
        bits = 32;

        for(i=0;i<nwords;i++){
            maskw = mask32 << bits;
           *lp++ = ( *lpack & maskw ) >> bits;
            bits = bits ^32;
            if(bits){
               lpack++;
            }
        }
}

_XRead32 (dpy, data, len)
    Display *dpy;
    long *data;
    long len;
{
    char packbuffer[PACKBUFFERSIZE];
    unsigned nwords = (PACKBUFFERSIZE >> 2);	/* bytes to CARD32 */

    for (; len > nwords; len -= nwords, data += nwords) {
	_doXRead32 (dpy, data, nwords, packbuffer);
    }
    _doXRead32 (dpy, data, len, packbuffer);
}



/*
 * _XRead16 - Read bytes from the socket unpacking each 16 bits
 *            into a long (64 bits on a CRAY computer).
 *
 */
static _doXRead16 (dpy, data, size, packbuffer)
        register Display *dpy;
        register short *data;
        register long size;
	char *packbuffer;
{
	long *lpack,*lp;
	long mask16 = 0x000000000000ffff;
	long maskw, nwords, i, bits;

        _XRead(dpy,packbuffer,size);	/* don't do a padded read... */

        lp = (long *) data;
        lpack = (long *) packbuffer;
        nwords = size >> 1;  /* number of 16 bit words to be unpacked */
        bits = 48;
        for(i=0;i<nwords;i++){
            maskw = mask16 << bits;
           *lp++ = ( *lpack & maskw ) >> bits;
            bits -= 16;
            if(bits < 0){
               lpack++;
               bits = 48;
            }
        }
}

_XRead16 (dpy, data, len)
    Display *dpy;
    short *data;
    long len;
{
    char packbuffer[PACKBUFFERSIZE];
    unsigned nwords = (PACKBUFFERSIZE >> 1);	/* bytes to CARD16 */

    for (; len > nwords; len -= nwords, data += nwords) {
	_doXRead16 (dpy, data, nwords, packbuffer);
    }
    _doXRead16 (dpy, data, len, packbuffer);
}

_XRead16Pad (dpy, data, size)
    Display *dpy;
    short *data;
    long size;
{
    int slop = (size & 3);
    short slopbuf[3];

    _XRead16 (dpy, data, size);
    if (slop > 0) {
	_XRead16 (dpy, slopbuf, 4 - slop);
    }
}
#endif /* WORD64 */


/*
 * _XReadPad - Read bytes from the socket taking into account incomplete
 * reads.  If the number of bytes is not 0 mod 32, read additional pad
 * bytes. This routine may have to be reworked if int < long.
 */
_XReadPad (dpy, data, size)
    	register Display *dpy;	
	register char *data;
	register long size;
{
    	register long bytes_read;
	struct iovec iov[2];
	char pad[3];

	if (size == 0) return;
	iov[0].iov_len = (int)size;
	iov[0].iov_base = data;
	/* 
	 * The following hack is used to provide 32 bit long-word
	 * aligned padding.  The [1] vector is of length 0, 1, 2, or 3,
	 * whatever is needed.
	 */

	iov[1].iov_len = padlength[size & 3];
	iov[1].iov_base = pad;
	size += iov[1].iov_len;

	errno = 0;
	while ((bytes_read = ReadvFromServer (dpy->fd, iov, 2)) != size) {

	    if (bytes_read > 0) {
		size -= bytes_read;
	    	if ((iov[0].iov_len -= bytes_read) < 0) {
		    iov[1].iov_len += iov[0].iov_len;
		    iov[1].iov_base -= iov[0].iov_len;
		    iov[0].iov_len = 0;
		    }
	    	else
	    	    iov[0].iov_base += bytes_read;
	    	}
#ifdef EWOULDBLOCK
	    else if (errno == EWOULDBLOCK) {
		_XWaitForReadable(dpy);
		errno = 0;
	    }
#endif
#ifdef SUNSYSV
	    else if (errno == 0) {
		_XWaitForReadable(dpy);
	    }
#endif
	    else if (bytes_read == 0) {
		/* Read failed because of end of file! */
		errno = EPIPE;
		(*_XIOErrorFunction)(dpy);
		}
	    
	    else  /* bytes_read is less than 0; presumably -1 */ {
		/* If it's a system call interrupt, it's not an error. */
		if (errno != EINTR)
		    (*_XIOErrorFunction)(dpy);
		}
	    }

}

/* -- _XmuXSingleSend - The original Xlib's _XSend 
 * --                   ( excuse the misnamimg here ! )
 * -- We need it to restrict the sending to one socket; there are modified
 * -- versions of Xlib routines that use _XSend instead of Data AND do their
 * -- own looping over all displays (e.g. XPutImage ). Using the modified
 * -- version of _XSend would mean that multiplex'ed servers must do the work
 * -- twice.
 */
_XmuXSingleSend (dpy, data, size)
	register Display *dpy;
	char *data;
	register long size;
{
	struct iovec iov[3];
	static char pad[3] = {0, 0, 0};
           /* XText8 and XText16 require that the padding bytes be zero! */

	long skip = 0;
	long total = (dpy->bufptr - dpy->buffer) + ((size + 3) & ~3);
	long todo = total;

	while (total) {
	    long before = skip;
	    long remain = todo;
	    int i = 0;
	    long len;

	/* You could be very general here and have "in" and "out" iovecs
	 * and write a loop without using a macro, but what the heck
	 */

#define InsertIOV(pointer, length) \
	    len = (length) - before; \
	    if (len > remain) \
		len = remain; \
	    if (len <= 0) { \
		before = -len; \
	    } else { \
		iov[i].iov_len = len; \
		iov[i].iov_base = (pointer) + before; \
		i++; \
		remain -= len; \
		before = 0; \
	    }

	    InsertIOV(dpy->buffer, dpy->bufptr - dpy->buffer)
	    InsertIOV(data, size)
	    /* Provide 32-bit aligned padding as necessary */
	    InsertIOV(pad, padlength[size & 3])
    
	    errno = 0;
	    if ((len = WritevToServer(dpy->fd, iov, i)) >= 0) {
		skip += len;
		total -= len;
		todo = total;
#ifdef EWOULDBLOCK
	    } else if (errno == EWOULDBLOCK) {
		_XWaitForWritable(dpy);
#endif
#ifdef SUNSYSV
	    } else if (errno == 0) {
		_XWaitForWritable(dpy);
#endif
#ifdef EMSGSIZE
	    } else if (errno == EMSGSIZE) {
		todo = todo >> 1;
#endif
	    } else {
		(*_XIOErrorFunction)(dpy);
	    }
	}

	dpy->bufptr = dpy->buffer;
	dpy->last_req = (char *) & _dummy_request;
}

/*
 * _XSend - Flush the buffer and send the client data. 32 bit word aligned
 * transmission is used, if size is not 0 mod 4, extra bytes are transmitted.
 * This routine may have to be reworked if int < long;
 * -- CHANGES :
 * --  Very similar to those in _XFlush :
 * --  Copy the incoming data into an intermediate buffer, write the data to
 * --  the server and then "prepare" the data for multiplexing.
 * --  Since we copy the data here, we do not use iovec's here; instead we
 * --  write the copy to the server via XmuXWriteToServer.
 */
_XSend (dpy, data, size)
	register Display *dpy;
	char *data;
	register long size;

{       register Display *curr_dpy ;
        register char *buffer , *bufindex ;
	register xReq *request ;
	static char pad[3] = {0, 0, 0};
           /* XText8 and XText16 require that the padding bytes be zero! */
	register int req_length , i ;
	long buf_size ,
	     pads ,
	     total , buftotal ;

	buf_size    =  dpy->bufptr - dpy->buffer ;
	pads        = padlength[ size & 3 ] ;
	buftotal    = buf_size + size + pads ;

	if( XmuXMustMultiplex( dpy ) )
	{
	    if( ( buffer = ( char * ) Xmalloc( buftotal ) ) == NULL )
	    {
		/* -- malloc failed -- */
		errno = ENOMEM ;
		( * _XIOErrorFunction ) ( dpy ) ;
	    }
	    /* -- copy the data :  -- */
	    /* -- (1) the request buffer -- */
	    bcopy( dpy->buffer , buffer , buf_size ) ;
	    /* -- (2) the data passed as an argument to _XSend -- */
	    bcopy( data , buffer + buf_size , size ) ;
	    /* -- the pad bytes -- */
	    if( pads )
		bcopy( &pad[ 0 ] , buffer + buf_size + size , pads ) ;

	    /* -- "_XSend" the buffer to dpy's server -- */
	    XmuXWriteToServer( dpy , buffer , buftotal ) ;
	    dpy->bufptr = dpy->buffer ;
	    dpy->last_req = ( char * ) &_dummy_request ;

	    /* -- loop over ALL multiplex'ed displays -- */
	    for( i = 1 ; ( curr_dpy = XmuXGetDisplay( dpy , i ) ) != NULL ; 
		 i++ )
	    {
		bufindex = buffer ;
		total    = buftotal ;
		/*
		 * -- loop until the entire buffer has been processed
		 */
		while( ( request = 
			 ( xReq * ) ReadRequest( bufindex , total ) ) != 
		             ( xReq * ) NULL )
		{
		    req_length = REQUEST_LENGTH( request ) ;
		    /* 
		     * -- call the corresponding request handling routine to
		     * -- "prepare" the data
		     */
		    ( * ( RequestProcVector[ request->reqType ] ) ) 
			                    ( curr_dpy , ( char * ) request ) ;
		    bufindex += req_length ;
		    total    -= req_length ;
		}
		/* -- flush the multiplex'ed connections -- */
		XmuXWriteToServer( curr_dpy , curr_dpy->buffer ,
				   curr_dpy->bufptr - curr_dpy->buffer ) ;
		curr_dpy->bufptr = curr_dpy->buffer ;
		curr_dpy->last_req = ( char * ) &_dummy_request ;
	    }
	    /* 
	     * -- there's at least one multiplex'ed connection (otherwise
	     * -- calls to XmuXCleanupResources would be useless)
	     * -- clean up  the resource list 
	     */
	    XmuXCleanupResources( dpy ) ;
	    Xfree( buffer ) ;
	}
	else
	    _XmuXSingleSend( dpy , data , size ) ;
}

/*
 * _XAllocID - normal resource ID allocation routine.  A client
 * can roll his own and instantiate it if he wants, but must
 * follow the rules.
 */

XID _XAllocID(dpy)
register Display *dpy;
{
   return (dpy->resource_base + (dpy->resource_id++ << dpy->resource_shift));
}

/*
 * The hard part about this is that we only get 16 bits from a reply.  Well,
 * then, we have three values that will march along, with the following
 * invariant:
 *	dpy->last_request_read <= rep->sequenceNumber <= dpy->request
 * The right choice for rep->sequenceNumber is the largest that
 * still meets these constraints.
 * --
 * -- CHANGES :
 * -- The hard part about this concerning multiplexing is that we can't ensure
 * -- identical sequence numbers on all connections. All we can do is to 
 * -- check the invariant above for the primary (application) connection.
 */
static unsigned long
_SetLastRequestRead(dpy, rep)
    register Display *dpy;
    register xGenericReply *rep;
{
    register unsigned long	newseq, lastseq;
    
    if( IsClientDisplay( dpy ) )
    {
	/*
	 * KeymapNotify has no sequence number, but is always guaranteed
	 * to immediately follow another event, except when generated via
	 * SendEvent (hmmm).
	 */
	if ((rep->type & 0x7f) == KeymapNotify)
	    return(dpy->last_request_read);
	
	newseq = (dpy->last_request_read & ~((unsigned long)0xffff)) |
	         rep->sequenceNumber;
	lastseq = dpy->last_request_read;
	while (newseq < lastseq) {
	    newseq += 0x10000;
	    if (newseq > dpy->request) {
		(void) fprintf (stderr, 
		    "Xlib:  sequence lost (0x%lx > 0x%lx) in reply type 0x%x!\n",
				newseq, dpy->request, 
				(unsigned int) rep->type);
		newseq -= 0x10000;
		break;
	    }
	}
	
	dpy->last_request_read = newseq;
	return(newseq);
    }
    else
	/* -- return a number that could make sense -- */
	return( LastKnownRequestProcessed( 
		    XmuXPrimaryDisplayFromDisplay( dpy ) ) ) ;
}

/* 
 * -- _XReply - Wait for a reply packet and copy its contents into the
 * -- specified reply. Mean while we must handle error and event packets that
 * -- we may encounter.
 * -- CHANGES :
 * -- Replies are somewhat special: There is no field to identify their
 * -- type and there's no way to queue them up. Normally, that's not a
 * -- problem, because the transaction scheme of X guarantees that the next
 * -- reply on the wire is the one that you're waiting for; in other words
 * -- there are no calls to _XReply when you are in _XReply! But multiplexing
 * -- isn't normal! If we receive an event during the wait for an reply that 
 * -- causes round-trip requests (e.g. XGetWindowAttributes) on the same 
 * -- connection, we will get out of "reply-order" and our process may exit.
 * -- So, we must find a way to make the call of _XReply atomic. 
 * -- Solution : Keep hands off from XReply! Don't try to do any multiplex
 * -- action during XReply! All we can do is enque XmuX-interesting events
 * -- in a special queue and handle them during calls to one of the event-
 * -- reading functions (XReadEvents.XeventsQueued).

 */
Status _XReply (dpy, rep, extra, discard)
    register Display *dpy;
    register xReply *rep;
    int extra;		/* number of 32-bit words expected after the reply */
    Bool discard;	/* should I discard data followind "extra" words? */
{
    /* Pull out the serial number now, so that (currently illegal) requests
     * generated by an error handler don't confuse us.
     */
    unsigned long cur_request = dpy->request;

    _XFlush(dpy);
    while (1) {
	_XRead(dpy, (char *)rep, (long)SIZEOF(xReply));
	switch ((int)rep->generic.type) {

	    case X_Reply:
	        /* Reply received.  Fast update for synchronous replies,
		 * but deal with multiple outstanding replies.
		 */
	        if (rep->generic.sequenceNumber == (cur_request & 0xffff))
		    dpy->last_request_read = cur_request;
		else
		    (void) _SetLastRequestRead(dpy, &rep->generic);
		if (extra == 0) {
		    if (discard && (rep->generic.length > 0))
		       /* unexpectedly long reply! */
		       _EatData (dpy, rep->generic.length);
		    return (1);
		    }
		if (extra == rep->generic.length) {
		    /* 
		     * Read the extra data into storage immediately following
		     * the GenericReply structure. 
		     */
		    _XRead (dpy, NEXTPTR(rep,xReply), ((long)extra) << 2);
		    return (1);
		    }
		if (extra < rep->generic.length) {
		    /* Actual reply is longer than "extra" */
		    _XRead (dpy, NEXTPTR(rep,xReply), ((long)extra) << 2);
		    if (discard)
		        _EatData (dpy, rep->generic.length - extra);
		    return (1);
		    }
		/* 
		 *if we get here, then extra > rep->generic.length--meaning we
		 * read a reply that's shorter than we expected.  This is an 
		 * error,  but we still need to figure out how to handle it...
		 */
		_XRead (dpy, NEXTPTR(rep,xReply),
			((long) rep->generic.length) << 2);
		(*_XIOErrorFunction) (dpy);
		return (0);

    	    case X_Error:
	    	{
	        register _XExtension *ext;
		register Bool ret = False;
		int ret_code;
		xError *err = (xError *) rep;
		unsigned long serial;

		serial = _SetLastRequestRead(dpy, (xGenericReply *)rep);
		if (serial == cur_request)
			/* do not die on "no such font", "can't allocate",
			   "can't grab" failures */
			switch ((int)err->errorCode) {
			case BadName:
			    switch (err->majorCode) {
				case X_OpenFont:
				case X_LookupColor:
				case X_AllocNamedColor:
				    return(0);
			    }
			    break;
			case BadFont:
			    if (err->majorCode == X_QueryFont)
				return (0);
			    break;
			case BadAlloc:
			case BadAccess:
				return (0);
			/* 
			 * we better see if there is an extension who may
			 * want to suppress the error.
			 */
			default:
			    ext = dpy->ext_procs;
			    while (ext) {
				if (ext->error != NULL) 
				   ret = (*ext->error)
					(dpy, err, &ext->codes, &ret_code);
				ext = ext->next;
				}
			    if (ret) return (ret_code);
			    break;
			}
		/*
		 * -- in case of multiplex'ed connections
		 * -- we want to return on tolerable errors; alas, 
		 * -- serial is not equal to cur_request 
		 * -- (see _SetLastRequestRead). That's the reason
		 * -- for the additional if statement .
		 */
		_XError(dpy, err);
		if( IsClientDisplay( dpy ) )
		{
		    if (serial == cur_request)
			return(0);
		}
		else
		    return( 0 ) ;
		}
		break;
	    default:
		_XEnq(dpy, (xEvent *) rep);
		break;
	    }
	}
}   


/* Read and discard "n" 32-bit words. */

static _EatData (dpy, n)
    Display *dpy;
    unsigned long n;
    {
    unsigned int bufsize;
    char *buf;
    n <<= 2;  /* convert to number of bytes */
    buf = Xmalloc (bufsize = (n > 2048) ? 2048 : n);
    while (n) {
	long bytes_read = (n > bufsize) ? bufsize : n;
	_XRead (dpy, buf, bytes_read);
	n -= bytes_read;
	}
    Xfree (buf);
    }

/*
 * _XEnq - Place event packets on the display's queue.
 * note that no squishing of move events in V11, since there
 * is pointer motion hints....
 * -- CHANGES :
 * --  Since we have to deal with "multiplexed" displays that are not known
 * --  to the application, we enqueue events in the "original" display
 * --  (i.e. that is used by the application ).
 * --  So, the first argument here is used to find this display.
 */
_XEnq (dpy, event)
	register Display *dpy;
	register xEvent *event;
{
	register _XQEvent *qelt;
	register Display  *known_dpy ;

	known_dpy = XmuXPrimaryDisplayFromDisplay( dpy ) ;
/*NOSTRICT*/
	if (qelt = _qfree) {
		/* If _qfree is non-NULL do this, else malloc a new one. */
		_qfree = qelt->next;
	}
	else if ((qelt = 
	    (_XQEvent *) Xmalloc((unsigned)sizeof(_XQEvent))) == NULL) {
		/* Malloc call failed! */
		errno = ENOMEM;
		(*_XIOErrorFunction)( known_dpy );
	}
	qelt->next = NULL;

	/* go call through display to find proper event reformatter */
	/* 
	 * -- NOTE : use CALLING dpy's event formatter, since we must do
	 * --        ID mapping !
	 */
	if ((*dpy->event_vec[event->u.u.type & 0177])( dpy, 
						       &qelt->event, event))
	{
	    if (known_dpy->tail)	
		known_dpy->tail->next = qelt;
	    else 		
		known_dpy->head = qelt;
    
	    known_dpy->tail = qelt;
	    known_dpy->qlen++;
	} 
	else 
	{
	    /* ignored, or stashed away for many-to-one compression */
	    qelt->next = _qfree;
	    _qfree = qelt;
	}
}
/*
 * EventToWire in seperate file in that often not needed.
 */

/*ARGSUSED*/
Bool
_XUnknownWireEvent(dpy, re, event)
register Display *dpy;	/* pointer to display structure */
register XEvent *re;	/* pointer to where event should be reformatted */
register xEvent *event;	/* wire protocol event */
{
#ifdef notdef
	(void) fprintf(stderr, 
	    "Xlib: unhandled wire event! event number = %d, display = %x\n.",
			event->u.u.type, dpy);
#endif
	return(False);
}

/*ARGSUSED*/
Status
_XUnknownNativeEvent(dpy, re, event)
register Display *dpy;	/* pointer to display structure */
register XEvent *re;	/* pointer to where event should be reformatted */
register xEvent *event;	/* wire protocol event */
{
#ifdef notdef
	(void) fprintf(stderr, 
 	   "Xlib: unhandled native event! event number = %d, display = %x\n.",
			re->type, dpy);
#endif
	return(0);
}

/*
 * -- reformat a wire event into an XEvent structure of the right type.
 * -- CHANGES :
 * --   ID mapping added.
 */

int
_XWireToEvent( dpy, re, event )

Display *dpy;   	/* pointer to display structure */
XEvent *re;	        /* pointer to where event should be reformatted */
xEvent *event;	        /* wire protocol event */

{   register int      must_deliver , 
	              mux_event ;
    register Display *default_dpy ;


    re->type = event->u.u.type & 0x7f;

    ( ( XAnyEvent * ) re )->serial = _SetLastRequestRead( dpy ,
					 ( xGenericReply * ) event ) ;
    ((XAnyEvent *)re)->send_event = ((event->u.u.type & 0x80) != 0);
    XmuXdebug( debug_events , "Event %s (#0x%lx) " , 
	   X11EventNames[ re->type ] , ( ( XAnyEvent * ) re )->serial ) ;
    
    /*
     * -- We only allow Chalk passing mode, but there are kind of
     * -- events that shoul be delivered even if they come not from the
     * -- chalk holder display. These events are all that notify the 
     * -- application about window changes, i.e.Expose , MapNotify, ...
     * -- but NOT "device events" (KeyPress, ButtonPress,...).
     * -- We use a variable to indicate this forced delivery.
     */
    must_deliver = 
    mux_event    = False ;
    /*
     * -- XmuX needs the pointer to the calling display, whereas the 
     * -- application needs the pointer to the default display; 
     * -- will be reset at the end
     */
    default_dpy = XmuXPrimaryDisplayFromDisplay( dpy ) ;

    ((XAnyEvent *)re)->display = dpy ;
    /* 
     * -- Ignore the leading bit of the event type since it is set when a
     * --  client sends an event rather than the server.
     */

    switch (event-> u.u.type & 0177) 
    {
    case KeyPress:
    case KeyRelease:
    {   register XKeyEvent *ev = (XKeyEvent*) re;
	
	ev->root 	= XmuXMapID( dpy , event->u.keyButtonPointer.root , 
				 FromServer ) ;
	ev->window 	= XmuXMapID( dpy , event->u.keyButtonPointer.event , 	
				 FromServer ) ;
	ev->subwindow 	= XmuXMapID( dpy , event->u.keyButtonPointer.child ,
				 FromServer ) ;
	
	ev->time 	= event->u.keyButtonPointer.time;
	ev->x 		= event->u.keyButtonPointer.eventX;
	ev->y 		= event->u.keyButtonPointer.eventY;
	ev->x_root 	= event->u.keyButtonPointer.rootX;
	ev->y_root 	= event->u.keyButtonPointer.rootY;
	ev->state	= event->u.keyButtonPointer.state;
	ev->same_screen	= event->u.keyButtonPointer.sameScreen;
	ev->keycode 	= event->u.u.detail;
    }
    break;
    
    case ButtonPress:
    case ButtonRelease:
    {	register XButtonEvent *ev =  (XButtonEvent *) re;
	
	ev->root 	= XmuXMapID( dpy , event->u.keyButtonPointer.root ,
				 FromServer ) ;				
	ev->window 	= XmuXMapID( dpy , event->u.keyButtonPointer.event ,
				 FromServer ) ;				
	ev->subwindow 	= XmuXMapID( dpy , event->u.keyButtonPointer.child ,
				FromServer ) ;

	ev->time 	= event->u.keyButtonPointer.time;
	ev->x 		= event->u.keyButtonPointer.eventX;
	ev->y 		= event->u.keyButtonPointer.eventY;
	ev->x_root 	= event->u.keyButtonPointer.rootX;
	ev->y_root 	= event->u.keyButtonPointer.rootY;
	ev->state	= event->u.keyButtonPointer.state;
	ev->same_screen	= event->u.keyButtonPointer.sameScreen;
	ev->button 	= event->u.u.detail;
    }
    break;
 
    case MotionNotify:
    {	register XMotionEvent *ev =   (XMotionEvent *)re;
	
	ev->root 	= XmuXMapID( dpy , event->u.keyButtonPointer.root ,
				 FromServer ) ;				
	ev->window 	= XmuXMapID( dpy , event->u.keyButtonPointer.event ,
				 FromServer ) ;				
	ev->subwindow 	= XmuXMapID( dpy , event->u.keyButtonPointer.child ,
				 FromServer ) ;
	ev->time 	= event->u.keyButtonPointer.time;
	ev->x 		= event->u.keyButtonPointer.eventX;
	ev->y 		= event->u.keyButtonPointer.eventY;
	ev->x_root 	= event->u.keyButtonPointer.rootX;
	ev->y_root 	= event->u.keyButtonPointer.rootY;
	ev->state	= event->u.keyButtonPointer.state;
	ev->same_screen	= event->u.keyButtonPointer.sameScreen;
	ev->is_hint 	= event->u.u.detail;
    }
    break;
 
    case EnterNotify:
    case LeaveNotify:
    {	register XCrossingEvent *ev   = (XCrossingEvent *) re;
	
	ev->root	= XmuXMapID( dpy , event->u.enterLeave.root ,
				 FromServer ) ;				
	ev->window	= XmuXMapID( dpy , event->u.enterLeave.event ,
				 FromServer ) ;
	ev->subwindow	= XmuXMapID( dpy , event->u.enterLeave.child ,
				 FromServer ) ;				
					
	ev->time	= event->u.enterLeave.time;
	ev->x		= event->u.enterLeave.eventX;
	ev->y		= event->u.enterLeave.eventY;
	ev->x_root	= event->u.enterLeave.rootX;
	ev->y_root	= event->u.enterLeave.rootY;
	ev->state	= event->u.enterLeave.state;
	ev->mode	= event->u.enterLeave.mode;
	ev->same_screen = (event->u.enterLeave.flags & 
			   ELFlagSameScreen) && True;
	ev->focus	= (event->u.enterLeave.flags &
			   ELFlagFocus) && True;
	ev->detail	= event->u.u.detail;
    }
    break;
	
    case FocusIn:
    case FocusOut:
    {	register XFocusChangeEvent *ev = (XFocusChangeEvent *) re;
	
	ev->window 	= XmuXMapID( dpy , event->u.focus.window , 
				     FromServer ) ;
	ev->mode	= event->u.focus.mode;
	ev->detail	= event->u.u.detail;
    }
    break;
 
    case KeymapNotify:
    {	register XKeymapEvent *ev = (XKeymapEvent *) re;
	
	ev->window	= XmuXMapID( dpy , dpy->current , FromServer ) ;
				
	bcopy ( (char *) ((xKeymapEvent *) event)->map,
	        &ev->key_vector[1], 
	        sizeof (((xKeymapEvent *) event)->map) , NULL );
    }
    break;
	
    case Expose:
    {	register XExposeEvent *ev = (XExposeEvent *) re;
	
	ev->window	= XmuXMapID( dpy , event->u.expose.window , FromServer ) ;
				
	ev->x		= event->u.expose.x;
	ev->y		= event->u.expose.y;
	ev->width	= event->u.expose.width;
	ev->height	= event->u.expose.height;
	ev->count	= event->u.expose.count;
	/* -- this event must be delivered by all means ! -- */
	must_deliver = True ;
    }
    break;
	
    case GraphicsExpose:
    {    register XGraphicsExposeEvent *ev = (XGraphicsExposeEvent *) re;
	     
	 ev->drawable	= XmuXMapID( dpy , event->u.graphicsExposure.drawable ,
				 FromServer ) ;				
	 
	 ev->x		= event->u.graphicsExposure.x;
	 ev->y		= event->u.graphicsExposure.y;
	 ev->width	= event->u.graphicsExposure.width;
	 ev->height	= event->u.graphicsExposure.height;
	 ev->count	= event->u.graphicsExposure.count;
	 ev->major_code	= event->u.graphicsExposure.majorEvent;
	 ev->minor_code	= event->u.graphicsExposure.minorEvent;
	/* -- this event must be delivered by all means ! -- */
	must_deliver = True ;
     }
    break;
 
    case NoExpose:
    {    register XNoExposeEvent *ev = (XNoExposeEvent *) re;
	
	 ev->drawable	= XmuXMapID( dpy , event->u.noExposure.drawable ,
				 FromServer ) ;				
	 
	 ev->major_code	= event->u.noExposure.majorEvent;
	 ev->minor_code	= event->u.noExposure.minorEvent;
	/* -- this event must be delivered by all means ! -- */
	must_deliver = True ;
     }
    break;
	
    case VisibilityNotify:
    {    register XVisibilityEvent *ev = (XVisibilityEvent *) re;
	
	 ev->window		= XmuXMapID( dpy , event->u.visibility.window ,
					 FromServer ) ;
	 
	 ev->state		= event->u.visibility.state;
	/* -- this event must be delivered by all means ! -- */
	must_deliver = True ;
     }
    break;
	
    case CreateNotify:
    {    register XCreateWindowEvent *ev = (XCreateWindowEvent *) re;
	     
	 ev->window		= XmuXMapID( dpy , 
					     event->u.createNotify.window ,
					     FromServer ) ;	     

	 ev->parent		= XmuXMapID( dpy ,
					     event->u.createNotify.parent ,
					     FromServer ) ;
		 
	 ev->x		        = event->u.createNotify.x;
	 ev->y		        = event->u.createNotify.y;
	 ev->width		= event->u.createNotify.width;
	 ev->height		= event->u.createNotify.height;
	 ev->border_width	= event->u.createNotify.borderWidth;
	 ev->override_redirect	= event->u.createNotify.override;
	/* -- this event must be delivered by all means ! -- */
	must_deliver = True ;
     }
    break;
	
    case DestroyNotify:
    {    register XDestroyWindowEvent *ev = (XDestroyWindowEvent *) re;
	     
	 ev->window		= XmuXMapID( dpy ,
					     event->u.destroyNotify.window ,
					     FromServer ) ;
	 ev->event		= XmuXMapID( dpy ,
					     event->u.destroyNotify.event ,
					     FromServer ) ;
	/* -- this event must be delivered by all means ! -- */
	must_deliver = True ;
     }
    break;
	
    case UnmapNotify:
    {    register XUnmapEvent *ev = (XUnmapEvent *) re;
	
	 ev->window		= XmuXMapID( dpy , event->u.unmapNotify.window ,
					 FromServer ) ;
	 ev->event		= XmuXMapID( dpy , event->u.unmapNotify.event ,
					FromServer ) ;
	 ev->from_configure	= event->u.unmapNotify.fromConfigure;
	/* -- this event must be delivered by all means ! -- */
	must_deliver = True ;
     }
    break;
	
    case MapNotify:
    {    register XMapEvent *ev = (XMapEvent *) re;
	
	 ev->window		= XmuXMapID( dpy , event->u.mapNotify.window ,
					FromServer ) ;	
	 ev->event		= XmuXMapID( dpy , event->u.mapNotify.event ,
					 FromServer ) ;
	 
	 ev->override_redirect	= event->u.mapNotify.override;
	/* -- this event must be delivered by all means ! -- */
	must_deliver = True ;
     }
    break;
 
    case MapRequest:
    {    register XMapRequestEvent *ev = (XMapRequestEvent *) re;
	
	 ev->window		= XmuXMapID( dpy , event->u.mapRequest.window ,
					 FromServer ) ;
	 ev->parent		= XmuXMapID( dpy , event->u.mapRequest.parent ,
					 FromServer ) ;
	/* -- this event must be delivered by all means ! -- */
	must_deliver = True ;
     }
    break;
	
    case ReparentNotify:
    {    register XReparentEvent *ev = (XReparentEvent *) re;
	
	 ev->event		= XmuXMapID( dpy , event->u.reparent.event ,
					FromServer ) ;
	 ev->window		= XmuXMapID( dpy , event->u.reparent.window , 
					 FromServer ) ;
	 ev->parent		= XmuXMapID( dpy , event->u.reparent.parent ,
					 FromServer ) ;

	 ev->x		        = event->u.reparent.x;
	 ev->y		        = event->u.reparent.y;
	 ev->override_redirect	= event->u.reparent.override;
	/* -- this event must be delivered by all means ! -- */
	must_deliver = True ;
     }
    break;
	
    case ConfigureNotify:
    {    register XConfigureEvent *ev = (XConfigureEvent *) re;
	
	 ev->event	= XmuXMapID( dpy , event->u.configureNotify.event ,
				 FromServer ) ;
	 ev->window	= XmuXMapID( dpy , event->u.configureNotify.window ,
				 FromServer ) ;
	 ev->above	= XmuXMapID( dpy , 
				     event->u.configureNotify.aboveSibling ,
				     FromServer ) ;

	 ev->x	        = event->u.configureNotify.x;
	 ev->y	        = event->u.configureNotify.y;
	 ev->width	= event->u.configureNotify.width;
	 ev->height	= event->u.configureNotify.height;
	 ev->border_width  = event->u.configureNotify.borderWidth;
	 ev->override_redirect = event->u.configureNotify.override;
	/* -- this event must be delivered by all means ! -- */
	must_deliver = True ;
     }
    break;
 
    case ConfigureRequest:
    {    register XConfigureRequestEvent *ev = (XConfigureRequestEvent *) re;
	     
	 ev->window		= XmuXMapID( dpy ,
					     event->u.configureRequest.window ,
					     FromServer ) ;
	 ev->parent		= XmuXMapID( dpy ,
					     event->u.configureRequest.parent ,
					     FromServer ) ;
	 ev->above		= XmuXMapID( dpy ,
					     event->u.configureRequest.sibling ,
					     FromServer ) ;
	 
	 ev->x		        = event->u.configureRequest.x;
	 ev->y		        = event->u.configureRequest.y;
	 ev->width		= event->u.configureRequest.width;
	 ev->height		= event->u.configureRequest.height;
	 ev->border_width	= event->u.configureRequest.borderWidth;
	 ev->value_mask	        = event->u.configureRequest.valueMask;
	 ev->detail  	        = event->u.u.detail;
	/* -- this event must be delivered by all means ! -- */
	must_deliver = True ;
     }
    break;
	
    case GravityNotify:
    {    register XGravityEvent *ev = (XGravityEvent *) re;
	
	 ev->window		= XmuXMapID( dpy , event->u.gravity.window ,
					 FromServer ) ;
	 ev->event		= XmuXMapID( dpy , event->u.gravity.event ,
					 FromServer ) ;

	 ev->x		        = event->u.gravity.x;
	 ev->y		        = event->u.gravity.y;
	/* -- this event must be delivered by all means ! -- */
	must_deliver = True ;
     }
    break;
	
    case ResizeRequest:
    {    register XResizeRequestEvent *ev = (XResizeRequestEvent *) re;
	     
	 ev->window		= XmuXMapID( dpy , 
					     event->u.resizeRequest.window ,
					      FromServer ) ;

	 ev->width		= event->u.resizeRequest.width;
	 ev->height		= event->u.resizeRequest.height;
	/* -- this event must be delivered by all means ! -- */
	must_deliver = True ;
     }
    break;
	
    case CirculateNotify:
    {    register XCirculateEvent *ev = (XCirculateEvent *) re;
	
	 ev->window		= XmuXMapID( dpy , event->u.circulate.window ,
					 FromServer ) ;
	 ev->event		= XmuXMapID( dpy , event->u.circulate.event ,
					 FromServer ) ;

	 ev->place		= event->u.circulate.place;
     }
    break;
	
    case CirculateRequest:
    {    register XCirculateRequestEvent *ev = (XCirculateRequestEvent *) re;
	     
	 ev->window		= XmuXMapID( dpy , event->u.circulate.window ,
					 FromServer ) ;
	 ev->parent		= XmuXMapID( dpy , event->u.circulate.event ,
					 FromServer ) ;

	 ev->place		= event->u.circulate.place;
	/* -- this event must be delivered by all means ! -- */
	must_deliver = True ;
     }
    break;
	
    case PropertyNotify:
    {    register XPropertyEvent *ev = (XPropertyEvent *) re;
	
	 ev->window		= XmuXMapID( dpy , event->u.property.window ,
					 FromServer ) ;
	 ev->atom		= XmuXMapID( dpy , event->u.property.atom , 
					     FromServer ) ;
	 ev->time		= event->u.property.time;
	 ev->state		= event->u.property.state;
	 
	 XmuXEnq( default_dpy , ev ) ;
	 /*
	  * -- PropertyNotify Events are one of two event types (the other
	  * -- is ClientMessage) that we use to communicate with an 
	  * -- multiplex'ed applications. What we actually do is "augmenting"
	  * -- the event-masks of top-level windows with the 
	  * -- PropertyChangeMask. If we receive PropertyNotify Events, we
	  * -- have to check out whether this event was an "multiplexed-only"
	  * -- event. If so, we'll throw it away (although applications should
	  * -- be prepared to receive events that they don't specify in their
	  * -- event masks;e.g. ClientMessage Events: that's why we don't do
	  * -- the check there!)
	  */
	 if( XmuXSpecificEvent( default_dpy , ev->window ) )
	     mux_event = True ;
	 else
	     must_deliver = True ;
     }
    break;
	
    case SelectionClear:
    {    register XSelectionClearEvent *ev = (XSelectionClearEvent *) re;
	     
	 ev->window		= XmuXMapID( dpy ,
					     event->u.selectionClear.window ,
					     FromServer ) ;

	 ev->selection	        = event->u.selectionClear.atom;
	 ev->time		= event->u.selectionClear.time;
     }
    break;
	
    case SelectionRequest:
    {    register XSelectionRequestEvent *ev = (XSelectionRequestEvent *) re;
	     
	 ev->owner		= XmuXMapID( dpy ,
					     event->u.selectionRequest.owner ,
					     FromServer ) ;
	 ev->requestor	        = XmuXMapID( dpy ,
					  event->u.selectionRequest.requestor ,
					  FromServer ) ;

	 ev->selection	        = event->u.selectionRequest.selection;
	 ev->target		= event->u.selectionRequest.target;
	 ev->property	        = event->u.selectionRequest.property;
	 ev->time		= event->u.selectionRequest.time;
     }
    break;
	
    case SelectionNotify:
    {    register XSelectionEvent *ev = (XSelectionEvent *) re;
	
	 ev->requestor	= XmuXMapID( dpy , event->u.selectionNotify.requestor ,
				 FromServer ) ;

	 ev->selection	        = event->u.selectionNotify.selection;
	 ev->target		= event->u.selectionNotify.target;
	 ev->property	        = event->u.selectionNotify.property;
	 ev->time		= event->u.selectionNotify.time;
     }
    break;
	
    case ColormapNotify:
    {    register XColormapEvent *ev = (XColormapEvent *) re;
	
	 ev->window		= XmuXMapID( dpy , event->u.colormap.window ,
					 FromServer ) ;
	 ev->colormap	        = XmuXMapID( dpy , event->u.colormap.colormap ,
					 FromServer ) ;

	 ev->new		= event->u.colormap.new;
	 ev->state		= event->u.colormap.state;
	/* -- this event must be delivered by all means ! -- */
	must_deliver = True ;
     }
    break;
	
    case ClientMessage:
    {   register int i;
	register XClientMessageEvent *ev = (XClientMessageEvent *) re;
	    
	ev->window		= XmuXMapID( dpy , 
					     event->u.clientMessage.window ,
					     FromServer ) ;
	ev->format		= event->u.u.detail;
	switch (ev->format) 
	{
	case 8:	
	    ev->message_type = XmuXMapID( dpy ,
					  event->u.clientMessage.u.b.type ,
					  FromServer ) ;
	    for (i = 0; i < 20; i++) 	
		ev->data.b[i] = event->u.clientMessage.u.b.bytes[i];
	    break;
	
	case 16:
	    ev->message_type = XmuXMapID( dpy ,
					  event->u.clientMessage.u.s.type ,
					  FromServer ) ;

	    ev->data.s[0] = event->u.clientMessage.u.s.shorts0;
	    ev->data.s[1] = event->u.clientMessage.u.s.shorts1;
	    ev->data.s[2] = event->u.clientMessage.u.s.shorts2;
	    ev->data.s[3] = event->u.clientMessage.u.s.shorts3;
	    ev->data.s[4] = event->u.clientMessage.u.s.shorts4;
	    ev->data.s[5] = event->u.clientMessage.u.s.shorts5;
	    ev->data.s[6] = event->u.clientMessage.u.s.shorts6;
	    ev->data.s[7] = event->u.clientMessage.u.s.shorts7;
	    ev->data.s[8] = event->u.clientMessage.u.s.shorts8;
	    ev->data.s[9] = event->u.clientMessage.u.s.shorts9;
	    break;
		
	case 32:
	    ev->message_type = XmuXMapID( dpy ,
					  event->u.clientMessage.u.l.type ,
					  FromServer ) ;

	    ev->data.l[0] = event->u.clientMessage.u.l.longs0;
	    ev->data.l[1] = event->u.clientMessage.u.l.longs1;
	    ev->data.l[2] = event->u.clientMessage.u.l.longs2;
	    ev->data.l[3] = event->u.clientMessage.u.l.longs3;
	    ev->data.l[4] = event->u.clientMessage.u.l.longs4;
	    break;
	
	default: /* XXX should never occur */
	    break;
	}
	XmuXEnq( default_dpy , ev ) ;
	/* -- this event must be delivered by all means ! -- */
	must_deliver = True ;
    }
    break;
	
    case MappingNotify:
    {   register XMappingEvent *ev = (XMappingEvent *)re;
	
	ev->first_keycode 	= event->u.mappingNotify.firstKeyCode;
	ev->request 		= event->u.mappingNotify.request;
	ev->count 		= event->u.mappingNotify.count;
    }
    break;
 
    default:
        return(_XUnknownWireEvent(dpy, re, event));
    }

    /*
     * -- must fool client !!
     */
    ((XAnyEvent *)re)->display = default_dpy ;
    
    /*
     * -- DIRTY TRICK :
     * -- non chalk holder events should be thrown away; 
     * -- this will be done if _XWireToEvent returns 0, so we do that 
     */
    if( ( XmuXHasChalk( dpy ) || must_deliver ) && !mux_event )
    {
	XmuXdebug( debug_events , "\n" ) ;
	return( 1 );
    }
    else
    {
	XmuXdebug( debug_events , "thrown away (no chalk)\n" ) ;
	return( 0 );
    }
}


static char *_SysErrorMsg (n)
    int n;
{
    extern char *sys_errlist[];
    extern int sys_nerr;
    char *s = ((n >= 0 && n < sys_nerr) ? sys_errlist[n] : "unknown error");

    return (s ? s : "no such error");
}

/*
 * _XIOError - Default fatal system error reporting routine.  Called when
 * an X internal system error is encountered.
 */
_XIOError (dpy)
	Display *dpy;
{
	(void) fprintf (stderr, 
	 "XIO:  fatal IO error %d (%s) on X server \"%s\"\r\n",
			errno, _SysErrorMsg (errno), DisplayString (dpy));
	(void) fprintf (stderr, 
	 "      after %lu requests (%lu known processed) with %d events remaining.\r\n",
			NextRequest(dpy) - 1, LastKnownRequestProcessed(dpy),
			QLength(dpy));

	if (errno == EPIPE) {
	    (void) fprintf (stderr,
	 "      The connection was probably broken by a server shutdown or KillClient.\r\n");
	}

	/* -- Don't die on multiplex displays -- */
	if( !IsClientDisplay( dpy ) )
	{
	  XmuXFreeEntry( dpy ) ;
	  return( 0 ) ;
	}
	exit (1);
}

/*
 * _XError - Default non-fatal error reporting routine.  Called when an
 * X_Error packet is encountered in the input stream.
 */
int _XError (dpy, rep)
    Display *dpy;
    xError *rep;
{
    XErrorEvent event;
    /* 
     * X_Error packet encountered!  We need to unpack the error before
     * giving it to the user.
     */
    /* 
     * -- set the error checking variables
     */
    event.display = dpy;
    event.type = X_Error;
    event.serial = _SetLastRequestRead(dpy, (xGenericReply *)rep);
    event.resourceid = rep->resourceID;
    event.error_code = rep->errorCode;
    event.request_code = rep->majorCode;
    event.minor_code = rep->minorCode;
    fprintf( stderr, "Error detected by Server %s (# %d)\n" , 
	     DisplayString( dpy ) , dpy->fd ) ;
    /* -- multiplex'ed connections won't exit here -- */
    if( !IsClientDisplay( dpy ) )
    {
	XmuXSetLastError( dpy , &event ) ;
	( void ) _XPrintDefaultError( dpy , &event , 
				      logfile ? logfile : stderr ) ;
	return( 0 ) ;
    }
    if (_XErrorFunction != NULL) {
      	return ((*_XErrorFunction)(dpy, &event));
      }
    exit(1);
    /*NOTREACHED*/
}
    
int _XPrintDefaultError (dpy, event, fp)
    Display *dpy;
    XErrorEvent *event;
    FILE *fp;
{
    char buffer[BUFSIZ];
    char mesg[BUFSIZ];
    char number[32];
    char *mtype = "XlibMessage";
    XGetErrorText(dpy, event->error_code, buffer, BUFSIZ);
    XGetErrorDatabaseText(dpy, mtype, "XError", "X Error", mesg, BUFSIZ);
    (void) fprintf(fp, "%s:  %s\n  ", mesg, buffer);
    XGetErrorDatabaseText(dpy, mtype, "MajorCode", "Request Major code %d", 
	mesg, BUFSIZ);
    (void) fprintf(fp, mesg, event->request_code);
    sprintf(number, "%d", event->request_code);
    XGetErrorDatabaseText(dpy, "XRequest", number, "", 	buffer, BUFSIZ);
    (void) fprintf(fp, " (%s)", buffer);
    fputs("\n  ", fp);
    XGetErrorDatabaseText(dpy, mtype, "MinorCode", "Request Minor code", 
	mesg, BUFSIZ);
    (void) fprintf(fp, mesg, event->minor_code);
    fputs("\n  ", fp);
    XGetErrorDatabaseText(dpy, mtype, "ResourceID", "ResourceID 0x%x",
	mesg, BUFSIZ);
    (void) fprintf(fp, mesg, event->resourceid);
    fputs("\n  ", fp);
    XGetErrorDatabaseText(dpy, mtype, "ErrorSerial", "Error Serial #%d", 
	mesg, BUFSIZ);
    (void) fprintf(fp, mesg, event->serial);
    fputs("\n  ", fp);
    XGetErrorDatabaseText(dpy, mtype, "CurrentSerial", "Current Serial #%d",
	mesg, BUFSIZ);
    (void) fprintf(fp, mesg, dpy->request);
    fputs("\n", fp);
    if (event->error_code == BadImplementation) return 0;
    return 1;
}

int _XDefaultError(dpy, event)
	Display *dpy;
	XErrorEvent *event;
{
    if (_XPrintDefaultError (dpy, event, stderr) == 0) return 0;
    exit(1);
    /*NOTREACHED*/
}

int (*_XIOErrorFunction)() = _XIOError;
int (*_XErrorFunction)() = _XDefaultError;

/*
 * This routine can be used to (cheaply) get some memory within a single
 * Xlib routine for scratch space.  It is reallocated from the same place
 * each time, unless the library needs a large scratch space.
 */
char *_XAllocScratch (dpy, nbytes)
	register Display *dpy;
	unsigned long nbytes;
{
	if (nbytes > dpy->scratch_length) {
	    if (dpy->scratch_buffer != NULL) Xfree (dpy->scratch_buffer);
	    return( dpy->scratch_length = nbytes, 
	    dpy->scratch_buffer = Xmalloc ((unsigned)nbytes) );
	}
	return (dpy->scratch_buffer);
}

/*
 * Given a visual id, find the visual structure for this id on this display.
 */
Visual *_XVIDtoVisual (dpy, id)
	Display *dpy;
	VisualID id;
{
	register int i, j, k;
	register Screen *sp;
	register Depth *dp;
	register Visual *vp;
	for (i = 0; i < dpy->nscreens; i++) {
		sp = &dpy->screens[i];
		for (j = 0; j < sp->ndepths; j++) {
			dp = &sp->depths[j];
			for (k = 0; k < dp->nvisuals; k++) {
				vp = &dp->visuals[k];
				if (vp->visualid == id) return (vp);
			}
		}
	}
	return (NULL);
}

XFree (data)
	char *data;
{
	Xfree (data);
}

#ifdef DataRoutineIsProcedure
void Data (dpy, data, len)
	Display *dpy;
	char *data;
	long len;
{
	if (dpy->bufptr + (len) <= dpy->bufmax) {
		bcopy(data, dpy->bufptr, (int)len);
		dpy->bufptr += ((len) + 3) & ~3;
	} else {
		_XSend(dpy, data, len);
	}
}
#endif /* DataRoutineIsProcedure */


#ifdef WORD64

/*
 * XXX This is a *really* stupid way of doing this.  It should just use 
 * dpy->bufptr directly, taking into account where in the word it is.
 */

/*
 * Data16 - Place 16 bit data in the buffer.
 *
 * "dpy" is a pointer to a Display.
 * "data" is a pointer to the data.
 * "len" is the length in bytes of the data.
 */

static doData16(dpy, data, len, packbuffer)
    register Display *dpy;
    short *data;
    unsigned len;
    char *packbuffer;
{
    long *lp,*lpack;
    long i, nwords,bits;
    long mask16 = 0x000000000000ffff;

        lp = (long *)data;
        lpack = (long *)packbuffer;
        *lpack = 0;

/*  nwords is the number of 16 bit values to be packed,
 *  the low order 16 bits of each word will be packed
 *  into 64 bit words
 */
        nwords = len >> 1;
        bits = 48;

        for(i=0;i<nwords;i++){
           *lpack ^= (*lp & mask16) << bits;
           bits -= 16 ;
           lp++;
           if(bits < 0){
               lpack++;
               *lpack = 0;
               bits = 48;
           }
        }
        Data(dpy, packbuffer, len);
}

Data16 (dpy, data, len)
    Display *dpy;
    short *data;
    unsigned len;
{
    char packbuffer[PACKBUFFERSIZE];
    unsigned nwords = (PACKBUFFERSIZE >> 1);	/* bytes to CARD16 */

    for (; len > nwords; len -= nwords, data += nwords) {
	doData16 (dpy, data, nwords, packbuffer);
    }
    doData16 (dpy, data, len, packbuffer);
}

/*
 * Data32 - Place 32 bit data in the buffer.
 *
 * "dpy" is a pointer to a Display.
 * "data" is a pointer to the data.
 * "len" is the length in bytes of the data.
 */

static doData32 (dpy, data, len, packbuffer)
    register Display *dpy;
    long *data;
    unsigned len;
    char *packbuffer;
{
    long *lp,*lpack;
    long i,bits,nwords;
    long mask32 = 0x00000000ffffffff;

        lpack = (long *) packbuffer;
        lp = data;

        *lpack = 0;

/*  nwords is the number of 32 bit values to be packed
 *  the low order 32 bits of each word will be packed
 *  into 64 bit words
 */
        nwords = len >> 2;
        bits = 32;

        for(i=0;i<nwords;i++){
           *lpack ^= (*lp & mask32) << bits;
           bits = bits ^32;
           lp++;
           if(bits){
              lpack++;
              *lpack = 0;
           }
        }
        Data(dpy, packbuffer, len);
}

Data32 (dpy, data, len)
    Display *dpy;
    short *data;
    unsigned len;
{
    char packbuffer[PACKBUFFERSIZE];
    unsigned nwords = (PACKBUFFERSIZE >> 2);	/* bytes to CARD32 */

    for (; len > nwords; len -= nwords, data += nwords) {
	doData32 (dpy, data, nwords, packbuffer);
    }
    doData32 (dpy, data, len, packbuffer);
}

#endif /* WORD64 */



/*
 * _XFreeQ - free the queue of events, called by XCloseDisplay when there are
 * no more displays left on the display list
 */

void _XFreeQ ()
{
    register _XQEvent *qelt = _qfree;
  
    while (qelt) {
	register _XQEvent *qnext = qelt->next;
	Xfree (qelt);
	qelt = qnext;
    }
    _qfree = NULL;
    return;
}
