/*
 *	$Source: /u1/Xr/src/Xrlib/Intrinsic/RCS/input.c,v $
 *	$Header: input.c,v 1.1 86/12/17 09:08:34 swick Exp $
 */

#ifndef lint
static char *rcsid_input_c = "$Header: input.c,v 1.1 86/12/17 09:08:34 swick Exp $";
#endif	lint

#include <Xr/xr-copyright.h>

/* $Header: input.c,v 1.1 86/12/17 09:08:34 swick Exp $ */
/* Copyright 1986, Hewlett-Packard Company */
/* Copyright 1986, Massachussetts Institute of Technology */

static char rcsid[] = "$Header: input.c,v 1.1 86/12/17 09:08:34 swick Exp $";
/*************************************<+>*************************************
 *****************************************************************************
 **
 **   File:        input.c
 **
 **   Project:     X-ray Toolbox
 **
 **   Description: Handle all of the input processing for X-ray.
 **
 **
 **   ------------------------ MODIFICATION RECORD   ------------------------
 *
 * $Log:	input.c,v $
 * Revision 1.1  86/12/17  09:08:34  swick
 * Initial revision
 * 
 * Revision 7.0  86/11/13  08:20:13  08:20:13  rick ()
 * Final QA release
 * 
 * Revision 6.2  86/11/12  07:38:51  07:38:51  rick ()
 * Fixed the NULL ptr reference in MSG_SETPROCESSFLAG.
 * 
 * Revision 6.1  86/11/11  12:17:48  12:17:48  rick ()
 * Changed the QLength() call to XPending() in MSG_PEEKEVENT.
 * 
 * Revision 6.0  86/11/10  15:22:03  15:22:03  rick ()
 * QA #2 release
 * 
 * Revision 5.4  86/11/07  14:01:58  14:01:58  rick ()
 * Added the copyright message.
 * 
 * Revision 5.3  86/10/30  13:24:38  13:24:38  rick ()
 * Added additional file descriptor verification for ADD and REMOVE INPUT.
 * 
 * Revision 5.2  86/10/30  11:43:58  11:43:58  rick ()
 * Changed the ADDINPUT handling of the X file descriptors to only allow
 * one X file descriptor in the set of selected upon fds.
 * 
 * Revision 5.0  86/10/28  08:22:46  08:22:46  rick ()
 * QA #1.1 release
 * 
 * Revision 4.1  86/10/27  13:33:29  13:33:29  rick ()
 * Changed the mapping of Key input in ProcessInput.
 * 
 * Revision 4.0  86/10/20  12:08:49  12:08:49  rick ()
 * QA 1 release
 * 
 * Revision 3.7  86/10/20  08:46:49  08:46:49  rick ()
 * Removed the #include <sys/param.h> and put the define for MAX_ALARM
 * in defs.h as XrMAX_ALARM.
 * 
 * Revision 3.6  86/10/17  12:23:35  12:23:35  rick ()
 * Linted
 * 
 * Revision 3.5  86/10/16  11:20:42  11:20:42  rick ()
 * Added register variables.
 * 
 * Revision 3.4  86/10/13  13:54:32  13:54:32  rick ()
 * Changed the XLookupMapping call to XrMapInput
 * 
 * Revision 3.3  86/10/10  14:51:35  14:51:35  rick ()
 * Fixed the button modifier checking in ProcessInput. 
 * 
 * Revision 3.2  86/10/10  13:13:17  13:13:17  rick ()
 * Added the changes in ProcessInput to handle the button modifiers.
 * 
 * Revision 3.1  86/10/06  09:57:59  09:57:59  rick ()
 * Added the automatic editor, group, and function list removal
 * from MSG_REMOVEWINDOW.
 * 
 * Revision 3.0  86/10/02  15:58:45  15:58:45  rick ()
 *  Alpha release set to 3.0
 * 
 * Revision 2.3  86/09/23  09:57:03  09:57:03  rick ()
 * Added an initialization of the inputCode field of the windowEvent
 * structure in ProcessKey.
 * 
 * Revision 2.2  86/09/22  10:08:59  10:08:59  rick ()
 * Added the check for a TRUE processFlag when comparing the window's
 * function event list structure.
 * 
 * Revision 2.1  86/09/19  10:42:18  10:42:18  rick ()
 * Changed the initialization of the base editor group from
 * the entire window to zero rect.
 * 
 * Revision 2.0  86/09/16  08:01:06  08:01:06  rick ()
 * Added new input scheme of no conversion of button or ascii input.
 * Changed the event list structure for indirect function calling.
 * 
 * Revision 1.5  86/09/11  08:01:13  08:01:13  rick ()
 * Added an initialization for the default group in MSG_ADDWINDOW.
 * 
 * Revision 1.4  86/09/05  14:43:15  14:43:15  rick ()
 * Finished fixing MSG_REMOVEWINDOWFUNCT.
 * 
 * Revision 1.3  86/09/05  06:43:53  06:43:53  rick ()
 * Added a malloc and copy of the applications event list for 
 * the message to add a window function.
 * Fixed the function removal in the message to remove a window funct.
 * 
 * Revision 1.2  86/09/04  09:15:20  09:15:20  rick ()
 * Fixed NONBLKHOTREAD handling of input events in _XrProcessInput().
 * 
 * Revision 1.1  86/09/03  13:35:14  13:35:14  rick ()
 * Initial revision
 * 
 *
 *****************************************************************************
 *************************************<+>*************************************/


