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