home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tkisrc04.zip / tk / os2 / tkEvent.c < prev    next >
C/C++ Source or Header  |  1998-08-07  |  30KB  |  1,043 lines

  1. /* 
  2.  * tkEvent.c --
  3.  *
  4.  *    This file provides basic low-level facilities for managing
  5.  *    X events in Tk.
  6.  *
  7.  * Copyright (c) 1990-1994 The Regents of the University of California.
  8.  * Copyright (c) 1994-1995 Sun Microsystems, Inc.
  9.  *
  10.  * See the file "license.terms" for information on usage and redistribution
  11.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12.  *
  13.  * SCCS: @(#) tkEvent.c 1.16 96/03/29 17:56:54
  14.  */
  15.  
  16. #include "tkPort.h"
  17. #include "tkInt.h"
  18. #include <signal.h>
  19.  
  20. /*
  21.  * There's a potential problem if a handler is deleted while it's
  22.  * current (i.e. its procedure is executing), since Tk_HandleEvent
  23.  * will need to read the handler's "nextPtr" field when the procedure
  24.  * returns.  To handle this problem, structures of the type below
  25.  * indicate the next handler to be processed for any (recursively
  26.  * nested) dispatches in progress.  The nextHandler fields get
  27.  * updated if the handlers pointed to are deleted.  Tk_HandleEvent
  28.  * also needs to know if the entire window gets deleted;  the winPtr
  29.  * field is set to zero if that particular window gets deleted.
  30.  */
  31.  
  32. typedef struct InProgress {
  33.     XEvent *eventPtr;         /* Event currently being handled. */
  34.     TkWindow *winPtr;         /* Window for event.  Gets set to None if
  35.                   * window is deleted while event is being
  36.                   * handled. */
  37.     TkEventHandler *nextHandler; /* Next handler in search. */
  38.     struct InProgress *nextPtr;     /* Next higher nested search. */
  39. } InProgress;
  40.  
  41. static InProgress *pendingPtr = NULL;
  42.                 /* Topmost search in progress, or
  43.                  * NULL if none. */
  44.  
  45. /*
  46.  * For each call to Tk_CreateGenericHandler, an instance of the following
  47.  * structure will be created.  All of the active handlers are linked into a
  48.  * list.
  49.  */
  50.  
  51. typedef struct GenericHandler {
  52.     Tk_GenericProc *proc;    /* Procedure to dispatch on all X events. */
  53.     ClientData clientData;    /* Client data to pass to procedure. */
  54.     int deleteFlag;        /* Flag to set when this handler is deleted. */
  55.     struct GenericHandler *nextPtr;
  56.                 /* Next handler in list of all generic
  57.                  * handlers, or NULL for end of list. */
  58. } GenericHandler;
  59.  
  60. static GenericHandler *genericList = NULL;
  61.                 /* First handler in the list, or NULL. */
  62. static GenericHandler *lastGenericPtr = NULL;
  63.                 /* Last handler in list. */
  64.  
  65. /*
  66.  * There's a potential problem if Tk_HandleEvent is entered recursively.
  67.  * A handler cannot be deleted physically until we have returned from
  68.  * calling it.  Otherwise, we're looking at unallocated memory in advancing to
  69.  * its `next' entry.  We deal with the problem by using the `delete flag' and
  70.  * deleting handlers only when it's known that there's no handler active.
  71.  *
  72.  * The following variable has a non-zero value when a handler is active.
  73.  */
  74.  
  75. static int genericHandlersActive = 0;
  76.  
  77. /*
  78.  * The following structure is used for queueing X-style events on the
  79.  * Tcl event queue.
  80.  */
  81.  
  82. typedef struct TkWindowEvent {
  83.     Tcl_Event header;        /* Standard information for all events. */
  84.     XEvent event;        /* The X event. */
  85. } TkWindowEvent;
  86.  
  87. /*
  88.  * Array of event masks corresponding to each X event:
  89.  */
  90.  
  91. static unsigned long eventMasks[] = {
  92.     0,
  93.     0,
  94.     KeyPressMask,            /* KeyPress */
  95.     KeyReleaseMask,            /* KeyRelease */
  96.     ButtonPressMask,            /* ButtonPress */
  97.     ButtonReleaseMask,            /* ButtonRelease */
  98.     PointerMotionMask|PointerMotionHintMask|ButtonMotionMask
  99.         |Button1MotionMask|Button2MotionMask|Button3MotionMask
  100.         |Button4MotionMask|Button5MotionMask,
  101.                     /* MotionNotify */
  102.     EnterWindowMask,            /* EnterNotify */
  103.     LeaveWindowMask,            /* LeaveNotify */
  104.     FocusChangeMask,            /* FocusIn */
  105.     FocusChangeMask,            /* FocusOut */
  106.     KeymapStateMask,            /* KeymapNotify */
  107.     ExposureMask,            /* Expose */
  108.     ExposureMask,            /* GraphicsExpose */
  109.     ExposureMask,            /* NoExpose */
  110.     VisibilityChangeMask,        /* VisibilityNotify */
  111.     SubstructureNotifyMask,        /* CreateNotify */
  112.     StructureNotifyMask,        /* DestroyNotify */
  113.     StructureNotifyMask,        /* UnmapNotify */
  114.     StructureNotifyMask,        /* MapNotify */
  115.     SubstructureRedirectMask,        /* MapRequest */
  116.     StructureNotifyMask,        /* ReparentNotify */
  117.     StructureNotifyMask,        /* ConfigureNotify */
  118.     SubstructureRedirectMask,        /* ConfigureRequest */
  119.     StructureNotifyMask,        /* GravityNotify */
  120.     ResizeRedirectMask,            /* ResizeRequest */
  121.     StructureNotifyMask,        /* CirculateNotify */
  122.     SubstructureRedirectMask,        /* CirculateRequest */
  123.     PropertyChangeMask,            /* PropertyNotify */
  124.     0,                    /* SelectionClear */
  125.     0,                    /* SelectionRequest */
  126.     0,                    /* SelectionNotify */
  127.     ColormapChangeMask,            /* ColormapNotify */
  128.     0,                    /* ClientMessage */
  129.     0,                    /* Mapping Notify */
  130.     ActivateMask,            /* ActivateNotify */
  131.     ActivateMask            /* DeactivateNotify */
  132. };
  133.  
  134. /*
  135.  * If someone has called Tk_RestrictEvents, the information below
  136.  * keeps track of it.
  137.  */
  138.  
  139. static Tk_RestrictProc *restrictProc;
  140.                 /* Procedure to call.  NULL means no
  141.                  * restrictProc is currently in effect. */
  142. static ClientData restrictArg;    /* Argument to pass to restrictProc. */
  143.  
  144. /*
  145.  * Prototypes for procedures that are only referenced locally within
  146.  * this file.
  147.  */
  148.  
  149. static void        DelayedMotionProc _ANSI_ARGS_((ClientData clientData));
  150. static int        WindowEventProc _ANSI_ARGS_((Tcl_Event *evPtr,
  151.                 int flags));
  152.  
  153. /*
  154.  *--------------------------------------------------------------
  155.  *
  156.  * Tk_CreateEventHandler --
  157.  *
  158.  *    Arrange for a given procedure to be invoked whenever
  159.  *    events from a given class occur in a given window.
  160.  *
  161.  * Results:
  162.  *    None.
  163.  *
  164.  * Side effects:
  165.  *    From now on, whenever an event of the type given by
  166.  *    mask occurs for token and is processed by Tk_HandleEvent,
  167.  *    proc will be called.  See the manual entry for details
  168.  *    of the calling sequence and return value for proc.
  169.  *
  170.  *--------------------------------------------------------------
  171.  */
  172.  
  173. void
  174. Tk_CreateEventHandler(token, mask, proc, clientData)
  175.     Tk_Window token;        /* Token for window in which to
  176.                  * create handler. */
  177.     unsigned long mask;        /* Events for which proc should
  178.                  * be called. */
  179.     Tk_EventProc *proc;        /* Procedure to call for each
  180.                  * selected event */
  181.     ClientData clientData;    /* Arbitrary data to pass to proc. */
  182. {
  183.     register TkEventHandler *handlerPtr;
  184.     register TkWindow *winPtr = (TkWindow *) token;
  185.     int found;
  186.  
  187.     /*
  188.      * Skim through the list of existing handlers to (a) compute the
  189.      * overall event mask for the window (so we can pass this new
  190.      * value to the X system) and (b) see if there's already a handler
  191.      * declared with the same callback and clientData (if so, just
  192.      * change the mask).  If no existing handler matches, then create
  193.      * a new handler.
  194.      */
  195.  
  196.     found = 0;
  197.     if (winPtr->handlerList == NULL) {
  198.     handlerPtr = (TkEventHandler *) ckalloc(
  199.         (unsigned) sizeof(TkEventHandler));
  200.     winPtr->handlerList = handlerPtr;
  201.     goto initHandler;
  202.     } else {
  203.     for (handlerPtr = winPtr->handlerList; ;
  204.         handlerPtr = handlerPtr->nextPtr) {
  205.         if ((handlerPtr->proc == proc)
  206.             && (handlerPtr->clientData == clientData)) {
  207.         handlerPtr->mask = mask;
  208.         found = 1;
  209.         }
  210.         if (handlerPtr->nextPtr == NULL) {
  211.         break;
  212.         }
  213.     }
  214.     }
  215.  
  216.     /*
  217.      * Create a new handler if no matching old handler was found.
  218.      */
  219.  
  220.     if (!found) {
  221.     handlerPtr->nextPtr = (TkEventHandler *)
  222.         ckalloc(sizeof(TkEventHandler));
  223.     handlerPtr = handlerPtr->nextPtr;
  224.     initHandler:
  225.     handlerPtr->mask = mask;
  226.     handlerPtr->proc = proc;
  227.     handlerPtr->clientData = clientData;
  228.     handlerPtr->nextPtr = NULL;
  229.     }
  230.  
  231.     /*
  232.      * No need to call XSelectInput:  Tk always selects on all events
  233.      * for all windows (needed to support bindings on classes and "all").
  234.      */
  235. }
  236.  
  237. /*
  238.  *--------------------------------------------------------------
  239.  *
  240.  * Tk_DeleteEventHandler --
  241.  *
  242.  *    Delete a previously-created handler.
  243.  *
  244.  * Results:
  245.  *    None.
  246.  *
  247.  * Side effects:
  248.  *    If there existed a handler as described by the
  249.  *    parameters, the handler is deleted so that proc
  250.  *    will not be invoked again.
  251.  *
  252.  *--------------------------------------------------------------
  253.  */
  254.  
  255. void
  256. Tk_DeleteEventHandler(token, mask, proc, clientData)
  257.     Tk_Window token;        /* Same as corresponding arguments passed */
  258.     unsigned long mask;        /* previously to Tk_CreateEventHandler. */
  259.     Tk_EventProc *proc;
  260.     ClientData clientData;
  261. {
  262.     register TkEventHandler *handlerPtr;
  263.     register InProgress *ipPtr;
  264.     TkEventHandler *prevPtr;
  265.     register TkWindow *winPtr = (TkWindow *) token;
  266.  
  267.     /*
  268.      * Find the event handler to be deleted, or return
  269.      * immediately if it doesn't exist.
  270.      */
  271.  
  272.     for (handlerPtr = winPtr->handlerList, prevPtr = NULL; ;
  273.         prevPtr = handlerPtr, handlerPtr = handlerPtr->nextPtr) {
  274.     if (handlerPtr == NULL) {
  275.         return;
  276.     }
  277.     if ((handlerPtr->mask == mask) && (handlerPtr->proc == proc)
  278.         && (handlerPtr->clientData == clientData)) {
  279.         break;
  280.     }
  281.     }
  282.  
  283.     /*
  284.      * If Tk_HandleEvent is about to process this handler, tell it to
  285.      * process the next one instead.
  286.      */
  287.  
  288.     for (ipPtr = pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) {
  289.     if (ipPtr->nextHandler == handlerPtr) {
  290.         ipPtr->nextHandler = handlerPtr->nextPtr;
  291.     }
  292.     }
  293.  
  294.     /*
  295.      * Free resources associated with the handler.
  296.      */
  297.  
  298.     if (prevPtr == NULL) {
  299.     winPtr->handlerList = handlerPtr->nextPtr;
  300.     } else {
  301.     prevPtr->nextPtr = handlerPtr->nextPtr;
  302.     }
  303.     ckfree((char *) handlerPtr);
  304.  
  305.  
  306.     /*
  307.      * No need to call XSelectInput:  Tk always selects on all events
  308.      * for all windows (needed to support bindings on classes and "all").
  309.      */
  310. }
  311.  
  312. /*--------------------------------------------------------------
  313.  *
  314.  * Tk_CreateGenericHandler --
  315.  *
  316.  *    Register a procedure to be called on each X event, regardless
  317.  *    of display or window.  Generic handlers are useful for capturing
  318.  *    events that aren't associated with windows, or events for windows
  319.  *    not managed by Tk.
  320.  *
  321.  * Results:
  322.  *    None.
  323.  *
  324.  * Side Effects:
  325.  *    From now on, whenever an X event is given to Tk_HandleEvent,
  326.  *    invoke proc, giving it clientData and the event as arguments.
  327.  *
  328.  *--------------------------------------------------------------
  329.  */
  330.  
  331. void
  332. Tk_CreateGenericHandler(proc, clientData)
  333.      Tk_GenericProc *proc;    /* Procedure to call on every event. */
  334.      ClientData clientData;    /* One-word value to pass to proc. */
  335. {
  336.     GenericHandler *handlerPtr;
  337.     
  338.     handlerPtr = (GenericHandler *) ckalloc (sizeof (GenericHandler));
  339.     
  340.     handlerPtr->proc = proc;
  341.     handlerPtr->clientData = clientData;
  342.     handlerPtr->deleteFlag = 0;
  343.     handlerPtr->nextPtr = NULL;
  344.     if (genericList == NULL) {
  345.     genericList = handlerPtr;
  346.     } else {
  347.     lastGenericPtr->nextPtr = handlerPtr;
  348.     }
  349.     lastGenericPtr = handlerPtr;
  350. }
  351.  
  352. /*
  353.  *--------------------------------------------------------------
  354.  *
  355.  * Tk_DeleteGenericHandler --
  356.  *
  357.  *    Delete a previously-created generic handler.
  358.  *
  359.  * Results:
  360.  *    None.
  361.  *
  362.  * Side Effects:
  363.  *    If there existed a handler as described by the parameters,
  364.  *    that handler is logically deleted so that proc will not be
  365.  *    invoked again.  The physical deletion happens in the event
  366.  *    loop in Tk_HandleEvent.
  367.  *
  368.  *--------------------------------------------------------------
  369.  */
  370.  
  371. void
  372. Tk_DeleteGenericHandler(proc, clientData)
  373.      Tk_GenericProc *proc;
  374.      ClientData clientData;
  375. {
  376.     GenericHandler * handler;
  377.     
  378.     for (handler = genericList; handler; handler = handler->nextPtr) {
  379.     if ((handler->proc == proc) && (handler->clientData == clientData)) {
  380.         handler->deleteFlag = 1;
  381.     }
  382.     }
  383. }
  384.  
  385. /*
  386.  *--------------------------------------------------------------
  387.  *
  388.  * Tk_HandleEvent --
  389.  *
  390.  *    Given an event, invoke all the handlers that have
  391.  *    been registered for the event.
  392.  *
  393.  * Results:
  394.  *    None.
  395.  *
  396.  * Side effects:
  397.  *    Depends on the handlers.
  398.  *
  399.  *--------------------------------------------------------------
  400.  */
  401.  
  402. void
  403. Tk_HandleEvent(eventPtr)
  404.     XEvent *eventPtr;        /* Event to dispatch. */
  405. {
  406.     register TkEventHandler *handlerPtr;
  407.     register GenericHandler *genericPtr;
  408.     register GenericHandler *genPrevPtr;
  409.     TkWindow *winPtr;
  410.     unsigned long mask;
  411.     InProgress ip;
  412.     Window handlerWindow;
  413.     TkDisplay *dispPtr;
  414.     Tcl_Interp *interp = (Tcl_Interp *) NULL;
  415.  
  416.     /* 
  417.      * Next, invoke all the generic event handlers (those that are
  418.      * invoked for all events).  If a generic event handler reports that
  419.      * an event is fully processed, go no further.
  420.      */
  421.  
  422.     for (genPrevPtr = NULL, genericPtr = genericList;  genericPtr != NULL; ) {
  423.     if (genericPtr->deleteFlag) {
  424.         if (!genericHandlersActive) {
  425.         GenericHandler *tmpPtr;
  426.  
  427.         /*
  428.          * This handler needs to be deleted and there are no
  429.          * calls pending through the handler, so now is a safe
  430.          * time to delete it.
  431.          */
  432.  
  433.         tmpPtr = genericPtr->nextPtr;
  434.         if (genPrevPtr == NULL) {
  435.             genericList = tmpPtr;
  436.         } else {
  437.             genPrevPtr->nextPtr = tmpPtr;
  438.         }
  439.         if (tmpPtr == NULL) {
  440.             lastGenericPtr = genPrevPtr;
  441.         }
  442.         (void) ckfree((char *) genericPtr);
  443.         genericPtr = tmpPtr;
  444.         continue;
  445.         }
  446.     } else {
  447.         int done;
  448.  
  449.         genericHandlersActive++;
  450.         done = (*genericPtr->proc)(genericPtr->clientData, eventPtr);
  451.         genericHandlersActive--;
  452.         if (done) {
  453.         return;
  454.         }
  455.     }
  456.     genPrevPtr = genericPtr;
  457.     genericPtr = genPrevPtr->nextPtr;
  458.     }
  459.  
  460.     /*
  461.      * If the event is a MappingNotify event, find its display and
  462.      * refresh the keyboard mapping information for the display.
  463.      * After that there's nothing else to do with the event, so just
  464.      * quit.
  465.      */
  466.  
  467.     if (eventPtr->type == MappingNotify) {
  468.     dispPtr = TkGetDisplay(eventPtr->xmapping.display);
  469.     if (dispPtr != NULL) {
  470.         XRefreshKeyboardMapping(&eventPtr->xmapping);
  471.         dispPtr->bindInfoStale = 1;
  472.     }
  473.     return;
  474.     }
  475.  
  476.     /*
  477.      * Events selected by StructureNotify require special handling.
  478.      * They look the same as those selected by SubstructureNotify.
  479.      * The only difference is whether the "event" and "window" fields
  480.      * are the same.  Compare the two fields and convert StructureNotify
  481.      * to SubstructureNotify if necessary.
  482.      */
  483.  
  484.     handlerWindow = eventPtr->xany.window;
  485.     mask = eventMasks[eventPtr->xany.type];
  486.     if (mask == StructureNotifyMask) {
  487.     if (eventPtr->xmap.event != eventPtr->xmap.window) {
  488.         mask = SubstructureNotifyMask;
  489.         handlerWindow = eventPtr->xmap.event;
  490.     }
  491.     }
  492.     winPtr = (TkWindow *) Tk_IdToWindow(eventPtr->xany.display, handlerWindow);
  493.     if (winPtr == NULL) {
  494.  
  495.     /*
  496.      * There isn't a TkWindow structure for this window.
  497.      * However, if the event is a PropertyNotify event then call
  498.      * the selection manager (it deals beneath-the-table with
  499.      * certain properties).
  500.      */
  501.  
  502.     if (eventPtr->type == PropertyNotify) {
  503.         TkSelPropProc(eventPtr);
  504.     }
  505.     return;
  506.     }
  507.  
  508.     if (winPtr->mainPtr != NULL) {
  509.  
  510.         /*
  511.          * Protect interpreter for this window from possible deletion
  512.          * while we are dealing with the event for this window. Thus,
  513.          * widget writers do not have to worry about protecting the
  514.          * interpreter in their own code.
  515.          */
  516.         
  517.         interp = winPtr->mainPtr->interp;
  518.         Tcl_Preserve((ClientData) interp);
  519.         
  520.     /*
  521.      * Call focus-related code to look at FocusIn, FocusOut, Enter,
  522.      * and Leave events;  depending on its return value, ignore the
  523.      * event.
  524.      */
  525.     
  526.     if ((mask & (FocusChangeMask|EnterWindowMask|LeaveWindowMask))
  527.         && !TkFocusFilterEvent(winPtr, eventPtr)) {
  528.             Tcl_Release((ClientData) interp);
  529.         return;
  530.     }
  531.     
  532.     /*
  533.      * Redirect KeyPress and KeyRelease events to the focus window,
  534.      * or ignore them entirely if there is no focus window.  Map the
  535.      * x and y coordinates to make sense in the context of the focus
  536.      * window, if possible (make both -1 if the map-from and map-to
  537.      * windows don't share the same screen).
  538.      */
  539.     
  540.     if (mask & (KeyPressMask|KeyReleaseMask)) {
  541.         TkWindow *focusPtr;
  542.         int winX, winY, focusX, focusY;
  543.     
  544.         winPtr->dispPtr->lastEventTime = eventPtr->xkey.time;
  545.         focusPtr = TkGetFocus(winPtr);
  546.         if (focusPtr == NULL) {
  547.                 Tcl_Release((ClientData) interp);
  548.         return;
  549.         }
  550.         if ((focusPtr->display != winPtr->display)
  551.             || (focusPtr->screenNum != winPtr->screenNum)) {
  552.         eventPtr->xkey.x = -1;
  553.         eventPtr->xkey.y = -1;
  554.         } else {
  555.         Tk_GetRootCoords((Tk_Window) winPtr, &winX, &winY);
  556.         Tk_GetRootCoords((Tk_Window) focusPtr, &focusX, &focusY);
  557.         eventPtr->xkey.x -= focusX - winX;
  558.         eventPtr->xkey.y -= focusY - winY;
  559.         }
  560.         eventPtr->xkey.window = focusPtr->window;
  561.         winPtr = focusPtr;
  562.     }
  563.     
  564.     /*
  565.      * Call a grab-related procedure to do special processing on
  566.      * pointer events.
  567.      */
  568.     
  569.     if (mask & (ButtonPressMask|ButtonReleaseMask|PointerMotionMask
  570.         |EnterWindowMask|LeaveWindowMask)) {
  571.         if (mask & (ButtonPressMask|ButtonReleaseMask)) {
  572.         winPtr->dispPtr->lastEventTime = eventPtr->xbutton.time;
  573.         } else if (mask & PointerMotionMask) {
  574.         winPtr->dispPtr->lastEventTime = eventPtr->xmotion.time;
  575.         } else {
  576.         winPtr->dispPtr->lastEventTime = eventPtr->xcrossing.time;
  577.         }
  578.         if (TkPointerEvent(eventPtr, winPtr) == 0) {
  579.                 goto done;
  580.         }
  581.     }
  582.     }
  583.  
  584. #ifdef TK_USE_INPUT_METHODS
  585.     /*
  586.      * Pass the event to the input method(s), if there are any, and
  587.      * discard the event if the input method(s) insist.  Create the
  588.      * input context for the window if it hasn't already been done
  589.      * (XFilterEvent needs this context).
  590.      */
  591.  
  592.     if (!(winPtr->flags & TK_CHECKED_IC)) {
  593.     if (winPtr->dispPtr->inputMethod != NULL) {
  594.         winPtr->inputContext = XCreateIC(
  595.             winPtr->dispPtr->inputMethod, XNInputStyle,
  596.             XIMPreeditNothing|XIMStatusNothing,
  597.             XNClientWindow, winPtr->window,
  598.             XNFocusWindow, winPtr->window, NULL);
  599.     }
  600.     winPtr->flags |= TK_CHECKED_IC;
  601.     }
  602.     if (XFilterEvent(eventPtr, None)) {
  603.         goto done;
  604.     }
  605. #endif /* TK_USE_INPUT_METHODS */
  606.  
  607.     /*
  608.      * For events where it hasn't already been done, update the current
  609.      * time in the display.
  610.      */
  611.  
  612.     if (eventPtr->type == PropertyNotify) {
  613.     winPtr->dispPtr->lastEventTime = eventPtr->xproperty.time;
  614.     }
  615.  
  616.     /*
  617.      * There's a potential interaction here with Tk_DeleteEventHandler.
  618.      * Read the documentation for pendingPtr.
  619.      */
  620.  
  621.     ip.eventPtr = eventPtr;
  622.     ip.winPtr = winPtr;
  623.     ip.nextHandler = NULL;
  624.     ip.nextPtr = pendingPtr;
  625.     pendingPtr = &ip;
  626.     if (mask == 0) {
  627.     if ((eventPtr->type == SelectionClear)
  628.         || (eventPtr->type == SelectionRequest)
  629.         || (eventPtr->type == SelectionNotify)) {
  630.         TkSelEventProc((Tk_Window) winPtr, eventPtr);
  631.     } else if ((eventPtr->type == ClientMessage)
  632.         && (eventPtr->xclient.message_type ==
  633.             Tk_InternAtom((Tk_Window) winPtr, "WM_PROTOCOLS"))) {
  634.         TkWmProtocolEventProc(winPtr, eventPtr);
  635.     }
  636.     } else {
  637.     for (handlerPtr = winPtr->handlerList; handlerPtr != NULL; ) {
  638.         if ((handlerPtr->mask & mask) != 0) {
  639.         ip.nextHandler = handlerPtr->nextPtr;
  640.         (*(handlerPtr->proc))(handlerPtr->clientData, eventPtr);
  641.         handlerPtr = ip.nextHandler;
  642.         } else {
  643.         handlerPtr = handlerPtr->nextPtr;
  644.         }
  645.     }
  646.  
  647.     /*
  648.      * Pass the event to the "bind" command mechanism.  But, don't
  649.      * do this for SubstructureNotify events.  The "bind" command
  650.      * doesn't support them anyway, and it's easier to filter out
  651.      * these events here than in the lower-level procedures.
  652.      */
  653.  
  654.     if ((ip.winPtr != None) && (mask != SubstructureNotifyMask)) {
  655.         TkBindEventProc(winPtr, eventPtr);
  656.     }
  657.     }
  658.     pendingPtr = ip.nextPtr;
  659. done:
  660.  
  661.     /*
  662.      * Release the interpreter for this window so that it can be potentially
  663.      * deleted if requested.
  664.      */
  665.     
  666.     if (interp != (Tcl_Interp *) NULL) {
  667.         Tcl_Release((ClientData) interp);
  668.     }
  669. }
  670.  
  671. /*
  672.  *--------------------------------------------------------------
  673.  *
  674.  * TkEventDeadWindow --
  675.  *
  676.  *    This procedure is invoked when it is determined that
  677.  *    a window is dead.  It cleans up event-related information
  678.  *    about the window.
  679.  *
  680.  * Results:
  681.  *    None.
  682.  *
  683.  * Side effects:
  684.  *    Various things get cleaned up and recycled.
  685.  *
  686.  *--------------------------------------------------------------
  687.  */
  688.  
  689. void
  690. TkEventDeadWindow(winPtr)
  691.     TkWindow *winPtr;        /* Information about the window
  692.                  * that is being deleted. */
  693. {
  694.     register TkEventHandler *handlerPtr;
  695.     register InProgress *ipPtr;
  696.  
  697.     /*
  698.      * While deleting all the handlers, be careful to check for
  699.      * Tk_HandleEvent being about to process one of the deleted
  700.      * handlers.  If it is, tell it to quit (all of the handlers
  701.      * are being deleted).
  702.      */
  703.  
  704.     while (winPtr->handlerList != NULL) {
  705.     handlerPtr = winPtr->handlerList;
  706.     winPtr->handlerList = handlerPtr->nextPtr;
  707.     for (ipPtr = pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) {
  708.         if (ipPtr->nextHandler == handlerPtr) {
  709.         ipPtr->nextHandler = NULL;
  710.         }
  711.         if (ipPtr->winPtr == winPtr) {
  712.         ipPtr->winPtr = None;
  713.         }
  714.     }
  715.     ckfree((char *) handlerPtr);
  716.     }
  717. }
  718.  
  719. /*
  720.  *----------------------------------------------------------------------
  721.  *
  722.  * TkCurrentTime --
  723.  *
  724.  *    Try to deduce the current time.  "Current time" means the time
  725.  *    of the event that led to the current code being executed, which
  726.  *    means the time in the most recently-nested invocation of
  727.  *    Tk_HandleEvent.
  728.  *
  729.  * Results:
  730.  *    The return value is the time from the current event, or
  731.  *    CurrentTime if there is no current event or if the current
  732.  *    event contains no time.
  733.  *
  734.  * Side effects:
  735.  *    None.
  736.  *
  737.  *----------------------------------------------------------------------
  738.  */
  739.  
  740. Time
  741. TkCurrentTime(dispPtr)
  742.     TkDisplay *dispPtr;        /* Display for which the time is desired. */
  743. {
  744.     register XEvent *eventPtr;
  745.  
  746.     if (pendingPtr == NULL) {
  747.     return dispPtr->lastEventTime;
  748.     }
  749.     eventPtr = pendingPtr->eventPtr;
  750.     switch (eventPtr->type) {
  751.     case ButtonPress:
  752.     case ButtonRelease:
  753.         return eventPtr->xbutton.time;
  754.     case KeyPress:
  755.     case KeyRelease:
  756.         return eventPtr->xkey.time;
  757.     case MotionNotify:
  758.         return eventPtr->xmotion.time;
  759.     case EnterNotify:
  760.     case LeaveNotify:
  761.         return eventPtr->xcrossing.time;
  762.     case PropertyNotify:
  763.         return eventPtr->xproperty.time;
  764.     }
  765.     return dispPtr->lastEventTime;
  766. }
  767.  
  768. /*
  769.  *----------------------------------------------------------------------
  770.  *
  771.  * Tk_RestrictEvents --
  772.  *
  773.  *    This procedure is used to globally restrict the set of events
  774.  *    that will be dispatched.  The restriction is done by filtering
  775.  *    all incoming X events through a procedure that determines
  776.  *    whether they are to be processed immediately, deferred, or
  777.  *    discarded.
  778.  *
  779.  * Results:
  780.  *    The return value is the previous restriction procedure in effect,
  781.  *    if there was one, or NULL if there wasn't.
  782.  *
  783.  * Side effects:
  784.  *    From now on, proc will be called to determine whether to process,
  785.  *    defer or discard each incoming X event.
  786.  *
  787.  *----------------------------------------------------------------------
  788.  */
  789.  
  790. Tk_RestrictProc *
  791. Tk_RestrictEvents(proc, arg, prevArgPtr)
  792.     Tk_RestrictProc *proc;    /* Procedure to call for each incoming
  793.                  * event. */
  794.     ClientData arg;        /* Arbitrary argument to pass to proc. */
  795.     ClientData *prevArgPtr;    /* Place to store information about previous
  796.                  * argument. */
  797. {
  798.     Tk_RestrictProc *prev;
  799.  
  800.     prev = restrictProc;
  801.     *prevArgPtr = restrictArg;
  802.     restrictProc = proc;
  803.     restrictArg = arg;
  804.     return prev;
  805. }
  806.  
  807. /*
  808.  *----------------------------------------------------------------------
  809.  *
  810.  * Tk_QueueWindowEvent --
  811.  *
  812.  *    Given an X-style window event, this procedure adds it to the
  813.  *    Tcl event queue at the given position.  This procedure also
  814.  *    performs mouse motion event collapsing if possible.
  815.  *
  816.  * Results:
  817.  *    None.
  818.  *
  819.  * Side effects:
  820.  *    Adds stuff to the event queue, which will eventually be
  821.  *    processed.
  822.  *
  823.  *----------------------------------------------------------------------
  824.  */
  825.  
  826. void
  827. Tk_QueueWindowEvent(eventPtr, position)
  828.     XEvent *eventPtr;            /* Event to add to queue.  This
  829.                      * procedures copies it before adding
  830.                      * it to the queue. */
  831.     Tcl_QueuePosition position;        /* Where to put it on the queue:
  832.                      * TCL_QUEUE_TAIL, TCL_QUEUE_HEAD,
  833.                      * or TCL_QUEUE_MARK. */
  834. {
  835.     TkWindowEvent *wevPtr;
  836.     TkDisplay *dispPtr;
  837.  
  838.     /*
  839.      * Find our display structure for the event's display.
  840.      */
  841.  
  842.     for (dispPtr = tkDisplayList; ; dispPtr = dispPtr->nextPtr) {
  843.     if (dispPtr == NULL) {
  844.         return;
  845.     }
  846.     if (dispPtr->display == eventPtr->xany.display) {
  847.         break;
  848.     }
  849.     }
  850.  
  851.     if ((dispPtr->delayedMotionPtr != NULL) && (position == TCL_QUEUE_TAIL)) {
  852.     if ((eventPtr->type == MotionNotify) && (eventPtr->xmotion.window
  853.         == dispPtr->delayedMotionPtr->event.xmotion.window)) {
  854.         /*
  855.          * The new event is a motion event in the same window as the
  856.          * saved motion event.  Just replace the saved event with the
  857.          * new one.
  858.          */
  859.  
  860.         dispPtr->delayedMotionPtr->event = *eventPtr;
  861.         return;
  862.     } else if ((eventPtr->type != GraphicsExpose)
  863.         && (eventPtr->type != NoExpose)
  864.         && (eventPtr->type != Expose)) {
  865.         /*
  866.          * The new event may conflict with the saved motion event.  Queue
  867.          * the saved motion event now so that it will be processed before
  868.          * the new event.
  869.          */
  870.  
  871.         Tcl_QueueEvent(&dispPtr->delayedMotionPtr->header, position);
  872.         dispPtr->delayedMotionPtr = NULL;
  873.         Tcl_CancelIdleCall(DelayedMotionProc, (ClientData) dispPtr);
  874.     }
  875.     }
  876.  
  877.     wevPtr = (TkWindowEvent *) ckalloc(sizeof(TkWindowEvent));
  878.     wevPtr->header.proc = WindowEventProc;
  879.     wevPtr->event = *eventPtr;
  880.     if ((eventPtr->type == MotionNotify) && (position == TCL_QUEUE_TAIL)) {
  881.     /*
  882.      * The new event is a motion event so don't queue it immediately;
  883.      * save it around in case another motion event arrives that it can
  884.      * be collapsed with.
  885.      */
  886.  
  887.     if (dispPtr->delayedMotionPtr != NULL) {
  888.         panic("Tk_QueueWindowEvent found unexpected delayed motion event");
  889.     }
  890.     dispPtr->delayedMotionPtr = wevPtr;
  891.     Tcl_DoWhenIdle(DelayedMotionProc, (ClientData) dispPtr);
  892.     } else {
  893.     Tcl_QueueEvent(&wevPtr->header, position);
  894.     }
  895. }
  896.  
  897. /*
  898.  *---------------------------------------------------------------------------
  899.  *
  900.  * TkQueueEventForAllChildren --
  901.  *
  902.  *    Given an XEvent, recursively queue the event for this window and
  903.  *    all non-toplevel children of the given window.  
  904.  *
  905.  * Results:
  906.  *    None.
  907.  *
  908.  * Side effects:
  909.  *    Events queued.
  910.  *
  911.  *---------------------------------------------------------------------------
  912.  */
  913.  
  914. void
  915. TkQueueEventForAllChildren(tkwin, eventPtr)
  916.     Tk_Window tkwin;        /* Window to which event is sent. */
  917.     XEvent *eventPtr;        /* The event to be sent. */
  918. {
  919.     TkWindow *winPtr, *childPtr;
  920.  
  921.     winPtr = (TkWindow *) tkwin;
  922.     eventPtr->xany.window = winPtr->window;
  923.     Tk_QueueWindowEvent(eventPtr, TCL_QUEUE_TAIL);
  924.     
  925.     childPtr = winPtr->childList;
  926.     while (childPtr != NULL) {
  927.     if (!Tk_IsTopLevel(childPtr)) {
  928.         TkQueueEventForAllChildren((Tk_Window) childPtr, eventPtr);
  929.     }
  930.     childPtr = childPtr->nextPtr;
  931.     }
  932. }
  933.  
  934. /*
  935.  *----------------------------------------------------------------------
  936.  *
  937.  * WindowEventProc --
  938.  *
  939.  *    This procedure is called by Tcl_DoOneEvent when a window event
  940.  *    reaches the front of the event queue.  This procedure is responsible
  941.  *    for actually handling the event.
  942.  *
  943.  * Results:
  944.  *    Returns 1 if the event was handled, meaning it should be removed
  945.  *    from the queue.  Returns 0 if the event was not handled, meaning
  946.  *    it should stay on the queue.  The event isn't handled if the
  947.  *    TCL_WINDOW_EVENTS bit isn't set in flags, if a restrict proc
  948.  *    prevents the event from being handled.
  949.  *
  950.  * Side effects:
  951.  *    Whatever the event handlers for the event do.
  952.  *
  953.  *----------------------------------------------------------------------
  954.  */
  955.  
  956. static int
  957. WindowEventProc(evPtr, flags)
  958.     Tcl_Event *evPtr;        /* Event to service. */
  959.     int flags;            /* Flags that indicate what events to
  960.                  * handle, such as TCL_WINDOW_EVENTS. */
  961. {
  962.     TkWindowEvent *wevPtr = (TkWindowEvent *) evPtr;
  963.     Tk_RestrictAction result;
  964.  
  965.     if (!(flags & TCL_WINDOW_EVENTS)) {
  966.     return 0;
  967.     }
  968.     if (restrictProc != NULL) {
  969.     result = (*restrictProc)(restrictArg, &wevPtr->event);
  970.     if (result != TK_PROCESS_EVENT) {
  971.         if (result == TK_DEFER_EVENT) {
  972.         return 0;
  973.         } else {
  974.         /*
  975.          * TK_DELETE_EVENT: return and say we processed the event,
  976.          * even though we didn't do anything at all.
  977.          */
  978.         return 1;
  979.         }
  980.     }
  981.     }
  982.     Tk_HandleEvent(&wevPtr->event);
  983.     return 1;
  984. }
  985.  
  986. /*
  987.  *----------------------------------------------------------------------
  988.  *
  989.  * DelayedMotionProc --
  990.  *
  991.  *    This procedure is invoked as an idle handler when a mouse motion
  992.  *    event has been delayed.  It queues the delayed event so that it
  993.  *    will finally be serviced.
  994.  *
  995.  * Results:
  996.  *    None.
  997.  *
  998.  * Side effects:
  999.  *    The delayed mouse motion event gets added to the Tcl event
  1000.  *    queue for servicing.
  1001.  *
  1002.  *----------------------------------------------------------------------
  1003.  */
  1004.  
  1005. static void
  1006. DelayedMotionProc(clientData)
  1007.     ClientData clientData;    /* Pointer to display containing a delayed
  1008.                  * motion event to be serviced. */
  1009. {
  1010.     TkDisplay *dispPtr = (TkDisplay *) clientData;
  1011.  
  1012.     if (dispPtr->delayedMotionPtr == NULL) {
  1013.     panic("DelayedMotionProc found no delayed mouse motion event");
  1014.     }
  1015.     Tcl_QueueEvent(&dispPtr->delayedMotionPtr->header, TCL_QUEUE_TAIL);
  1016.     dispPtr->delayedMotionPtr = NULL;
  1017. }
  1018.  
  1019. /*
  1020.  *--------------------------------------------------------------
  1021.  *
  1022.  * Tk_MainLoop --
  1023.  *
  1024.  *    Call Tcl_DoOneEvent over and over again in an infinite
  1025.  *    loop as long as there exist any main windows.
  1026.  *
  1027.  * Results:
  1028.  *    None.
  1029.  *
  1030.  * Side effects:
  1031.  *    Arbitrary;  depends on handlers for events.
  1032.  *
  1033.  *--------------------------------------------------------------
  1034.  */
  1035.  
  1036. void
  1037. Tk_MainLoop()
  1038. {
  1039.     while (Tk_GetNumMainWindows() > 0) {
  1040.     Tcl_DoOneEvent(0);
  1041.     }
  1042. }
  1043.