#ifdef BSD
#include <sys/time.h>
#else
#include <time.h>
#endif
#include <X/Xlib.h>
#include <Xr/defs.h>
#include <Xr/types.h>
#include <Xr/in_types.h>



/*
 *  Defines used locally for the file descriptor tables.
 */

#define XrTABLESIZE 64
#define XrMASKSIZE 4


/*
 *  Select input timeout values.  ZeroTime is for unblocked reads (polling).
 *  userTime is for the user selected timeout and is initialize to max time.
 *  selectTime gets set to one of the above two times and is used by select.
 */

static struct timeval   zeroTime = { 0, 0 };
static struct timeval   usrTime = { XrMAX_ALARM, 0 };
static struct timeval * selectTime;


/*
 *  The following three tables contain the file descriptors 
 *  used for reading, writing, and exceptions respectively.
 */

static int readFds [XrTABLESIZE], 
           writeFds [XrTABLESIZE], 
           exceptFds [XrTABLESIZE];


/*
 *  Counts of how many read, write, and except file descriptors.
 */

static int readCount = 0;
static int writeCount = 0;
static int exceptCount = 0;
static int xfdIndex = -1;


/*
 *  fdCount is the maximum of the file descriptor values defined
 *  in the Fds tables and is used for the select(2) call.
 */

static int fdCount;


/*
 *  The mask sets used for the select call and copies of the masks
 *  used to restore the masks after select.
 */

static unsigned int readMasks[XrMASKSIZE], readSaveMasks[XrMASKSIZE];
static unsigned int writeMasks[XrMASKSIZE], writeSaveMasks[XrMASKSIZE];
static unsigned int exceptMasks[XrMASKSIZE], exceptSaveMasks[XrMASKSIZE];


/*
 *  Resource info structure used access the registered windows in
 *  the resource manager.
 */

static xrResourceInfo resourceInfo = 
   { XrTYPE_REGWINDOW, 0, 0, XrMEMORY, NULL };



/*************************************<->*************************************
 *
 *  XrInput (windowId, message, data)
 *  INT32  windowId;
 *  INT32  message;
 *  INT8 * data;
 *
 *
 *   Description:
 *   -----------
 *     The XrInput() routine handles all requests for input by an 
 *     application from a window or windows.  Within X-ray, all input
 *     is routed through a single entry point.  This provies for a
 *     one routine interface to all of the types of input an application
 *     will need.  The input routine also provides the mechanism for 
 *     routines that handle the higher level X-ray functions to route the
 *     results of their actions through the same input stream.  For a
 *     complete description of the resource manager, refer to XrInput(3Xr)
 *     and the X-ray toolbox manual.
 *
 *
 *   Inputs:
 *   ------
 *     windowId = Several of the messages operate upon a particular window.
 *                This parameter contains the id of that window.
 *
 *     message  = Contains the message which describes the capability
 *                to be executed.
 *
 *     data     = Contains a pointer to a structure mecessary for the
 *                completion of the message.
 *
 *
 *     For a complete description of the resource managers messages and
 *     data parameters, refer to XrInput(3XR) and the X-ray toolbox manual.
 *
 * 
 *   Outputs:
 *   -------
 *     windowId = Returned as the value of the function if a message 
 *                which requires a windowId succeeds.
 *
 *     TRUE     = Returned as the value of the function if a message
 *                which does not require a windowId succeeds.
 *
 *     FALSE = Returned as the value of the function if the message fails.
 *
 *     data  = Several of the messages return information in the structure
 *             pointed at by data.
 *
 *     xrError = The error variable is set to one several values upon
 *               failure of this routine.
 *
 *     For a complete description of the values returned in data, 
 *     refer to XrInput(3XR) and the X-ray toolbox manual.
 *
 *
 *   Procedures Called
 *   -----------------
 *     _XrProcessInput()
 *     _XrAddFd()
 *     _XrRemoveFd()
 *     _Xrmemcpy()	  -  utilities.c
 *     XrResource()       -  resource.c
 *     XrCopyRect()       -  calc.c
 *     XPending()         -  Xlib
 *     XNextEvent()       -  Xlib
 *     XPutBackEvent()    -  Xlib
 *     XSync()            -  Xlib
 *     select()
 *
 *************************************<->***********************************/


Window
XrInput (windowId, message, data)
Window  windowId;
INT32   message;
INT8  * data;

