/* $Id: XlibInt.c,v 1.3 90/11/30 11:34:17 spanachi Exp $ */

#include "copyright.h"

/*
 * 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 */
  long pending[MAXSOCKS];
  register long pend;
  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;
      /* 
       * keyboard encodings may differ; try yo map it
       * might not work in all cases !
       * What are we doing here: pass the display dependend KeyCode 
       * to the display the event comes from and retrieve the display 
       * INDEPENDENT KeySym. Then pass the KeySym to the client display and
       * get it's KeyCode. 
       * Any questions?
       */
      ev->keycode = XKeysymToKeycode(default_dpy,
			XKeycodeToKeysym(dpy,event->u.u.detail,0));
    }
    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;

      /* 
       * keyboard encodings may differ; try yo map it
       * might not work in all cases !
       * What are we doing here: pass the display dependend KeyCode 
       * to the display the event comes from and retrieve the display 
       * INDEPENDENT KeySym. Then pass the KeySym to the client display and
       * get it's KeyCode. 
       * Any questions?
       */
      ev->first_keycode = 
	XKeysymToKeycode(default_dpy,
	    XKeycodeToKeysym(dpy,event->u.mappingNotify.firstKeyCode,0));
      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;
}
