home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / mitsch75.zip / scheme-7_5_17-src.zip / scheme-7.5.17 / src / swat / c / tk3.2-custom / tkEvent.c < prev    next >
C/C++ Source or Header  |  1995-08-02  |  50KB  |  1,676 lines

  1. /* 
  2.  * tkEvent.c --
  3.  *
  4.  *    This file provides basic event-managing facilities,
  5.  *    whereby procedure callbacks may be attached to
  6.  *    certain events.
  7.  *
  8.  * Copyright 1990-1992 Regents of the University of California.
  9.  * Permission to use, copy, modify, and distribute this
  10.  * software and its documentation for any purpose and without
  11.  * fee is hereby granted, provided that the above copyright
  12.  * notice appear in all copies.  The University of California
  13.  * makes no representations about the suitability of this
  14.  * software for any purpose.  It is provided "as is" without
  15.  * express or implied warranty.
  16.  */
  17.  
  18. /* ADDED tk_GetIntervalToNextEvent */
  19.  
  20. #ifndef lint
  21. static char rcsid[] = "$Header: /scheme/cvsroot/v7/src/swat/c/tk3.2-custom/tkEvent.c,v 1.1 1995/08/02 21:23:26 adams Exp $ SPRITE (Berkeley)";
  22. #endif
  23.  
  24. #include "tkConfig.h"
  25. #include "tkInt.h"
  26. #include <errno.h>
  27. #include <signal.h>
  28.  
  29. /*
  30.  * For each timer callback that's pending, there is one record
  31.  * of the following type, chained together in a list sorted by
  32.  * time (earliest event first).
  33.  */
  34.  
  35. typedef struct TimerEvent {
  36.     struct timeval time;    /* When timer is to fire. */
  37.     void (*proc)  _ANSI_ARGS_((ClientData clientData));
  38.                 /* Procedure to call. */
  39.     ClientData clientData;    /* Argument to pass to proc. */
  40.     Tk_TimerToken token;    /* Identifies event so it can be
  41.                  * deleted. */
  42.     struct TimerEvent *nextPtr;    /* Next event in queue, or NULL for
  43.                  * end of queue. */
  44. } TimerEvent;
  45.  
  46. static TimerEvent *timerQueue;    /* First event in queue. */
  47.  
  48. /*
  49.  * The information below is used to provide read, write, and
  50.  * exception masks to select during calls to Tk_DoOneEvent.
  51.  */
  52.  
  53. static int readCount;        /* Number of files for which we */
  54. static int writeCount;        /* care about each event type. */
  55. static int exceptCount;
  56. #define MASK_SIZE ((OPEN_MAX+(8*sizeof(int))-1)/(8*sizeof(int)))
  57. static int masks[3*MASK_SIZE];    /* Integer array containing official
  58.                  * copies of the three sets of
  59.                  * masks. */
  60. static int ready[3*MASK_SIZE];    /* Temporary copy of masks, passed
  61.                  * to select and modified by kernel
  62.                  * to indicate which files are
  63.                  * actually ready. */
  64. static int *readPtr;        /* Pointers to the portions of */
  65. static int *writePtr;        /* *readyPtr for reading, writing, */
  66. static int *exceptPtr;        /* and excepting.  Will be NULL if
  67.                  * corresponding count (e.g. readCount
  68.                  * is zero. */
  69. static int numFds = 0;        /* Number of valid bits in mask
  70.                  * arrays (this value is passed
  71.                  * to select). */
  72.  
  73. /*
  74.  * For each file registered in a call to Tk_CreateFileHandler,
  75.  * and for each display that's currently active, there is one
  76.  * record of the following type.  All of these records are
  77.  * chained together into a single list.
  78.  */
  79.  
  80. typedef struct FileEvent {
  81.     int fd;            /* Descriptor number for this file. */
  82.     int *readPtr;        /* Pointer to word in ready array
  83.                  * for this file's read mask bit. */
  84.     int *writePtr;        /* Same for write mask bit. */
  85.     int *exceptPtr;        /* Same for except mask bit. */
  86.     int mask;            /* Value to AND with mask word to
  87.                  * select just this file's bit. */
  88.     void (*proc)  _ANSI_ARGS_((ClientData clientData, int mask));
  89.                 /* Procedure to call.  NULL means
  90.                  * this is a display. */
  91.     ClientData clientData;    /* Argument to pass to proc.  For
  92.                  * displays, this is a (Display *). */
  93.     struct FileEvent *nextPtr;    /* Next in list of all files we
  94.                  * care about (NULL for end of
  95.                  * list). */
  96. } FileEvent;
  97.  
  98. static FileEvent *fileList;    /* List of all file events. */
  99.  
  100. /*
  101.  * There is one of the following structures for each of the
  102.  * handlers declared in a call to Tk_DoWhenIdle.  All of the
  103.  * currently-active handlers are linked together into a list.
  104.  */
  105.  
  106. typedef struct IdleHandler {
  107.     void (*proc)  _ANSI_ARGS_((ClientData clientData));
  108.                 /* Procedure to call. */
  109.     ClientData clientData;    /* Value to pass to proc. */
  110.     int generation;        /* Used to distinguish older handlers from
  111.                  * recently-created ones. */
  112.     struct IdleHandler *nextPtr;/* Next in list of active handlers. */
  113. } IdleHandler;
  114.  
  115. static IdleHandler *idleList = NULL;
  116.                 /* First in list of all idle handlers. */
  117. static IdleHandler *lastIdlePtr = NULL;
  118.                 /* Last in list (or NULL for empty list). */
  119. static int idleGeneration = 0;    /* Used to fill in the "generation" fields
  120.                  * of IdleHandler structures.  Increments
  121.                  * each time Tk_DoOneEvent starts calling
  122.                  * idle handlers, so that all old handlers
  123.                  * can be called without calling any of the
  124.                  * new ones created by old ones. */
  125.  
  126. /*
  127.  * There's a potential problem if a handler is deleted while it's
  128.  * current (i.e. its procedure is executing), since Tk_HandleEvent
  129.  * will need to read the handler's "nextPtr" field when the procedure
  130.  * returns.  To handle this problem, structures of the type below
  131.  * indicate the next handler to be processed for any (recursively
  132.  * nested) dispatches in progress.  The nextHandler fields get
  133.  * updated if the handlers pointed to are deleted.  Tk_HandleEvent
  134.  * also needs to know if the entire window gets deleted;  the winPtr
  135.  * field is set to zero if that particular window gets deleted.
  136.  */
  137.  
  138. typedef struct InProgress {
  139.     XEvent *eventPtr;         /* Event currently being handled. */
  140.     TkWindow *winPtr;         /* Window for event.  Gets set to None if
  141.                   * window is deleted while event is being
  142.                   * handled. */
  143.     TkEventHandler *nextHandler; /* Next handler in search. */
  144.     struct InProgress *nextPtr;     /* Next higher nested search. */
  145. } InProgress;
  146.  
  147. static InProgress *pendingPtr = NULL;
  148.                 /* Topmost search in progress, or
  149.                  * NULL if none. */
  150.  
  151. /*
  152.  * For each call to Tk_CreateGenericHandler, an instance of the following
  153.  * structure will be created.  All of the active handlers are linked into a
  154.  * list.
  155.  */
  156.  
  157. typedef struct GenericHandler {
  158.     Tk_GenericProc *proc;    /* Procedure to dispatch on all X events. */
  159.     ClientData clientData;    /* Client data to pass to procedure. */
  160.     int deleteFlag;        /* Flag to set when this handler is deleted. */
  161.     struct GenericHandler *nextPtr;
  162.                 /* Next handler in list of all generic
  163.                  * handlers, or NULL for end of list. */
  164. } GenericHandler;
  165.  
  166. static GenericHandler *genericList = NULL;
  167.                 /* First handler in the list, or NULL. */
  168. static GenericHandler *lastGenericPtr = NULL;
  169.                 /* Last handler in list. */
  170.  
  171. /*
  172.  * There's a potential problem if Tk_HandleEvent is entered recursively.
  173.  * A handler cannot be deleted physically until we have returned from
  174.  * calling it.  Otherwise, we're looking at unallocated memory in advancing to
  175.  * its `next' entry.  We deal with the problem by using the `delete flag' and
  176.  * deleting handlers only when it's known that there's no handler active.
  177.  *
  178.  * The following variable has a non-zero value when a handler is active.
  179.  */
  180.  
  181. static int genericHandlersActive = 0;
  182.  
  183. /*
  184.  * Array of event masks corresponding to each X event:
  185.  */
  186.  
  187. static unsigned long eventMasks[] = {
  188.     0,
  189.     0,
  190.     KeyPressMask,            /* KeyPress */
  191.     KeyReleaseMask,            /* KeyRelease */
  192.     ButtonPressMask,            /* ButtonPress */
  193.     ButtonReleaseMask,            /* ButtonRelease */
  194.     PointerMotionMask|PointerMotionHintMask|ButtonMotionMask
  195.         |Button1MotionMask|Button2MotionMask|Button3MotionMask
  196.         |Button4MotionMask|Button5MotionMask,
  197.                     /* MotionNotify */
  198.     EnterWindowMask,            /* EnterNotify */
  199.     LeaveWindowMask,            /* LeaveNotify */
  200.     FocusChangeMask,            /* FocusIn */
  201.     FocusChangeMask,            /* FocusOut */
  202.     KeymapStateMask,            /* KeymapNotify */
  203.     ExposureMask,            /* Expose */
  204.     ExposureMask,            /* GraphicsExpose */
  205.     ExposureMask,            /* NoExpose */
  206.     VisibilityChangeMask,        /* VisibilityNotify */
  207.     SubstructureNotifyMask,        /* CreateNotify */
  208.     StructureNotifyMask,        /* DestroyNotify */
  209.     StructureNotifyMask,        /* UnmapNotify */
  210.     StructureNotifyMask,        /* MapNotify */
  211.     SubstructureRedirectMask,        /* MapRequest */
  212.     StructureNotifyMask,        /* ReparentNotify */
  213.     StructureNotifyMask,        /* ConfigureNotify */
  214.     SubstructureRedirectMask,        /* ConfigureRequest */
  215.     StructureNotifyMask,        /* GravityNotify */
  216.     ResizeRedirectMask,            /* ResizeRequest */
  217.     StructureNotifyMask,        /* CirculateNotify */
  218.     SubstructureRedirectMask,        /* CirculateRequest */
  219.     PropertyChangeMask,            /* PropertyNotify */
  220.     0,                    /* SelectionClear */
  221.     0,                    /* SelectionRequest */
  222.     0,                    /* SelectionNotify */
  223.     ColormapChangeMask,            /* ColormapNotify */
  224.     0,                    /* ClientMessage */
  225.     0,                    /* Mapping Notify */
  226. };
  227.  
  228. /*
  229.  * If someone has called Tk_RestrictEvents, the information below
  230.  * keeps track of it.
  231.  */
  232.  
  233. static Bool (*restrictProc)  _ANSI_ARGS_((Display *display, XEvent *eventPtr,
  234.     char *arg));        /* Procedure to call.  NULL means no
  235.                  * restrictProc is currently in effect. */
  236. static char *restrictArg;    /* Argument to pass to restrictProc. */
  237.  
  238. /*
  239.  * The following array keeps track of the last TK_NEVENTS X events, for
  240.  * memory dump analysis.  The tracing is only done if tkEventDebug is set
  241.  * to 1.
  242.  */
  243.  
  244. #define TK_NEVENTS 32
  245. static XEvent eventTrace[TK_NEVENTS];
  246. static int traceIndex = 0;
  247. int tkEventDebug = 0;
  248.  
  249. long tk_GetIntervalToNextEvent()
  250. /* Returns next time event in milliseconds (from now) */
  251. { struct timeval curTime, timeout, *timeoutPtr;
  252.  
  253.   if (idleList != NULL) return 0; /* Ready NOW */
  254.   if (timerQueue == NULL) return -1;
  255.   (void) gettimeofday(&curTime, (struct timezone *) NULL);
  256.   if ((timerQueue->time.tv_sec < curTime.tv_sec)
  257.       || ((timerQueue->time.tv_sec == curTime.tv_sec)
  258.       &&  (timerQueue->time.tv_usec < curTime.tv_usec)))
  259.     return 0;            /* Already expired, so do it NOW */
  260.   return (((curTime.tv_sec - timerQueue->time.tv_sec) * 1000) +
  261.       (((curTime.tv_usec - timerQueue->time.tv_usec) + 500) /
  262.        1000));
  263. }
  264.  
  265. /*
  266.  *--------------------------------------------------------------
  267.  *
  268.  * Tk_CreateEventHandler --
  269.  *
  270.  *    Arrange for a given procedure to be invoked whenever
  271.  *    events from a given class occur in a given window.
  272.  *
  273.  * Results:
  274.  *    None.
  275.  *
  276.  * Side effects:
  277.  *    From now on, whenever an event of the type given by
  278.  *    mask occurs for token and is processed by Tk_HandleEvent,
  279.  *    proc will be called.  See the manual entry for details
  280.  *    of the calling sequence and return value for proc.
  281.  *
  282.  *--------------------------------------------------------------
  283.  */
  284.  
  285. void
  286. Tk_CreateEventHandler(token, mask, proc, clientData)
  287.     Tk_Window token;        /* Token for window in which to
  288.                  * create handler. */
  289.     unsigned long mask;        /* Events for which proc should
  290.                  * be called. */
  291.     Tk_EventProc *proc;        /* Procedure to call for each
  292.                  * selected event */
  293.     ClientData clientData;    /* Arbitrary data to pass to proc. */
  294. {
  295.     register TkEventHandler *handlerPtr;
  296.     register TkWindow *winPtr = (TkWindow *) token;
  297.     int found;
  298.  
  299.     /*
  300.      * Skim through the list of existing handlers to (a) compute the
  301.      * overall event mask for the window (so we can pass this new
  302.      * value to the X system) and (b) see if there's already a handler
  303.      * declared with the same callback and clientData (if so, just
  304.      * change the mask).  If no existing handler matches, then create
  305.      * a new handler.
  306.      */
  307.  
  308.     found = 0;
  309.     if (winPtr->handlerList == NULL) {
  310.     handlerPtr = (TkEventHandler *) ckalloc(
  311.         (unsigned) sizeof(TkEventHandler));
  312.     winPtr->handlerList = handlerPtr;
  313.     goto initHandler;
  314.     } else {
  315.     for (handlerPtr = winPtr->handlerList; ;
  316.         handlerPtr = handlerPtr->nextPtr) {
  317.         if ((handlerPtr->proc == proc)
  318.             && (handlerPtr->clientData == clientData)) {
  319.         handlerPtr->mask = mask;
  320.         found = 1;
  321.         }
  322.         if (handlerPtr->nextPtr == NULL) {
  323.         break;
  324.         }
  325.     }
  326.     }
  327.  
  328.     /*
  329.      * Create a new handler if no matching old handler was found.
  330.      */
  331.  
  332.     if (!found) {
  333.     handlerPtr->nextPtr = (TkEventHandler *)
  334.         ckalloc(sizeof(TkEventHandler));
  335.     handlerPtr = handlerPtr->nextPtr;
  336.     initHandler:
  337.     handlerPtr->mask = mask;
  338.     handlerPtr->proc = proc;
  339.     handlerPtr->clientData = clientData;
  340.     handlerPtr->nextPtr = NULL;
  341.     }
  342.  
  343.     /*
  344.      * No need to call XSelectInput:  Tk always selects on all events
  345.      * for all windows (needed to support bindings on classes and "all").
  346.      */
  347. }
  348.  
  349. /*
  350.  *--------------------------------------------------------------
  351.  *
  352.  * Tk_DeleteEventHandler --
  353.  *
  354.  *    Delete a previously-created handler.
  355.  *
  356.  * Results:
  357.  *    None.
  358.  *
  359.  * Side effects:
  360.  *    If there existed a handler as described by the
  361.  *    parameters, the handler is deleted so that proc
  362.  *    will not be invoked again.
  363.  *
  364.  *--------------------------------------------------------------
  365.  */
  366.  
  367. void
  368. Tk_DeleteEventHandler(token, mask, proc, clientData)
  369.     Tk_Window token;        /* Same as corresponding arguments passed */
  370.     unsigned long mask;        /* previously to Tk_CreateEventHandler. */
  371.     Tk_EventProc *proc;
  372.     ClientData clientData;
  373. {
  374.     register TkEventHandler *handlerPtr;
  375.     register InProgress *ipPtr;
  376.     TkEventHandler *prevPtr;
  377.     register TkWindow *winPtr = (TkWindow *) token;
  378.  
  379.     /*
  380.      * Find the event handler to be deleted, or return
  381.      * immediately if it doesn't exist.
  382.      */
  383.  
  384.     for (handlerPtr = winPtr->handlerList, prevPtr = NULL; ;
  385.         prevPtr = handlerPtr, handlerPtr = handlerPtr->nextPtr) {
  386.     if (handlerPtr == NULL) {
  387.         return;
  388.     }
  389.     if ((handlerPtr->mask == mask) && (handlerPtr->proc == proc)
  390.         && (handlerPtr->clientData == clientData)) {
  391.         break;
  392.     }
  393.     }
  394.  
  395.     /*
  396.      * If Tk_HandleEvent is about to process this handler, tell it to
  397.      * process the next one instead.
  398.      */
  399.  
  400.     for (ipPtr = pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) {
  401.     if (ipPtr->nextHandler == handlerPtr) {
  402.         ipPtr->nextHandler = handlerPtr->nextPtr;
  403.     }
  404.     }
  405.  
  406.     /*
  407.      * Free resources associated with the handler.
  408.      */
  409.  
  410.     if (prevPtr == NULL) {
  411.     winPtr->handlerList = handlerPtr->nextPtr;
  412.     } else {
  413.     prevPtr->nextPtr = handlerPtr->nextPtr;
  414.     }
  415.     ckfree((char *) handlerPtr);
  416.  
  417.  
  418.     /*
  419.      * No need to call XSelectInput:  Tk always selects on all events
  420.      * for all windows (needed to support bindings on classes and "all").
  421.      */
  422. }
  423.  
  424. /*--------------------------------------------------------------
  425.  *
  426.  * Tk_CreateGenericHandler --
  427.  *
  428.  *    Register a procedure to be called on each X event, regardless
  429.  *    of display or window.  Generic handlers are useful for capturing
  430.  *    events that aren't associated with windows, or events for windows
  431.  *    not managed by Tk.
  432.  *
  433.  * Results:
  434.  *    None.
  435.  *
  436.  * Side Effects:
  437.  *    From now on, whenever an X event is given to Tk_HandleEvent,
  438.  *    invoke proc, giving it clientData and the event as arguments.
  439.  *
  440.  *--------------------------------------------------------------
  441.  */
  442.  
  443. void
  444. Tk_CreateGenericHandler(proc, clientData)
  445.      Tk_GenericProc *proc;    /* Procedure to call on every event. */
  446.      ClientData clientData;    /* One-word value to pass to proc. */
  447. {
  448.     GenericHandler *handlerPtr;
  449.     
  450.     handlerPtr = (GenericHandler *) ckalloc (sizeof (GenericHandler));
  451.     
  452.     handlerPtr->proc = proc;
  453.     handlerPtr->clientData = clientData;
  454.     handlerPtr->deleteFlag = 0;
  455.     handlerPtr->nextPtr = NULL;
  456.     if (genericList == NULL) {
  457.     genericList = handlerPtr;
  458.     } else {
  459.     lastGenericPtr->nextPtr = handlerPtr;
  460.     }
  461.     lastGenericPtr = handlerPtr;
  462. }
  463.  
  464. /*
  465.  *--------------------------------------------------------------
  466.  *
  467.  * Tk_DeleteGenericHandler --
  468.  *
  469.  *    Delete a previously-created generic handler.
  470.  *
  471.  * Results:
  472.  *    None.
  473.  *
  474.  * Side Effects:
  475.  *    If there existed a handler as described by the parameters,
  476.  *    that handler is logically deleted so that proc will not be
  477.  *    invoked again.  The physical deletion happens in the event
  478.  *    loop in Tk_HandleEvent.
  479.  *
  480.  *--------------------------------------------------------------
  481.  */
  482.  
  483. void
  484. Tk_DeleteGenericHandler(proc, clientData)
  485.      Tk_GenericProc *proc;
  486.      ClientData clientData;
  487. {
  488.     GenericHandler * handler;
  489.     
  490.     for (handler = genericList; handler; handler = handler->nextPtr) {
  491.     if ((handler->proc == proc) && (handler->clientData == clientData)) {
  492.         handler->deleteFlag = 1;
  493.     }
  494.     }
  495. }
  496.  
  497. /*
  498.  *--------------------------------------------------------------
  499.  *
  500.  * Tk_HandleEvent --
  501.  *
  502.  *    Given an event, invoke all the handlers that have
  503.  *    been registered for the event.
  504.  *
  505.  * Results:
  506.  *    None.
  507.  *
  508.  * Side effects:
  509.  *    Depends on the handlers.
  510.  *
  511.  *--------------------------------------------------------------
  512.  */
  513.  
  514. void
  515. Tk_HandleEvent(eventPtr)
  516.     XEvent *eventPtr;        /* Event to dispatch. */
  517. {
  518.     register TkEventHandler *handlerPtr;
  519.     register GenericHandler *genericPtr;
  520.     register GenericHandler *genPrevPtr;
  521.     TkWindow *winPtr;
  522.     register unsigned long mask;
  523.     InProgress ip;
  524.     Window handlerWindow;
  525.  
  526.     /*
  527.      * First off, look for a special trigger event left around by the
  528.      * grab module.  If it's found, call the grab module and discard
  529.      * the event.
  530.      */
  531.  
  532.     if ((eventPtr->xany.type == -1) && (eventPtr->xany.window == None)) {
  533.     TkGrabTriggerProc(eventPtr);
  534.     return;
  535.     }
  536.  
  537.     /* 
  538.      * Next, invoke all the generic event handlers (those that are
  539.      * invoked for all events).  If a generic event handler reports that
  540.      * an event is fully processed, go no further.
  541.      */
  542.  
  543.     for (genPrevPtr = NULL, genericPtr = genericList;  genericPtr != NULL; ) {
  544.     if (genericPtr->deleteFlag) {
  545.         if (!genericHandlersActive) {
  546.         GenericHandler *tmpPtr;
  547.  
  548.         /*
  549.          * This handler needs to be deleted and there are no
  550.          * calls pending through the handler, so now is a safe
  551.          * time to delete it.
  552.          */
  553.  
  554.         tmpPtr = genericPtr->nextPtr;
  555.         if (genPrevPtr == NULL) {
  556.             genericList = tmpPtr;
  557.         } else {
  558.             genPrevPtr->nextPtr = tmpPtr;
  559.         }
  560.         (void) ckfree((char *) genericPtr);
  561.         genericPtr = tmpPtr;
  562.         continue;
  563.         }
  564.     } else {
  565.         int done;
  566.  
  567.         genericHandlersActive++;
  568.         done = (*genericPtr->proc)(genericPtr->clientData, eventPtr);
  569.         genericHandlersActive--;
  570.         if (done) {
  571.         return;
  572.         }
  573.     }
  574.     genPrevPtr = genericPtr;
  575.     genericPtr = genPrevPtr->nextPtr;
  576.     }
  577.  
  578.     /*
  579.      * If the event is a MappingNotify event, find its display and
  580.      * refresh the keyboard mapping information for the display.
  581.      * After that there's nothing else to do with the event, so just
  582.      * quit.
  583.      */
  584.  
  585.     if (eventPtr->type == MappingNotify) {
  586.     TkDisplay *dispPtr;
  587.  
  588.     for (dispPtr = tkDisplayList; dispPtr != NULL;
  589.         dispPtr = dispPtr->nextPtr) {
  590.         if (dispPtr->display != eventPtr->xmapping.display) {
  591.         continue;
  592.         }
  593.         XRefreshKeyboardMapping(&eventPtr->xmapping);
  594.         dispPtr->bindInfoStale = 1;
  595.         break;
  596.     }
  597.     return;
  598.     }
  599.  
  600.     /*
  601.      * Events selected by StructureNotify look the same as those
  602.      * selected by SubstructureNotify;  the only difference is
  603.      * whether the "event" and "window" fields are the same.
  604.      * Check it out and convert StructureNotify to
  605.      * SubstructureNotify if necessary.
  606.      */
  607.  
  608.     handlerWindow = eventPtr->xany.window;
  609.     mask = eventMasks[eventPtr->xany.type];
  610.     if (mask == StructureNotifyMask) {
  611.     if (eventPtr->xmap.event != eventPtr->xmap.window) {
  612.         mask = SubstructureNotifyMask;
  613.         handlerWindow = eventPtr->xmap.event;
  614.     }
  615.     }
  616.     if (XFindContext(eventPtr->xany.display, handlerWindow,
  617.         tkWindowContext, (caddr_t *) &winPtr) != 0) {
  618.  
  619.     /*
  620.      * There isn't a TkWindow structure for this window.
  621.      * However, if the event is a PropertyNotify event then call
  622.      * the selection manager (it deals beneath-the-table with
  623.      * certain properties).
  624.      */
  625.  
  626.     if (eventPtr->type == PropertyNotify) {
  627.         TkSelPropProc(eventPtr);
  628.     }
  629.     return;
  630.     }
  631.  
  632.     /*
  633.      * Call focus-related code to look at FocusIn, FocusOut, Enter,
  634.      * and Leave events;  depending on its return value, ignore the
  635.      * event.
  636.      */
  637.  
  638.     if ((mask & (FocusChangeMask|EnterWindowMask|LeaveWindowMask))
  639.         && !TkFocusFilterEvent(winPtr, eventPtr)) {
  640.     return;
  641.     }
  642.  
  643.     /*
  644.      * Redirect KeyPress and KeyRelease events to the focus window,
  645.      * or ignore them entirely if there is no focus window.  Map the
  646.      * x and y coordinates to make sense in the context of the focus
  647.      * window, if possible (make both -1 if the map-from and map-to
  648.      * windows don't share the same screen).
  649.      */
  650.  
  651.     if (mask & (KeyPressMask|KeyReleaseMask)) {
  652.     TkWindow *focusPtr;
  653.     int winX, winY, focusX, focusY;
  654.  
  655.     winPtr->dispPtr->lastEventTime = eventPtr->xkey.time;
  656.     if (winPtr->mainPtr->focusPtr == NULL) {
  657.         return;
  658.     }
  659.     focusPtr = winPtr->mainPtr->focusPtr;
  660.     if ((focusPtr->display != winPtr->display)
  661.         || (focusPtr->screenNum != winPtr->screenNum)) {
  662.         eventPtr->xkey.x = -1;
  663.         eventPtr->xkey.y = -1;
  664.     } else {
  665.         Tk_GetRootCoords((Tk_Window) winPtr, &winX, &winY);
  666.         Tk_GetRootCoords((Tk_Window) focusPtr, &focusX, &focusY);
  667.         eventPtr->xkey.x -= focusX - winX;
  668.         eventPtr->xkey.y -= focusY - winY;
  669.     }
  670.     eventPtr->xkey.window = focusPtr->window;
  671.     winPtr = focusPtr;
  672.     }
  673.  
  674.     /*
  675.      * Call a grab-related procedure to do special processing on
  676.      * pointer events.
  677.      */
  678.  
  679.     if (mask & (ButtonPressMask|ButtonReleaseMask|PointerMotionMask
  680.         |EnterWindowMask|LeaveWindowMask)) {
  681.     if (mask & (ButtonPressMask|ButtonReleaseMask)) {
  682.         winPtr->dispPtr->lastEventTime = eventPtr->xbutton.time;
  683.     } else if (mask & PointerMotionMask) {
  684.         winPtr->dispPtr->lastEventTime = eventPtr->xmotion.time;
  685.     } else {
  686.         winPtr->dispPtr->lastEventTime = eventPtr->xcrossing.time;
  687.     }
  688.     if (TkPointerEvent(eventPtr, winPtr) == 0) {
  689.         return;
  690.     }
  691.     }
  692.  
  693.     /*
  694.      * For events where it hasn't already been done, update the current
  695.      * time in the display.
  696.      */
  697.  
  698.     if (eventPtr->type == PropertyNotify) {
  699.     winPtr->dispPtr->lastEventTime = eventPtr->xproperty.time;
  700.     }
  701.  
  702.     /*
  703.      * There's a potential interaction here with Tk_DeleteEventHandler.
  704.      * Read the documentation for pendingPtr.
  705.      */
  706.  
  707.     ip.eventPtr = eventPtr;
  708.     ip.winPtr = winPtr;
  709.     ip.nextHandler = NULL;
  710.     ip.nextPtr = pendingPtr;
  711.     pendingPtr = &ip;
  712.     if (mask == 0) {
  713.     if ((eventPtr->type == SelectionClear)
  714.         || (eventPtr->type == SelectionRequest)
  715.         || (eventPtr->type == SelectionNotify)) {
  716.         TkSelEventProc((Tk_Window) winPtr, eventPtr);
  717.     } else if ((eventPtr->type == ClientMessage)
  718.         && (eventPtr->xclient.message_type ==
  719.             Tk_InternAtom((Tk_Window) winPtr, "WM_PROTOCOLS"))) {
  720.         TkWmProtocolEventProc(winPtr, eventPtr);
  721.     }
  722.     } else {
  723.     for (handlerPtr = winPtr->handlerList; handlerPtr != NULL; ) {
  724.         if ((handlerPtr->mask & mask) != 0) {
  725.         ip.nextHandler = handlerPtr->nextPtr;
  726.         (*(handlerPtr->proc))(handlerPtr->clientData, eventPtr);
  727.         handlerPtr = ip.nextHandler;
  728.         } else {
  729.         handlerPtr = handlerPtr->nextPtr;
  730.         }
  731.     }
  732.  
  733.     /*
  734.      * Pass the event to the "bind" command mechanism.  But, don't
  735.      * do this for SubstructureNotify events.  The "bind" command
  736.      * doesn't support them anyway, and it's easier to filter out
  737.      * these events here than in the lower-level procedures.
  738.      */
  739.  
  740.     if ((ip.winPtr != None) && (mask != SubstructureNotifyMask)) {
  741.         TkBindEventProc(winPtr, eventPtr);
  742.     }
  743.     }
  744.     pendingPtr = ip.nextPtr;
  745. }
  746.  
  747. /*
  748.  *--------------------------------------------------------------
  749.  *
  750.  * Tk_CreateFileHandler --
  751.  *
  752.  *    Arrange for a given procedure to be invoked whenever
  753.  *    a given file becomes readable or writable.
  754.  *
  755.  * Results:
  756.  *    None.
  757.  *
  758.  * Side effects:
  759.  *    From now on, whenever the I/O channel given by fd becomes
  760.  *    ready in the way indicated by mask, proc will be invoked.
  761.  *    See the manual entry for details on the calling sequence
  762.  *    to proc.  If fd is already registered then the old mask
  763.  *    and proc and clientData values will be replaced with
  764.  *    new ones.
  765.  *
  766.  *--------------------------------------------------------------
  767.  */
  768.  
  769. void
  770. Tk_CreateFileHandler(fd, mask, proc, clientData)
  771.     int fd;            /* Integer identifier for stream. */
  772.     int mask;            /* OR'ed combination of TK_READABLE,
  773.                  * TK_WRITABLE, and TK_EXCEPTION:
  774.                  * indicates conditions under which
  775.                  * proc should be called. */
  776.     Tk_FileProc *proc;        /* Procedure to call for each
  777.                  * selected event.  NULL means that
  778.                  * this is a display, and that
  779.                  * clientData is the (Display *)
  780.                  * for it, and that events should
  781.                  * be handled automatically. */
  782.     ClientData clientData;    /* Arbitrary data to pass to proc. */
  783. {
  784.     register FileEvent *filePtr;
  785.     int index;
  786.  
  787.     if (fd >= OPEN_MAX) {
  788.     panic("Tk_CreatefileHandler can't handle file id %d", fd);
  789.     }
  790.  
  791.     /*
  792.      * Make sure the file isn't already registered.  Create a
  793.      * new record in the normal case where there's no existing
  794.      * record.
  795.      */
  796.  
  797.     for (filePtr = fileList; filePtr != NULL;
  798.         filePtr = filePtr->nextPtr) {
  799.     if (filePtr->fd == fd) {
  800.         break;
  801.     }
  802.     }
  803.     index = fd/(8*sizeof(int));
  804.     if (filePtr == NULL) {
  805.     filePtr = (FileEvent *) ckalloc(sizeof(FileEvent));
  806.     filePtr->fd = fd;
  807.     filePtr->readPtr = &ready[index];
  808.     filePtr->writePtr = &ready[index+MASK_SIZE];
  809.     filePtr->exceptPtr = &ready[index+2*MASK_SIZE];
  810.     filePtr->mask = 1 << (fd%(8*sizeof(int)));
  811.     filePtr->nextPtr = fileList;
  812.     fileList = filePtr;
  813.     } else {
  814.     if (masks[index] & filePtr->mask) {
  815.         readCount--;
  816.         *filePtr->readPtr &= ~filePtr->mask;
  817.         masks[index] &= ~filePtr->mask;
  818.     }
  819.     if (masks[index+MASK_SIZE] & filePtr->mask) {
  820.         writeCount--;
  821.         *filePtr->writePtr &= ~filePtr->mask;
  822.         masks[index+MASK_SIZE] &= ~filePtr->mask;
  823.     }
  824.     if (masks[index+2*MASK_SIZE] & filePtr->mask) {
  825.         exceptCount--;
  826.         *filePtr->exceptPtr &= ~filePtr->mask;
  827.         masks[index+2*MASK_SIZE] &= ~filePtr->mask;
  828.     }
  829.     }
  830.  
  831.     /*
  832.      * The remainder of the initialization below is done
  833.      * regardless of whether or not this is a new record
  834.      * or a modification of an old one.
  835.      */
  836.  
  837.     if (mask & TK_READABLE) {
  838.     masks[index] |= filePtr->mask;
  839.     readCount++;
  840.     }
  841.     readPtr = (readCount == 0) ? (int *) NULL : &ready[0];
  842.  
  843.     if (mask & TK_WRITABLE) {
  844.     masks[index+MASK_SIZE] |= filePtr->mask;
  845.     writeCount++;
  846.     }
  847.     writePtr = (writeCount == 0) ? (int *) NULL : &ready[MASK_SIZE];
  848.  
  849.     if (mask & TK_EXCEPTION) {
  850.     masks[index+2*MASK_SIZE] |= filePtr->mask;
  851.     exceptCount++;
  852.     }
  853.     exceptPtr = (exceptCount == 0) ? (int *) NULL : &ready[2*MASK_SIZE];
  854.  
  855.     filePtr->proc = proc;
  856.     filePtr->clientData = clientData;
  857.  
  858.     if (numFds <= fd) {
  859.     numFds = fd+1;
  860.     }
  861. }
  862.  
  863. /*
  864.  *--------------------------------------------------------------
  865.  *
  866.  * Tk_DeleteFileHandler --
  867.  *
  868.  *    Cancel a previously-arranged callback arrangement for
  869.  *    a file.
  870.  *
  871.  * Results:
  872.  *    None.
  873.  *
  874.  * Side effects:
  875.  *    If a callback was previously registered on fd, remove it.
  876.  *
  877.  *--------------------------------------------------------------
  878.  */
  879.  
  880. void
  881. Tk_DeleteFileHandler(fd)
  882.     int fd;            /* Stream id for which to remove
  883.                  * callback procedure. */
  884. {
  885.     register FileEvent *filePtr;
  886.     FileEvent *prevPtr;
  887.     int index;
  888.  
  889.     /*
  890.      * Find the entry for the given file (and return if there
  891.      * isn't one).
  892.      */
  893.  
  894.     for (prevPtr = NULL, filePtr = fileList; ;
  895.         prevPtr = filePtr, filePtr = filePtr->nextPtr) {
  896.     if (filePtr == NULL) {
  897.         return;
  898.     }
  899.     if (filePtr->fd == fd) {
  900.         break;
  901.     }
  902.     }
  903.  
  904.     /*
  905.      * Clean up information in the callback record.
  906.      */
  907.  
  908.     index = filePtr->fd/(8*sizeof(int));
  909.     if (masks[index] & filePtr->mask) {
  910.     readCount--;
  911.     *filePtr->readPtr &= ~filePtr->mask;
  912.     masks[index] &= ~filePtr->mask;
  913.     }
  914.     if (masks[index+MASK_SIZE] & filePtr->mask) {
  915.     writeCount--;
  916.     *filePtr->writePtr &= ~filePtr->mask;
  917.     masks[index+MASK_SIZE] &= ~filePtr->mask;
  918.     }
  919.     if (masks[index+2*MASK_SIZE] & filePtr->mask) {
  920.     exceptCount--;
  921.     *filePtr->exceptPtr &= ~filePtr->mask;
  922.     masks[index+2*MASK_SIZE] &= ~filePtr->mask;
  923.     }
  924.     if (prevPtr == NULL) {
  925.     fileList = filePtr->nextPtr;
  926.     } else {
  927.     prevPtr->nextPtr = filePtr->nextPtr;
  928.     }
  929.     ckfree((char *) filePtr);
  930.  
  931.     /*
  932.      * Recompute numFds.
  933.      */
  934.  
  935.     numFds = 0;
  936.     for (filePtr = fileList; filePtr != NULL;
  937.         filePtr = filePtr->nextPtr) {
  938.     if (numFds <= filePtr->fd) {
  939.         numFds = filePtr->fd+1;
  940.     }
  941.     }
  942. }
  943.  
  944. /*
  945.  *--------------------------------------------------------------
  946.  *
  947.  * Tk_CreateTimerHandler --
  948.  *
  949.  *    Arrange for a given procedure to be invoked at a particular
  950.  *    time in the future.
  951.  *
  952.  * Results:
  953.  *    The return value is a token for the timer event, which
  954.  *    may be used to delete the event before it fires.
  955.  *
  956.  * Side effects:
  957.  *    When milliseconds have elapsed, proc will be invoked
  958.  *    exactly once.
  959.  *
  960.  *--------------------------------------------------------------
  961.  */
  962.  
  963. Tk_TimerToken
  964. Tk_CreateTimerHandler(milliseconds, proc, clientData)
  965.     int milliseconds;        /* How many milliseconds to wait
  966.                  * before invoking proc. */
  967.     Tk_TimerProc *proc;        /* Procedure to invoke. */
  968.     ClientData clientData;    /* Arbitrary data to pass to proc. */
  969. {
  970.     register TimerEvent *timerPtr, *tPtr2, *prevPtr;
  971.     static int id = 0;
  972.  
  973.     timerPtr = (TimerEvent *) ckalloc(sizeof(TimerEvent));
  974.  
  975.     /*
  976.      * Compute when the event should fire.
  977.      */
  978.  
  979.     (void) gettimeofday(&timerPtr->time, (struct timezone *) NULL);
  980.     timerPtr->time.tv_sec += milliseconds/1000;
  981.     timerPtr->time.tv_usec += (milliseconds%1000)*1000;
  982.     if (timerPtr->time.tv_usec > 1000000) {
  983.     timerPtr->time.tv_usec -= 1000000;
  984.     timerPtr->time.tv_sec += 1;
  985.     }
  986.  
  987.     /*
  988.      * Fill in other fields for the event.
  989.      */
  990.  
  991.     timerPtr->proc = proc;
  992.     timerPtr->clientData = clientData;
  993.     id++;
  994.     timerPtr->token = (Tk_TimerToken) id;
  995.  
  996.     /*
  997.      * Add the event to the queue in the correct position
  998.      * (ordered by event firing time).
  999.      */
  1000.  
  1001.     for (tPtr2 = timerQueue, prevPtr = NULL; tPtr2 != NULL;
  1002.         prevPtr = tPtr2, tPtr2 = tPtr2->nextPtr) {
  1003.     if ((tPtr2->time.tv_sec > timerPtr->time.tv_sec)
  1004.         || ((tPtr2->time.tv_sec == timerPtr->time.tv_sec)
  1005.         && (tPtr2->time.tv_usec > timerPtr->time.tv_usec))) {
  1006.         break;
  1007.     }
  1008.     }
  1009.     if (prevPtr == NULL) {
  1010.     timerPtr->nextPtr = timerQueue;
  1011.     timerQueue = timerPtr;
  1012.     } else {
  1013.     timerPtr->nextPtr = prevPtr->nextPtr;
  1014.     prevPtr->nextPtr = timerPtr;
  1015.     }
  1016.     return timerPtr->token;
  1017. }
  1018.  
  1019. /*
  1020.  *--------------------------------------------------------------
  1021.  *
  1022.  * Tk_DeleteTimerHandler --
  1023.  *
  1024.  *    Delete a previously-registered timer handler.
  1025.  *
  1026.  * Results:
  1027.  *    None.
  1028.  *
  1029.  * Side effects:
  1030.  *    Destroy the timer callback identified by TimerToken,
  1031.  *    so that its associated procedure will not be called.
  1032.  *    If the callback has already fired, or if the given
  1033.  *    token doesn't exist, then nothing happens.
  1034.  *
  1035.  *--------------------------------------------------------------
  1036.  */
  1037.  
  1038. void
  1039. Tk_DeleteTimerHandler(token)
  1040.     Tk_TimerToken token;    /* Result previously returned by
  1041.                  * Tk_DeleteTimerHandler. */
  1042. {
  1043.     register TimerEvent *timerPtr, *prevPtr;
  1044.  
  1045.     for (timerPtr = timerQueue, prevPtr = NULL; timerPtr != NULL;
  1046.         prevPtr = timerPtr, timerPtr = timerPtr->nextPtr) {
  1047.     if (timerPtr->token != token) {
  1048.         continue;
  1049.     }
  1050.     if (prevPtr == NULL) {
  1051.         timerQueue = timerPtr->nextPtr;
  1052.     } else {
  1053.         prevPtr->nextPtr = timerPtr->nextPtr;
  1054.     }
  1055.     ckfree((char *) timerPtr);
  1056.     return;
  1057.     }
  1058. }
  1059.  
  1060. /*
  1061.  *--------------------------------------------------------------
  1062.  *
  1063.  * Tk_DoWhenIdle --
  1064.  *
  1065.  *    Arrange for proc to be invoked the next time the
  1066.  *    system is idle (i.e., just before the next time
  1067.  *    that Tk_DoOneEvent would have to wait for something
  1068.  *    to happen).
  1069.  *
  1070.  * Results:
  1071.  *    None.
  1072.  *
  1073.  * Side effects:
  1074.  *    Proc will eventually be called, with clientData
  1075.  *    as argument.  See the manual entry for details.
  1076.  *
  1077.  *--------------------------------------------------------------
  1078.  */
  1079.  
  1080. void
  1081. Tk_DoWhenIdle(proc, clientData)
  1082.     Tk_IdleProc *proc;        /* Procedure to invoke. */
  1083.     ClientData clientData;    /* Arbitrary value to pass to proc. */
  1084. {
  1085.     register IdleHandler *idlePtr;
  1086.  
  1087.     idlePtr = (IdleHandler *) ckalloc(sizeof(IdleHandler));
  1088.     idlePtr->proc = proc;
  1089.     idlePtr->clientData = clientData;
  1090.     idlePtr->generation = idleGeneration;
  1091.     idlePtr->nextPtr = NULL;
  1092.     if (lastIdlePtr == NULL) {
  1093.     idleList = idlePtr;
  1094.     } else {
  1095.     lastIdlePtr->nextPtr = idlePtr;
  1096.     }
  1097.     lastIdlePtr = idlePtr;
  1098. }
  1099.  
  1100. /*
  1101.  *----------------------------------------------------------------------
  1102.  *
  1103.  * Tk_CancelIdleCall --
  1104.  *
  1105.  *    If there are any when-idle calls requested to a given procedure
  1106.  *    with given clientData, cancel all of them.
  1107.  *
  1108.  * Results:
  1109.  *    None.
  1110.  *
  1111.  * Side effects:
  1112.  *    If the proc/clientData combination were on the when-idle list,
  1113.  *    they are removed so that they will never be called.
  1114.  *
  1115.  *----------------------------------------------------------------------
  1116.  */
  1117.  
  1118. void
  1119. Tk_CancelIdleCall(proc, clientData)
  1120.     Tk_IdleProc *proc;        /* Procedure that was previously registered. */
  1121.     ClientData clientData;    /* Arbitrary value to pass to proc. */
  1122. {
  1123.     register IdleHandler *idlePtr, *prevPtr;
  1124.     IdleHandler *nextPtr;
  1125.  
  1126.     for (prevPtr = NULL, idlePtr = idleList; idlePtr != NULL;
  1127.         prevPtr = idlePtr, idlePtr = idlePtr->nextPtr) {
  1128.     while ((idlePtr->proc == proc)
  1129.         && (idlePtr->clientData == clientData)) {
  1130.         nextPtr = idlePtr->nextPtr;
  1131.         ckfree((char *) idlePtr);
  1132.         idlePtr = nextPtr;
  1133.         if (prevPtr == NULL) {
  1134.         idleList = idlePtr;
  1135.         } else {
  1136.         prevPtr->nextPtr = idlePtr;
  1137.         }
  1138.         if (idlePtr == NULL) {
  1139.         lastIdlePtr = prevPtr;
  1140.         return;
  1141.         }
  1142.     }
  1143.     }
  1144. }
  1145.  
  1146. /*
  1147.  *--------------------------------------------------------------
  1148.  *
  1149.  * Tk_DoOneEvent --
  1150.  *
  1151.  *    Process a single event of some sort.  If there's no
  1152.  *    work to do, wait for an event to occur, then process
  1153.  *    it.
  1154.  *
  1155.  * Results:
  1156.  *    The return value is 1 if the procedure actually found
  1157.  *    an event to process.  If no event was found then 0 is
  1158.  *    returned.
  1159.  *
  1160.  * Side effects:
  1161.  *    May delay execution of process while waiting for an
  1162.  *    X event, X error, file-ready event, or timer event.
  1163.  *    The handling of the event could cause additional
  1164.  *    side effects.  Collapses sequences of mouse-motion
  1165.  *    events for the same window into a single event by
  1166.  *    delaying motion event processing.
  1167.  *
  1168.  *--------------------------------------------------------------
  1169.  */
  1170.  
  1171. int
  1172. Tk_DoOneEvent(flags)
  1173.     int flags;            /* Miscellaneous flag values:  may be any
  1174.                  * combination of TK_DONT_WAIT, TK_X_EVENTS,
  1175.                  * TK_FILE_EVENTS, TK_TIMER_EVENTS, and
  1176.                  * TK_IDLE_EVENTS. */
  1177. {
  1178.     register FileEvent *filePtr;
  1179.     struct timeval curTime, timeout, *timeoutPtr;
  1180.     int numFound;
  1181.     static XEvent delayedMotionEvent;    /* Used to hold motion events that
  1182.                      * are being saved until later. */
  1183.     static int eventDelayed = 0;    /* Non-zero means there is an event
  1184.                      * in delayedMotionEvent. */
  1185.  
  1186.     if ((flags & TK_ALL_EVENTS) == 0) {
  1187.     flags |= TK_ALL_EVENTS;
  1188.     }
  1189.  
  1190.     /*
  1191.      * Phase One: see if there's already something ready
  1192.      * (either a file or a display) that was left over
  1193.      * from before (i.e don't do a select, just check the
  1194.      * bits from the last select).
  1195.      */
  1196.  
  1197.     checkFiles:
  1198.     for (filePtr = fileList; filePtr != NULL;
  1199.         filePtr = filePtr->nextPtr) {
  1200.     int mask;
  1201.  
  1202.     /*
  1203.      * Displays:  flush output, check for queued events,
  1204.      * and read events from the server if display is ready.
  1205.      * If there are any events, process one and then
  1206.      * return.
  1207.      */
  1208.  
  1209.     if ((filePtr->proc == NULL) && (flags & TK_X_EVENTS)) {
  1210.         Display *display = (Display *) filePtr->clientData;
  1211.         XEvent event;
  1212.  
  1213.         XFlush(display);
  1214.         if ((*filePtr->readPtr) & filePtr->mask) {
  1215.         *filePtr->readPtr &= ~filePtr->mask;
  1216.         if (XEventsQueued(display, QueuedAfterReading) == 0) {
  1217.  
  1218.             /*
  1219.              * Things are very tricky if there aren't any events
  1220.              * readable at this point (after all, there was
  1221.              * supposedly data available on the connection).
  1222.              * A couple of things could have occurred:
  1223.              * 
  1224.              * One possibility is that there were only error events
  1225.              * in the input from the server.  If this happens,
  1226.              * we should return (we don't want to go to sleep
  1227.              * in XNextEvent below, since this would block out
  1228.              * other sources of input to the process).
  1229.              *
  1230.              * Another possibility is that our connection to the
  1231.              * server has been closed.  This will not necessarily
  1232.              * be detected in XEventsQueued (!!), so if we just
  1233.              * return then there will be an infinite loop.  To
  1234.              * detect such an error, generate a NoOp protocol
  1235.              * request to exercise the connection to the server,
  1236.              * then return.  However, must disable SIGPIPE while
  1237.              * sending the event, or else the process will die
  1238.              * from the signal and won't invoke the X error
  1239.              * function to print a nice message.
  1240.              */
  1241.  
  1242.             void (*oldHandler)();
  1243.  
  1244.             oldHandler = (void (*)()) signal(SIGPIPE, SIG_IGN);
  1245.             XNoOp(display);
  1246.             XFlush(display);
  1247.             (void) signal(SIGPIPE, oldHandler);
  1248.             return 1;
  1249.         }
  1250.         if (restrictProc != NULL) {
  1251.             if (!XCheckIfEvent(display, &event, restrictProc,
  1252.                 restrictArg)) {
  1253.             return 1;
  1254.             }
  1255.         } else {
  1256.             XNextEvent(display, &event);
  1257.         }
  1258.         } else {
  1259.         if (QLength(display) == 0) {
  1260.             continue;
  1261.         }
  1262.         if (restrictProc != NULL) {
  1263.             if (!XCheckIfEvent(display, &event, restrictProc,
  1264.                 restrictArg)) {
  1265.             continue;
  1266.             }
  1267.         } else {
  1268.             XNextEvent(display, &event);
  1269.         }
  1270.         }
  1271.  
  1272.         /*
  1273.          * Got an event.  Deal with mouse-motion-collapsing and
  1274.          * event-delaying here.  If there's already an event delayed,
  1275.          * then process that event if it's incompatible with the new
  1276.          * event (new event not mouse motion, or window changed, or
  1277.          * state changed).  If the new event is mouse motion, then
  1278.          * don't process it now;  delay it until later in the hopes
  1279.          * that it can be merged with other mouse motion events
  1280.          * immediately following.
  1281.          */
  1282.  
  1283.         if (tkEventDebug) {
  1284.         eventTrace[traceIndex] = event;
  1285.         traceIndex = (traceIndex+1) % TK_NEVENTS;
  1286.         }
  1287.  
  1288.         if (eventDelayed) {
  1289.         if (((event.type != MotionNotify)
  1290.                 && (event.type != GraphicsExpose)
  1291.                 && (event.type != NoExpose)
  1292.                 && (event.type != Expose))
  1293.             || (event.xmotion.display
  1294.                 != delayedMotionEvent.xmotion.display)
  1295.             || (event.xmotion.window
  1296.                 != delayedMotionEvent.xmotion.window)) {
  1297.             XEvent copy;
  1298.  
  1299.             /*
  1300.              * Must copy the event out of delayedMotionEvent before
  1301.              * processing it, in order to allow recursive calls to
  1302.              * Tk_DoOneEvent as part of the handler.
  1303.              */
  1304.  
  1305.             copy = delayedMotionEvent;
  1306.             eventDelayed = 0;
  1307.             Tk_HandleEvent(©);
  1308.         }
  1309.         }
  1310.         if (event.type == MotionNotify) {
  1311.         delayedMotionEvent = event;
  1312.         eventDelayed = 1;
  1313.         } else {
  1314.         Tk_HandleEvent(&event);
  1315.         }
  1316.         return 1;
  1317.     }
  1318.  
  1319.     /*
  1320.      * Not a display:  if the file is ready, call the
  1321.      * appropriate handler.
  1322.      */
  1323.  
  1324.     if (((*filePtr->readPtr | *filePtr->writePtr
  1325.         | *filePtr->exceptPtr) & filePtr->mask) == 0) {
  1326.         continue;
  1327.     }
  1328.     if (!(flags & TK_FILE_EVENTS)) {
  1329.         continue;
  1330.     }
  1331.     mask = 0;
  1332.     if (*filePtr->readPtr & filePtr->mask) {
  1333.         mask |= TK_READABLE;
  1334.         *filePtr->readPtr &= ~filePtr->mask;
  1335.     }
  1336.     if (*filePtr->writePtr & filePtr->mask) {
  1337.         mask |= TK_WRITABLE;
  1338.         *filePtr->writePtr &= ~filePtr->mask;
  1339.     }
  1340.     if (*filePtr->exceptPtr & filePtr->mask) {
  1341.         mask |= TK_EXCEPTION;
  1342.         *filePtr->exceptPtr &= ~filePtr->mask;
  1343.     }
  1344.     (*filePtr->proc)(filePtr->clientData, mask);
  1345.     return 1;
  1346.     }
  1347.  
  1348.     /*
  1349.      * Phase Two: get the current time and see if any timer
  1350.      * events are ready to fire.  If so, fire one and return.
  1351.      */
  1352.  
  1353.     checkTime:
  1354.     if ((timerQueue != NULL) && (flags & TK_TIMER_EVENTS)) {
  1355.     register TimerEvent *timerPtr = timerQueue;
  1356.  
  1357.     (void) gettimeofday(&curTime, (struct timezone *) NULL);
  1358.     if ((timerPtr->time.tv_sec < curTime.tv_sec)
  1359.         || ((timerPtr->time.tv_sec == curTime.tv_sec)
  1360.         &&  (timerPtr->time.tv_usec < curTime.tv_usec))) {
  1361.         timerQueue = timerPtr->nextPtr;
  1362.         (*timerPtr->proc)(timerPtr->clientData);
  1363.         ckfree((char *) timerPtr);
  1364.         return 1;
  1365.     }
  1366.     }
  1367.  
  1368.  
  1369.     /*
  1370.      * Phase Three: if there is a delayed motion event, process it
  1371.      * now, before any DoWhenIdle handlers.  Better to process before
  1372.      * idle handlers than after, because the goal of idle handlers is
  1373.      * to delay until after all pending events have been processed.
  1374.      * Must free up delayedMotionEvent *before* calling Tk_HandleEvent,
  1375.      * so that the event handler can call Tk_DoOneEvent recursively
  1376.      * without infinite looping.
  1377.      */
  1378.  
  1379.     if ((eventDelayed) && (flags & TK_X_EVENTS)) {
  1380.     XEvent copy;
  1381.  
  1382.     copy = delayedMotionEvent;
  1383.     eventDelayed = 0;
  1384.     Tk_HandleEvent(©);
  1385.     return 1;
  1386.     }
  1387.  
  1388.     /*
  1389.      * Phase Four: if there are DoWhenIdle requests pending (or
  1390.      * if we're not allowed to block), then do a select with an
  1391.      * instantaneous timeout.  If a ready file is found, then go
  1392.      * back to process it.
  1393.      */
  1394.  
  1395.     if (((idleList != NULL) && (flags & TK_IDLE_EVENTS))
  1396.         || (flags & TK_DONT_WAIT)) {
  1397.     if (flags & (TK_X_EVENTS|TK_FILE_EVENTS)) {
  1398.         memcpy((VOID *) ready, (VOID *) masks, 3*MASK_SIZE*sizeof(int));
  1399.         timeout.tv_sec = timeout.tv_usec = 0;
  1400.         do {
  1401.         numFound = select(numFds, (SELECT_MASK *) readPtr,
  1402.             (SELECT_MASK *) writePtr, (SELECT_MASK *) exceptPtr,
  1403.             &timeout);
  1404.         } while ((numFound == -1) && (errno == EINTR));
  1405.         if (numFound > 0) {
  1406.         goto checkFiles;
  1407.         }
  1408.     }
  1409.     }
  1410.  
  1411.     /*
  1412.      * Phase Five:  process all pending DoWhenIdle requests.
  1413.      */
  1414.  
  1415.     if ((idleList != NULL) && (flags & TK_IDLE_EVENTS)) {
  1416.     register IdleHandler *idlePtr;
  1417.     int oldGeneration;
  1418.  
  1419.     oldGeneration = idleList->generation;
  1420.     idleGeneration++;
  1421.  
  1422.     /*
  1423.      * The code below is trickier than it may look, for the following
  1424.      * reasons:
  1425.      *
  1426.      * 1. New handlers can get added to the list while the current
  1427.      *    one is being processed.  If new ones get added, we don't
  1428.      *    want to process them during this pass through the list (want
  1429.      *    to check for other work to do first).  This is implemented
  1430.      *    using the generation number in the handler:  new handlers
  1431.      *    will have a different generation than any of the ones currently
  1432.      *    on the list.
  1433.      * 2. The handler can call Tk_DoOneEvent, so we have to remove
  1434.      *    the hander from the list before calling it. Otherwise an
  1435.      *    infinite loop could result.
  1436.      * 3. Tk_CancelIdleCall can be called to remove an element from
  1437.      *    the list while a handler is executing, so the list could
  1438.      *    change structure during the call.
  1439.      */
  1440.  
  1441.     for (idlePtr = idleList;
  1442.         ((idlePtr != NULL) && (idlePtr->generation == oldGeneration));
  1443.         idlePtr = idleList) {
  1444.       /* fprintf(stderr, "Phase5A"); Here is where it is looping */
  1445.       idleList = idlePtr->nextPtr;
  1446.         if (idleList == NULL) {
  1447.         lastIdlePtr = NULL;
  1448.         }
  1449.         (*idlePtr->proc)(idlePtr->clientData);
  1450.         ckfree((char *) idlePtr);
  1451.     }
  1452.     return 1;
  1453.     }
  1454.  
  1455.     /*
  1456.      * Phase Six: do a select to wait for either one of the
  1457.      * files to become ready or for the first timer event to
  1458.      * fire.  Then go back to process the event.
  1459.      */
  1460.  
  1461.     if ((flags & TK_DONT_WAIT)
  1462.         || !(flags & (TK_TIMER_EVENTS|TK_FILE_EVENTS|TK_X_EVENTS))) {
  1463.     return 0;
  1464.     }
  1465.     if ((timerQueue == NULL) || !(flags & TK_TIMER_EVENTS)) {
  1466.     timeoutPtr = NULL;
  1467.     } else {
  1468.     timeoutPtr = &timeout;
  1469.     timeout.tv_sec = timerQueue->time.tv_sec - curTime.tv_sec;
  1470.     timeout.tv_usec = timerQueue->time.tv_usec - curTime.tv_usec;
  1471.     if (timeout.tv_usec < 0) {
  1472.         timeout.tv_sec -= 1;
  1473.         timeout.tv_usec += 1000000;
  1474.     }
  1475.     }
  1476.     memcpy((VOID *) ready, (VOID *) masks, 3*MASK_SIZE*sizeof(int));
  1477.     do {
  1478.     numFound = select(numFds, (SELECT_MASK *) readPtr,
  1479.         (SELECT_MASK *) writePtr, (SELECT_MASK *) exceptPtr,
  1480.         timeoutPtr);
  1481.     } while ((numFound == -1) && (errno == EINTR));
  1482.     if (numFound == 0) {
  1483.     goto checkTime;
  1484.     }
  1485.     goto checkFiles;
  1486. }
  1487.  
  1488. /*
  1489.  *--------------------------------------------------------------
  1490.  *
  1491.  * Tk_MainLoop --
  1492.  *
  1493.  *    Call Tk_DoOneEvent over and over again in an infinite
  1494.  *    loop as long as there exist any main windows.
  1495.  *
  1496.  * Results:
  1497.  *    None.
  1498.  *
  1499.  * Side effects:
  1500.  *    Arbitrary;  depends on handlers for events.
  1501.  *
  1502.  *--------------------------------------------------------------
  1503.  */
  1504.  
  1505. void
  1506. Tk_MainLoop()
  1507. {
  1508.     while (tk_NumMainWindows > 0) {
  1509.     Tk_DoOneEvent(0);
  1510.     }
  1511. }
  1512.  
  1513. /*
  1514.  *----------------------------------------------------------------------
  1515.  *
  1516.  * Tk_Sleep --
  1517.  *
  1518.  *    Delay execution for the specified number of milliseconds.
  1519.  *
  1520.  * Results:
  1521.  *    None.
  1522.  *
  1523.  * Side effects:
  1524.  *    Time passes.
  1525.  *
  1526.  *----------------------------------------------------------------------
  1527.  */
  1528.  
  1529. void
  1530. Tk_Sleep(ms)
  1531.     int ms;            /* Number of milliseconds to sleep. */
  1532. {
  1533.     static struct timeval delay;
  1534.  
  1535.     delay.tv_sec = ms/1000;
  1536.     delay.tv_usec = (ms%1000)*1000;
  1537.     (void) select(0, (SELECT_MASK *) 0, (SELECT_MASK *) 0,
  1538.         (SELECT_MASK *) 0, &delay);
  1539. }
  1540.  
  1541. /*
  1542.  *----------------------------------------------------------------------
  1543.  *
  1544.  * Tk_RestrictEvents --
  1545.  *
  1546.  *    This procedure is used to globally restrict the set of events
  1547.  *    that will be dispatched.  The restriction is done by filtering
  1548.  *    all incoming X events through a procedure that determines
  1549.  *    whether they are to be processed immediately or deferred.
  1550.  *
  1551.  * Results:
  1552.  *    The return value is the previous restriction procedure in effect,
  1553.  *    if there was one, or NULL if there wasn't.
  1554.  *
  1555.  * Side effects:
  1556.  *    From now on, proc will be called to determine whether to process
  1557.  *    or defer each incoming X event.
  1558.  *
  1559.  *----------------------------------------------------------------------
  1560.  */
  1561.  
  1562. Tk_RestrictProc *
  1563. Tk_RestrictEvents(proc, arg, prevArgPtr)
  1564.     Tk_RestrictProc *proc;    /* X "if" procedure to call for each
  1565.                  * incoming event.  See "XIfEvent" doc.
  1566.                  * for details. */
  1567.     char *arg;            /* Arbitrary argument to pass to proc. */
  1568.     char **prevArgPtr;        /* Place to store information about previous
  1569.                  * argument. */
  1570. {
  1571.     Bool (*prev)  _ANSI_ARGS_((Display *display, XEvent *eventPtr, char *arg));
  1572.  
  1573.     prev = restrictProc;
  1574.     *prevArgPtr = restrictArg;
  1575.     restrictProc = proc;
  1576.     restrictArg = arg;
  1577.     return prev;
  1578. }
  1579.  
  1580. /*
  1581.  *--------------------------------------------------------------
  1582.  *
  1583.  * TkEventDeadWindow --
  1584.  *
  1585.  *    This procedure is invoked when it is determined that
  1586.  *    a window is dead.  It cleans up event-related information
  1587.  *    about the window.
  1588.  *
  1589.  * Results:
  1590.  *    None.
  1591.  *
  1592.  * Side effects:
  1593.  *    Various things get cleaned up and recycled.
  1594.  *
  1595.  *--------------------------------------------------------------
  1596.  */
  1597.  
  1598. void
  1599. TkEventDeadWindow(winPtr)
  1600.     TkWindow *winPtr;        /* Information about the window
  1601.                  * that is being deleted. */
  1602. {
  1603.     register TkEventHandler *handlerPtr;
  1604.     register InProgress *ipPtr;
  1605.  
  1606.     /*
  1607.      * While deleting all the handlers, be careful to check for
  1608.      * Tk_HandleEvent being about to process one of the deleted
  1609.      * handlers.  If it is, tell it to quit (all of the handlers
  1610.      * are being deleted).
  1611.      */
  1612.  
  1613.     while (winPtr->handlerList != NULL) {
  1614.     handlerPtr = winPtr->handlerList;
  1615.     winPtr->handlerList = handlerPtr->nextPtr;
  1616.     for (ipPtr = pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) {
  1617.         if (ipPtr->nextHandler == handlerPtr) {
  1618.         ipPtr->nextHandler = NULL;
  1619.         }
  1620.         if (ipPtr->winPtr == winPtr) {
  1621.         ipPtr->winPtr = None;
  1622.         }
  1623.     }
  1624.     ckfree((char *) handlerPtr);
  1625.     }
  1626. }
  1627.  
  1628. /*
  1629.  *----------------------------------------------------------------------
  1630.  *
  1631.  * TkCurrentTime --
  1632.  *
  1633.  *    Try to deduce the current time.  "Current time" means the time
  1634.  *    of the event that led to the current code being executed, which
  1635.  *    means the time in the most recently-nested invocation of
  1636.  *    Tk_HandleEvent.
  1637.  *
  1638.  * Results:
  1639.  *    The return value is the time from the current event, or
  1640.  *    CurrentTime if there is no current event or if the current
  1641.  *    event contains no time.
  1642.  *
  1643.  * Side effects:
  1644.  *    None.
  1645.  *
  1646.  *----------------------------------------------------------------------
  1647.  */
  1648.  
  1649. Time
  1650. TkCurrentTime(dispPtr)
  1651.     TkDisplay *dispPtr;        /* Display for which the time is desired. */
  1652. {
  1653.     register XEvent *eventPtr;
  1654.  
  1655.     if (pendingPtr == NULL) {
  1656.     return dispPtr->lastEventTime;
  1657.     }
  1658.     eventPtr = pendingPtr->eventPtr;
  1659.     switch (eventPtr->type) {
  1660.     case ButtonPress:
  1661.     case ButtonRelease:
  1662.         return eventPtr->xbutton.time;
  1663.     case KeyPress:
  1664.     case KeyRelease:
  1665.         return eventPtr->xkey.time;
  1666.     case MotionNotify:
  1667.         return eventPtr->xmotion.time;
  1668.     case EnterNotify:
  1669.     case LeaveNotify:
  1670.         return eventPtr->xcrossing.time;
  1671.     case PropertyNotify:
  1672.         return eventPtr->xproperty.time;
  1673.     }
  1674.     return dispPtr->lastEventTime;
  1675. }
  1676.