{


   /*
    *  Set up a switch to handle each of the messages.
    */

   switch (message)
   {

      /*
       *  Register a window with XrInput() by allocating an xrWindow
       *  structure initializing it, and adding into the resource manager.
       */

      case MSG_ADDWINDOW:
      {
         register xrWindow     * window;
         register xrWindowData * windowData;

      
         windowData = (xrWindowData *) data;

         resourceInfo.resourceId = windowId;


         if (data == NULL)
         {
            xrErrno = XrINVALIDPARM;
            return ((Window) FALSE);
         }

         if (windowId == 0 || XrResource (MSG_FIND, &resourceInfo) == TRUE)
         {
            xrErrno = XrINVALIDID;
            return ((Window) FALSE);
         }


         /*
          *  Allocate the xrWindow and default processing 
          *  event structures neccessary for the window.
          */

         if ((window = (xrWindow *) (*xrMalloc) (sizeof (xrWindow))) == NULL)
         {
            xrErrno = XrOUTOFMEM;
            return ((Window) FALSE);
         }

         if ((window -> functList.eventList = 
             (xrWindowEvent *) (*xrMalloc) (sizeof (xrWindowEvent))) == NULL)
         {
            (*xrFree)(window);
            xrErrno = XrOUTOFMEM;
            return ((Window) FALSE);
         }


         /*
          *  Set the relevant members of the resource info structure
          *  and add the window resource into the resource manager.
          */
      
         resourceInfo.resourceObject = (INT8 *) window;

         if (XrResource (MSG_ADD, &resourceInfo) == FALSE)
         {
            (*xrFree)(*(window -> functList.eventList));
            (*xrFree)(window);
            return ((Window) FALSE);
         }


         /*
          *  Initialize the members of the windowData structure.
          */

         XrCopyRect (&windowData -> windowRect, &window -> windowRect);
         window -> foreTile = windowData -> foreTile;
         window -> backTile = windowData -> backTile;
         window -> activeGroup = &(window -> groupList);


         /*
          *  Initialize the members of the group list structure.
          */

         window -> groupList.groupWindowId = windowId;
         XrCopyRect (&xrZeroRect, &(window -> groupList.groupRect));
         window -> groupList.groupState = XrVISIBLE | XrSENSITIVE;
         window -> groupList.editorList = NULL;
         window -> groupList.graphicList = NULL;
         window -> groupList.nextGroup = NULL;


         /*
          *  Initialize the members of the function list structure.
          */

         window -> functList.processFlag = TRUE;
         window -> functList.funct = (xrPFI) XrEditor;
         window -> functList.instance = windowId;
         window -> functList.message = MSG_PROCESSKEY;

         window -> functList.eventCount = 1;
         window -> functList.nextFunct = NULL;


         /*
          *  Initialize the members of the function list event list structure.
          */

         XrGetWindowEvent (XrSELECT, window -> functList.eventList);

         return (windowId);
      }
      break;


      /*
       *  Remove (de-register) a window by removing it from the 
       *  resource manager.
       */

      case MSG_REMOVEWINDOW:
      {
         register xrWindow * window;
         register xrWindowFunct * functPtr;
         register xrWindowFunct * nextFunctPtr;


         resourceInfo.resourceId = windowId;

         if (XrResource (MSG_FIND, &resourceInfo) == FALSE)
         {
            xrErrno = XrINVALIDID;
            return ((Window) FALSE);
         }

         window = (xrWindow *) resourceInfo.resourceObject;
         functPtr = window -> functList.nextFunct;


         /*
          *  Free the default event list and all of the funct
          *  structures.
          */

         (*xrFree) (window -> functList.eventList);
         while (functPtr != NULL)
         {
            nextFunctPtr = functPtr -> nextFunct;
            (*xrFree) (functPtr -> eventList);
            (*xrFree) (functPtr);
            functPtr = nextFunctPtr;
         }
         window -> functList.eventList = NULL;
         window -> functList.nextFunct = NULL;


         /*
          *  Free all of the editors and editor groups.
          */

         while (window -> groupList.nextGroup != NULL)
            XrEditorGroup (window -> groupList.nextGroup, MSG_FREE, NULL);
         XrEditorGroup (&(window -> groupList), MSG_FREE, NULL);


         /*
          *  Remove the window from the resource manager and free
          *  the window structure.
          */

         if (XrResource (MSG_REMOVE, &resourceInfo) == FALSE)
         {
            xrErrno = XrINVALIDID;
            return ((Window) FALSE);
         }

         (*xrFree)(window);

         return (windowId);
      }
      break;


      /*
       *  Set some of the window specific data, i.e. the windowRect,
       *  foreTile, and backTile.
       */

      case MSG_SETWINDOWDATA:
      {
         register xrWindowData * windowData;
         register xrWindow     * window;


         if ((windowData = (xrWindowData *) data) == NULL)
         {
            xrErrno = XrINVALIDPARM;
            return ((Window) FALSE);
         }

         resourceInfo.resourceId = windowId;
         if (XrResource (MSG_FIND, &resourceInfo) == FALSE)
         {
            xrErrno = XrINVALIDID;
            return ((Window) FALSE);
         }

         window = (xrWindow *) resourceInfo.resourceObject;

         XrCopyRect (&windowData -> windowRect, &window -> windowRect);
         window -> foreTile = windowData -> foreTile;
         window -> backTile = windowData -> backTile;

         return (windowId);
      }
      break;


      /*
       *  Get some of the window specific data, i.e. the windowRect,
       *  foreTile, and backTile.
       */

      case MSG_GETWINDOWDATA:
      {
         register xrWindowData * windowData;
         register xrWindow     * window;


         if ((windowData = (xrWindowData *) data) == NULL)
         {
            xrErrno = XrINVALIDPARM;
            return ((Window) FALSE);
         }

         resourceInfo.resourceId = windowId;
         if (XrResource (MSG_FIND, &resourceInfo) == FALSE)
         {
            xrErrno = XrINVALIDID;
            return ((Window) FALSE);
         }

         window = (xrWindow *) resourceInfo.resourceObject;

         XrCopyRect (&window -> windowRect, &windowData -> windowRect);
         windowData -> foreTile = window -> foreTile;
         windowData -> backTile = window -> backTile;

         return (windowId);
      }
      break;


      /*
       *  Add an xrWindowFunct structure into the window specified.
       *  This will add another indirect window function.
       */

      case MSG_ADDWINDOWFUNCT:
      {
         register xrWindowFunct     * windowFunct;
         register xrWindowFunct     * newWindowFunct;
         register xrWindowFunct     * functPtr;


         if ((windowFunct = (xrWindowFunct *) data) == NULL)
         {
            xrErrno = XrINVALIDPARM;
            return ((Window) FALSE);
         }


         /*
          *  Find the resource which contain's the window's information.
          */

         resourceInfo.resourceId = windowId;
         if (XrResource (MSG_FIND, &resourceInfo) == FALSE)
         {
            xrErrno = XrINVALIDID;
            return ((Window) FALSE);
         }


         /*
          *  Allocate an xrWindowFunct structure to hold the new
          *  function to be attached to the window and an xrEvent
          *  array to hold the event list.
          */

         if ((newWindowFunct = 
             (xrWindowFunct *) (*xrMalloc) (sizeof (xrWindowFunct))) == NULL)
         {
            xrErrno = XrOUTOFMEM;
            return ((Window) FALSE);
         }

         if ((newWindowFunct -> eventList = (xrWindowEvent *) (*xrMalloc)
             (windowFunct -> eventCount * sizeof (xrWindowEvent))) == NULL)
         {
            (*xrFree)(newWindowFunct);
            xrErrno = XrOUTOFMEM;
            return ((Window) FALSE);
         }


         /*
          *  Go out to the end of the window's function list and
          *  attach the malloc'ed xrWindowFunct structure.
          */

         functPtr = &(((xrWindow *)(resourceInfo.resourceObject))->functList);
         while (functPtr -> nextFunct != NULL)
            functPtr = functPtr -> nextFunct;
         functPtr -> nextFunct = newWindowFunct;


         /*
          *  Set the members of the malloc'ed xrWindowFunct structure
          *  to the values in the data parameter.
          */

         _Xrmemcpy (newWindowFunct -> eventList, windowFunct -> eventList,
                    windowFunct -> eventCount * sizeof (xrWindowEvent));
         newWindowFunct -> funct = windowFunct -> funct;
         newWindowFunct -> instance = windowFunct -> instance;
         newWindowFunct -> message = windowFunct -> message;
         newWindowFunct -> processFlag = windowFunct -> processFlag;
         newWindowFunct -> eventCount = windowFunct -> eventCount;
         newWindowFunct -> nextFunct = NULL;

         return (windowId);
      }
      break;


      /*
       *  Remove an xrWindowFunct structure into the window specified.
       *  This will remove an indirect window function.
       */

      case MSG_REMOVEWINDOWFUNCT:
      {
         register xrWindowFunct * functPtr;
         register xrWindowFunct * removeFunctPtr;
         register xrPFI   funct;
         xrWindow       * window;


         if ((funct = (xrPFI) data) == NULL)
         {
            xrErrno = XrINVALIDPARM;
            return ((Window) FALSE);
         }


         /*
          *  Find the resource which contain's the window's information.
          */

         resourceInfo.resourceId = windowId;
         if (XrResource (MSG_FIND, &resourceInfo) == FALSE)
         {
            xrErrno = XrINVALIDID;
            return ((Window) FALSE);
         }


         /*
          *  Go find the function structure which contains the 
          *  function to be removed, and remove it and free it.
          */

         window = (xrWindow *)(resourceInfo.resourceObject);
         functPtr = window -> functList.nextFunct;

         if (functPtr == NULL)
         {
            xrErrno = XrINVALIDPARM;
            return ((Window) FALSE);
         }

         removeFunctPtr = NULL;

         if (functPtr -> funct == funct)
         {
            removeFunctPtr = window -> functList.nextFunct;
            window -> functList.nextFunct = removeFunctPtr -> nextFunct;
         }
         else
         {
            while (functPtr -> nextFunct != NULL)
            {
               if (functPtr -> nextFunct -> funct == funct)
               {
                  removeFunctPtr = functPtr -> nextFunct;
                  functPtr -> nextFunct = functPtr -> nextFunct -> nextFunct;
                  break;
               }
               functPtr = functPtr -> nextFunct;
            }
         }

         if (removeFunctPtr == NULL)
         {
           xrErrno = XrINVALIDPARM;
           return ((Window) FALSE);
         }

         (*xrFree)(removeFunctPtr -> eventList);
         (*xrFree)(removeFunctPtr);
         return (windowId);
      }
      break;


      /*
       *  Turn on or off a window's indirect processing functions by
       *  finding the window in the resource manager and then setting
       *  or clearing the processFlag according to the message.
       */

      case MSG_SETPROCESSFLAG:
      case MSG_CLEARPROCESSFLAG:
      {
         register xrPFI funct;
         register xrWindowFunct * functPtr;


         if ((funct = (xrPFI) data) == NULL)
         {
            xrErrno = XrINVALIDPARM;
            return ((Window) FALSE);
         }


         /*
          *  Find the resource which contain's the window's information.
          */

         resourceInfo.resourceId = windowId;
         if (XrResource (MSG_FIND, &resourceInfo) == FALSE)
         {
            xrErrno = XrINVALIDID;
            return ((Window) FALSE);
         }

         /*
          *  Find the function which matches the input data parameter
          *  and then set or clear its processflag as appropriate.
          */

         functPtr = &(((xrWindow *)(resourceInfo.resourceObject))->functList);
         while (functPtr -> funct != funct)
         {
            functPtr = functPtr -> nextFunct;

            if (functPtr == NULL)
            {
               xrErrno = XrINVALIDPARM;
               return ((Window) FALSE);
            }
         }

         if (message == MSG_SETPROCESSFLAG)
            functPtr -> processFlag = TRUE;
         else
            functPtr -> processFlag = FALSE;

         return (windowId);
      }
      break;


      /*
       *  The following set of messages handle the return of input
       *  to the application.
       */

      case MSG_BLKREAD:
      case MSG_NONBLKREAD:
      case MSG_BLKHOTREAD:
      case MSG_NONBLKHOTREAD:
      {
         register XEvent  * xInput;
         register xrEvent * xrInput;
         register INT32     inputCount;
         register INT32     i;


         if ((xInput = (XEvent *) data) == NULL)
         {
            xrErrno = XrINVALIDPARM;
            return ((Window) FALSE);
         }

         xrInput = (xrEvent *) data;


         /*
          *  See if the X input queue has input pending.  If
          *  it does, process the input and return it to the 
          *  application.
          */

         if (XPending ())
         {
            XNextEvent (xInput);

            if (message == MSG_BLKREAD || message == MSG_NONBLKREAD)
               return ((Window) TRUE);
            else
               return (_XrProcessInput (xInput));
         }


         /*
          *  Set up the masks and timeout for a select and execute
          *  the select to wait for blocked input.
          */

         for (i = 0; i < XrMASKSIZE; i++)
         {
            readMasks [i] = readSaveMasks [i];
            writeMasks [i] = writeSaveMasks [i];
            exceptMasks [i] = exceptSaveMasks [i];
         }

         if (message == MSG_BLKREAD || message == MSG_BLKHOTREAD)
            selectTime = &usrTime;
         else
            selectTime = &zeroTime;

         if ((inputCount = select (fdCount, readMasks, writeMasks,
                                   exceptMasks, selectTime)) <= 0)
            return ((Window) FALSE);


         /*
          *  Check for exception input.
          */

         for (i = exceptCount - 1; i >= 0 && inputCount > 0; i--)
         {
            if (exceptMasks[(exceptFds[i] >> 5)] & (1 << (exceptFds[i] & 31)))
            {
               inputCount--;
               xrInput -> type = XrXRAY;
               xrInput -> source = (INT32) exceptFds[i];
               xrInput -> inputType = XrFILE;
               xrInput -> inputCode = XrEXCEPTION;
               XPutBackEvent ((XEvent *) xrInput);
            }
         }


         /*
          *  Check for write input pending.
          */

         for (i = writeCount - 1; i >= 0 && inputCount > 0; i--)
         {
            if (writeMasks[(writeFds[i] >> 5)] & (1 << (writeFds[i] & 31)))
            {
               inputCount--;
               xrInput -> type = XrXRAY;
               xrInput -> source = (INT32) writeFds[i];
               xrInput -> inputType = XrFILE;
               xrInput -> inputCode = XrWRITE;
               XPutBackEvent ((XEvent *) xrInput);
            }
         }


         /*
          *  Check for read input pending.
          */

         for (i = readCount - 1; i >= 0 && inputCount > 0; i--)
         {
            if (readMasks [(readFds[i] >> 5)] & (1 << (readFds[i] & 31)))
            {
               if (i == xfdIndex)	/*  input from an X server?  */
               {
                  inputCount--;

                  XNextEvent (xInput);

                  if (message == MSG_BLKHOTREAD ||
                      message == MSG_NONBLKHOTREAD)
                     _XrProcessInput (xInput);

                  XPutBackEvent ((XEvent *) xInput);                  
               }
               else
               {
                  inputCount--;
                  xrInput -> type = XrXRAY;
                  xrInput -> source = (INT32) readFds[i];
                  xrInput -> inputType = XrFILE;
                  xrInput -> inputCode = XrREAD;
                  XPutBackEvent ((XEvent *) xrInput);
               }
            }
         }

         XNextEvent (xInput);
         return ((Window) TRUE);
      }
      break;


      /*
       *  The following set of messages allow the input queue to
       *  be played with.
       */

      case MSG_PUSHEVENT:
         if (data == NULL)
         {
            xrErrno = XrINVALIDPARM;
            return ((Window) FALSE);
         }

         XPutBackEvent ((XEvent *) data);
         return ((Window) TRUE);
      break;


      case MSG_PEEKEVENT:
         if (data == NULL)
         {
            xrErrno = XrINVALIDPARM;
            return ((Window) FALSE);
         }

         if (XPending())
         {
           XPeekEvent ((XEvent *) data);
           return ((Window) TRUE);
         }
         return ((Window) FALSE);
      break;


      case MSG_CLEAR:
         XSync (TRUE);
         return ((Window) TRUE);
      break;


      /*
       *  The following set of messages set and change input sources.
       */

      case MSG_ADDINPUT:
      {
         register xrFDInput * inputSource;
         register INT32       i;

         if (data == NULL)
         {
            xrErrno = XrINVALIDPARM;
            return ((Window) FALSE);
         }

         inputSource = (xrFDInput *) data;

         if (inputSource -> fd < 0 || 
             !(inputSource -> type & (XrREAD | XrWRITE | XrEXCEPTION)))
         {
            xrErrno = XrINVALIDPARM;
            return ((Window) FALSE);
         }


         if (inputSource -> fd == dpyno())
         {
            if (xfdIndex != -1)
               _XrRemoveFd (XrREAD, readFds[xfdIndex]);

            if (_XrAddFd (XrREAD, inputSource -> fd) == FALSE)
            {
               xrErrno = XrINVALIDID;
               return ((Window) FALSE);
            }
            xfdIndex = readCount - 1;
         }
         else
            if (_XrAddFd (inputSource -> type, inputSource -> fd) == FALSE)
            {
               xrErrno = XrINVALIDID;
               return ((Window) FALSE);
            }

         return ((Window) TRUE);
      }
      break;


      case MSG_REMOVEINPUT:
      {
         register xrFDInput * inputSource;

         if (data == NULL)
         {
            xrErrno = XrINVALIDPARM;
            return ((Window) FALSE);
         }

         inputSource = (xrFDInput *) data;

         if (inputSource -> fd < 0 || 
             !(inputSource -> type & (XrREAD | XrWRITE | XrEXCEPTION)))
         {
            xrErrno = XrINVALIDPARM;
            return ((Window) FALSE);
         }

         _XrRemoveFd (((xrFDInput *) data) -> type, 
                      ((xrFDInput *) data) -> fd);
         return ((Window) TRUE);
      }
      break;


      case MSG_SETTIMEOUT:
         if (data == NULL)
         {
            xrErrno = XrINVALIDPARM;
            return ((Window) FALSE);
         }

         usrTime.tv_sec = ((struct timeval *) data) -> tv_sec;
         usrTime.tv_usec = ((struct timeval *) data) -> tv_usec;
         return ((Window) TRUE);
      break;


      case MSG_GETTIMEOUT:
      {
         struct timeval * time;

         if (data == NULL)
         {
            xrErrno = XrINVALIDPARM;
            return ((Window) FALSE);
         }

         time = (struct timeval *) data;
         time -> tv_sec = usrTime.tv_sec;
         time -> tv_usec = usrTime.tv_usec;
         return ((Window) TRUE);
      }
      break;


      default:
         xrErrno = XrINVALIDMSG;
         return ((Window) FALSE);
      break;
   }

   return ((Window) FALSE);
}



/*************************************<->*************************************
 *
 *  _XrProcessInput (event)
 *  XEvent * event;
 *
 *
 *   Description:
 *   -----------
 *     _XrProcessInput() is called when there is X input pending and
 *     the read type was hot read.  It processes the input by comparing
 *     it to the set of functions attached to the window and calling
 *     the function is a match is found.
 *
 *
 *   Inputs:
 *   ------
 *     event = The XEvent to be processed.
 *
 * 
 *   Outputs:
 *   -------
 *     event = The XEvent that was read and processed is returned
 *             through the event parameter.
 *
 *
 *   Procedures Called
 *   -----------------
 *     XNextEvent      -  Xlib
 *     XrInputMap      -
 *     XrResource      -  resource.c
 *
 *************************************<->***********************************/


_XrProcessInput (event)
XKeyOrButtonEvent * event;

{
   register xrWindowFunct * listPtr;
   register xrWindowEvent * eventPtr;
   register INT32  i;
   INT8 * inputString;
   INT32  stringLen;
   xrWindowEvent   windowEvent;


   resourceInfo.resourceId = event -> window;
   if (XrResource (MSG_FIND, &resourceInfo) == FALSE)
      return (TRUE);

   windowEvent.inputType = event -> type;
   windowEvent.inputCode = 0;

   if (event -> type & (KeyPressed | KeyReleased))
   {
      inputString = XrInputMap (event, &stringLen);
      if (stringLen > 2)
         return (TRUE);
      if (stringLen == 1)
         windowEvent.inputCode = *inputString;
      else
         strncpy (&windowEvent.inputCode, inputString, stringLen);
   }

   else if (event -> type & (ButtonPressed | ButtonReleased))
      windowEvent.inputCode = 
         event->detail & (ControlMask | MetaMask | ShiftMask | 0x00FF);


   /*
    *  Process the input if it meets the following conditions.  Compare
    *  the set of events within be function list attached to the window
    *  to the input.  When a match is found, invoke the function which
    *  corresponds to the event.
    */

   listPtr = &(((xrWindow *)(resourceInfo.resourceObject)) -> functList);

   while (listPtr != NULL)
   {
      if (listPtr -> processFlag)
      {
         for (i = 0; i < listPtr -> eventCount; i++)
         {
            eventPtr = listPtr -> eventList + i;

            if (windowEvent.inputType & eventPtr -> inputType)
            {
               if (windowEvent.inputType & (ButtonPressed | ButtonReleased))
               {
                  if ((windowEvent.inputCode & 0x00FF) == 
                       (eventPtr -> inputCode & 0x00FF))
                  {
                     if ((((windowEvent.inputCode & 0xFF00) == 0)  &&
                          ((eventPtr -> inputCode & 0xFF00) == 0)) ||
                          ((windowEvent.inputCode & 0xFF00) &
                           (eventPtr -> inputCode & 0xFF00)))
                     {
                        if (((*listPtr -> funct) 
                          (listPtr->instance,listPtr->message,event))!=FALSE)
                        {
                           XNextEvent ((XEvent *) event);
                           return (TRUE);
                        }
                     }
                  }
               }
               else if (windowEvent.inputCode == eventPtr -> inputCode)
               {
                  if (((*listPtr -> funct) 
                   (listPtr -> instance, listPtr -> message, event)) != FALSE)
                  {
                     XNextEvent ((XEvent *) event);
                     return (TRUE);
                  }
               }
            }
         }
      }
      listPtr = listPtr -> nextFunct;
   }
   return (TRUE);
}



/*************************************<->*************************************
 *
 *  _XrAddFd (type, fd)
 *  INT32 type;
 *  int   fd;
 *
 *
 *   Description:
 *   -----------
 *     Add a file descriptor to the list of file descriptors to
 *     be selected upon.
 *
 *
 *   Inputs:
 *   ------
 *     type  =  Is set to a combination of XrREAD, XrWRITE, or XrEXCEPTION
 *              defines and denotes which fd tables and masks the fd
 *              is to be added to.
 *     fd    =  The file descriptor to be added.
 *
 * 
 *   Outputs:
 *   -------
 *     TRUE   =  Returned if all of the adds succeed.
 *
 *     FALSE  =  Returned if any of the adds fail.
 *
 *
 *   Procedures Called
 *   -----------------
 *     _XrAddFds()
 *
 *************************************<->***********************************/


static
_XrAddFd (type, fd)
INT32 type;
int   fd;

{
   if (type & XrREAD)
      if (_XrAddFds (fd, &readCount, readSaveMasks, readFds) == FALSE)
         return (FALSE);

   if (type & XrWRITE)
      if (_XrAddFds (fd, &writeCount, writeSaveMasks, writeFds) == FALSE)
         return (FALSE);

   if (type & XrEXCEPTION)
      if (_XrAddFds (fd, &exceptCount, exceptSaveMasks, exceptFds) == FALSE)
         return (FALSE);

   return (TRUE);
}




/*************************************<->*************************************
 *
 *  _XrRemoveFd (type, fd)
 *  INT32 type;
 *  int   fd;
 *
 *
 *   Description:
 *   -----------
 *     Remove a file descriptor from the list of file descriptors to
 *     be selected upon.
 *
 *
 *   Inputs:
 *   ------
 *     type  =  Is set to a combination of XrREAD, XrWRITE, or XrEXCEPTION
 *              defines and denotes which fd tables and masks the fd
 *              is to be removed from.
 *     fd    =  The file descriptor to be removed.
 *
 * 
 *   Outputs:
 *   -------
 *     TRUE   =  Returned if all of the removes succeed.
 *
 *     FALSE  =  Returned if any of the removes fail.
 *
 *
 *   Procedures Called
 *   -----------------
 *     _XrRemoveFds()
 *
 *************************************<->***********************************/


static
_XrRemoveFd (type, fd)
INT32 type;
int   fd;

{
   if (type & XrREAD)
      if (_XrRemoveFds (fd, &readCount, readSaveMasks, readFds) == FALSE)
         return (FALSE);

   if (type & XrWRITE)
      if (_XrRemoveFds (fd, &writeCount, writeSaveMasks, writeFds) == FALSE)
         return (FALSE);

   if (type & XrEXCEPTION)
      if (_XrRemoveFds (fd,&exceptCount, exceptSaveMasks, exceptFds) == FALSE)
         return (FALSE);

   return (TRUE);
}



/*************************************<->*************************************
 *
 *  _XrAddFds (fd, count, masks, fds)
 *  INT32   fd;
 *  INT32 * count;
 *  INT32   masks[];
 *  INT32   fds[];
 *
 *
 *   Description:
 *   -----------
 *     _XrAddFds adds a file descriptor to the table which contains
 *     file descriptors of its type, it also sets the appropriate 
 *     select mask to show that the file descriptor has been removed,
 *     and adjusts the global fdCount if needed.
 *
 *
 *   Inputs:
 *   ------
 *     fd     =  The file descriptor to be added.
 *     count  =  A pointer to an integer which contains the number 
 *               of file descriptors of that type, i.e. read, write,
 *               or exception.
 *     masks  =  The integer array which contains the select mask for
 *               the file descriptor to be added.
 *     fds    =  The array which contains the file descriptor to be
 *               added.
 *
 * 
 *   Outputs:
 *   -------
 *     TRUE  =  Is returned if the fd is successfully added.
 *
 *     FALSE  =  Is returned if the fd cannot be added.
 *
 *     fdCount  =  The static internal fdCount will be adjusted to
 *                 the input fd if fd is larger than fdCount.
 *
 *
 *   Procedures Called
 *   -----------------
 *     None.
 *
 *************************************<->***********************************/


static
_XrAddFds (fd, count, masks, fds)
INT32   fd;
INT32 * count;
INT32   masks[];
INT32   fds[];

{
   int i;

   for (i = 0; i < *count; i++)
      if (fd == fds[i])
         return (FALSE);

   fds[*count] = fd;
   *count = *count + 1;
   masks[fd >> 5] |= (1 << (fd & 31));

   if (fdCount <= fd)
      fdCount = fd + 1;

   return (TRUE);
}



/*************************************<->*************************************
 *
 *  _XrRemoveFds (fd, count, masks, fds)
 *  INT32   fd;
 *  INT32 * count;
 *  INT32   masks[];
 *  INT32   fds[];
 *
 *
 *   Description:
 *   -----------
 *     _XrRemoveFds removes a file descriptor from the table which
 *     contains it, sets the appropriate select mask to show that
 *     the file descriptor has been removed, and calls a routine
 *     to adjust the global fdCount if needed.
 *
 *
 *   Inputs:
 *   ------
 *     fd     =  The file descriptor to be removed.
 *     count  =  A pointer to an integer which contains the number 
 *               of file descriptors of that type, i.e. read, write,
 *               or exception.
 *     masks  =  The integer array which contains the select mask for
 *               the file descriptor to be removed. 
 *     fds    =  The array which contains the file descriptor to be
 *               removed.
 *
 * 
 *   Outputs:
 *   -------
 *     TRUE  =  Is returned if the fd is successfully removed.
 *
 *     FALSE  =  Is returned if the fd cannot be removed.
 *
 *
 *   Procedures Called
 *   -----------------
 *     _XrSetFdCount()
 *
 *************************************<->***********************************/


static
_XrRemoveFds (fd, count, masks, fds)
INT32   fd;
INT32 * count;
INT32   masks[];
INT32   fds[];

{
   int i;

   for (i = 0; i < *count; i++)
      if (fds[i] == fd)
      {
         fds[i] = 0;
         break;
      }

   if (i == *count)
      return (FALSE);

   for (; i < *count - 1; i++)
      fds[i] = fds[i+1];
   *count = *count - 1;

   masks[fd >> 5] &= ~(1 << (fd & 31));

   if (fd == fdCount)
      _XrSetFdCount ();

   return (TRUE);
}



/*************************************<->*************************************
 *
 *  _XrSetFdCount()
 *
 *
 *   Description:
 *   -----------
 *     Set the global fdCount to the maximum valued file descriptor.
 *
 *
 *   Inputs:
 *   ------
 *     None
 *
 * 
 *   Outputs:
 *   -------
 *     fdCount  =  This internal static is set to the maximum
 *                 valued file descriptor contained in the three
 *                 file descriptor tables.
 *
 *
 *   Procedures Called
 *   -----------------
 *     None
 *
 *************************************<->***********************************/


static
_XrSetFdCount ()
{
   register int i;

   fdCount = 0;

   for (i = 0; i < readCount; i++)
      if (fdCount <= readFds[i])
         fdCount = readFds[i] + 1;
   for (i = 0; i < writeCount; i++)
      if (fdCount <= writeFds[i])
         fdCount = writeFds[i] + 1;
   for (i = 0; i < exceptCount; i++)
      if (fdCount <= exceptFds[i])
         fdCount = exceptFds[i] + 1;
}
