tkEvent.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:43k
源码类别:

通讯编程

开发平台:

Visual C++

  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.  * Copyright (c) 1998-2000 Ajuba Solutions.
  10.  *
  11.  * See the file "license.terms" for information on usage and redistribution
  12.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  13.  *
  14.  * RCS: @(#) $Id: tkEvent.c,v 1.17.2.8 2006/01/20 18:42:04 jenglish Exp $
  15.  */
  16. #include "tkPort.h"
  17. #include "tkInt.h"
  18. #include <signal.h>
  19. /*
  20.  * There's a potential problem if a handler is deleted while it's
  21.  * current (i.e. its procedure is executing), since Tk_HandleEvent
  22.  * will need to read the handler's "nextPtr" field when the procedure
  23.  * returns.  To handle this problem, structures of the type below
  24.  * indicate the next handler to be processed for any (recursively
  25.  * nested) dispatches in progress.  The nextHandler fields get
  26.  * updated if the handlers pointed to are deleted.  Tk_HandleEvent
  27.  * also needs to know if the entire window gets deleted;  the winPtr
  28.  * field is set to zero if that particular window gets deleted.
  29.  */
  30. typedef struct InProgress {
  31.     XEvent *eventPtr;  /* Event currently being handled. */
  32.     TkWindow *winPtr;  /* Window for event.  Gets set to None if
  33.   * window is deleted while event is being
  34.   * handled. */
  35.     TkEventHandler *nextHandler; /* Next handler in search. */
  36.     struct InProgress *nextPtr;  /* Next higher nested search. */
  37. } InProgress;
  38. /*
  39.  * For each call to Tk_CreateGenericHandler, an instance of the following
  40.  * structure will be created.  All of the active handlers are linked into a
  41.  * list.
  42.  */
  43. typedef struct GenericHandler {
  44.     Tk_GenericProc *proc; /* Procedure to dispatch on all X events. */
  45.     ClientData clientData; /* Client data to pass to procedure. */
  46.     int deleteFlag; /* Flag to set when this handler is deleted. */
  47.     struct GenericHandler *nextPtr;
  48. /* Next handler in list of all generic
  49.  * handlers, or NULL for end of list. */
  50. } GenericHandler;
  51. /*
  52.  * There's a potential problem if Tk_HandleEvent is entered recursively.
  53.  * A handler cannot be deleted physically until we have returned from
  54.  * calling it.  Otherwise, we're looking at unallocated memory in advancing to
  55.  * its `next' entry.  We deal with the problem by using the `delete flag' and
  56.  * deleting handlers only when it's known that there's no handler active.
  57.  *
  58.  */
  59. /*
  60.  * The following structure is used for queueing X-style events on the
  61.  * Tcl event queue.
  62.  */
  63. typedef struct TkWindowEvent {
  64.     Tcl_Event header; /* Standard information for all events. */
  65.     XEvent event; /* The X event. */
  66. } TkWindowEvent;
  67. /*
  68.  * Array of event masks corresponding to each X event:
  69.  */
  70. static unsigned long eventMasks[TK_LASTEVENT] = {
  71.     0,
  72.     0,
  73.     KeyPressMask, /* KeyPress */
  74.     KeyReleaseMask, /* KeyRelease */
  75.     ButtonPressMask, /* ButtonPress */
  76.     ButtonReleaseMask, /* ButtonRelease */
  77.     PointerMotionMask|PointerMotionHintMask|ButtonMotionMask
  78.     |Button1MotionMask|Button2MotionMask|Button3MotionMask
  79.     |Button4MotionMask|Button5MotionMask,
  80. /* MotionNotify */
  81.     EnterWindowMask, /* EnterNotify */
  82.     LeaveWindowMask, /* LeaveNotify */
  83.     FocusChangeMask, /* FocusIn */
  84.     FocusChangeMask, /* FocusOut */
  85.     KeymapStateMask, /* KeymapNotify */
  86.     ExposureMask, /* Expose */
  87.     ExposureMask, /* GraphicsExpose */
  88.     ExposureMask, /* NoExpose */
  89.     VisibilityChangeMask, /* VisibilityNotify */
  90.     SubstructureNotifyMask, /* CreateNotify */
  91.     StructureNotifyMask, /* DestroyNotify */
  92.     StructureNotifyMask, /* UnmapNotify */
  93.     StructureNotifyMask, /* MapNotify */
  94.     SubstructureRedirectMask, /* MapRequest */
  95.     StructureNotifyMask, /* ReparentNotify */
  96.     StructureNotifyMask, /* ConfigureNotify */
  97.     SubstructureRedirectMask, /* ConfigureRequest */
  98.     StructureNotifyMask, /* GravityNotify */
  99.     ResizeRedirectMask, /* ResizeRequest */
  100.     StructureNotifyMask, /* CirculateNotify */
  101.     SubstructureRedirectMask, /* CirculateRequest */
  102.     PropertyChangeMask, /* PropertyNotify */
  103.     0, /* SelectionClear */
  104.     0, /* SelectionRequest */
  105.     0, /* SelectionNotify */
  106.     ColormapChangeMask, /* ColormapNotify */
  107.     0, /* ClientMessage */
  108.     0, /* Mapping Notify */
  109.     VirtualEventMask, /* VirtualEvents */
  110.     ActivateMask, /* ActivateNotify */
  111.     ActivateMask, /* DeactivateNotify */
  112.     MouseWheelMask /* MouseWheelEvent */
  113. };
  114. /*
  115.  * The structure below is used to store Data for the Event module that
  116.  * must be kept thread-local.  The "dataKey" is used to fetch the 
  117.  * thread-specific storage for the current thread.
  118.  */
  119. typedef struct ThreadSpecificData {
  120.     int handlersActive; /* The following variable has a non-zero 
  121.  * value when a handler is active. */
  122.     InProgress *pendingPtr; /* Topmost search in progress, or
  123.  * NULL if none. */
  124.     GenericHandler *genericList; /* First handler in the list, or NULL. */
  125.     GenericHandler *lastGenericPtr; /* Last handler in list. */
  126.     GenericHandler *cmList; /* First handler in the list, or NULL. */
  127.     GenericHandler *lastCmPtr; /* Last handler in list. */
  128.     /*
  129.      * If someone has called Tk_RestrictEvents, the information below
  130.      * keeps track of it.
  131.      */
  132.     Tk_RestrictProc *restrictProc;
  133. /* Procedure to call.  NULL means no
  134.  * restrictProc is currently in effect. */
  135.     ClientData restrictArg; /* Argument to pass to restrictProc. */
  136. } ThreadSpecificData;
  137. static Tcl_ThreadDataKey dataKey;
  138. /*
  139.  * Prototypes for procedures that are only referenced locally within
  140.  * this file.
  141.  */
  142. static void DelayedMotionProc _ANSI_ARGS_((ClientData clientData));
  143. static int WindowEventProc _ANSI_ARGS_((Tcl_Event *evPtr,
  144.     int flags));
  145. static int TkXErrorHandler _ANSI_ARGS_((ClientData clientData,
  146.     XErrorEvent *errEventPtr));
  147. /*
  148.  *--------------------------------------------------------------
  149.  *
  150.  * Tk_CreateEventHandler --
  151.  *
  152.  * Arrange for a given procedure to be invoked whenever
  153.  * events from a given class occur in a given window.
  154.  *
  155.  * Results:
  156.  * None.
  157.  *
  158.  * Side effects:
  159.  * From now on, whenever an event of the type given by
  160.  * mask occurs for token and is processed by Tk_HandleEvent,
  161.  * proc will be called.  See the manual entry for details
  162.  * of the calling sequence and return value for proc.
  163.  *
  164.  *--------------------------------------------------------------
  165.  */
  166. void
  167. Tk_CreateEventHandler(token, mask, proc, clientData)
  168.     Tk_Window token; /* Token for window in which to
  169.  * create handler. */
  170.     unsigned long mask; /* Events for which proc should
  171.  * be called. */
  172.     Tk_EventProc *proc; /* Procedure to call for each
  173.  * selected event */
  174.     ClientData clientData; /* Arbitrary data to pass to proc. */
  175. {
  176.     register TkEventHandler *handlerPtr;
  177.     register TkWindow *winPtr = (TkWindow *) token;
  178.     int found;
  179.     /*
  180.      * Skim through the list of existing handlers to (a) compute the
  181.      * overall event mask for the window (so we can pass this new
  182.      * value to the X system) and (b) see if there's already a handler
  183.      * declared with the same callback and clientData (if so, just
  184.      * change the mask).  If no existing handler matches, then create
  185.      * a new handler.
  186.      */
  187.     found = 0;
  188.     if (winPtr->handlerList == NULL) {
  189. handlerPtr = (TkEventHandler *) ckalloc(
  190. (unsigned) sizeof(TkEventHandler));
  191. winPtr->handlerList = handlerPtr;
  192. goto initHandler;
  193.     } else {
  194. for (handlerPtr = winPtr->handlerList; ;
  195. handlerPtr = handlerPtr->nextPtr) {
  196.     if ((handlerPtr->proc == proc)
  197.     && (handlerPtr->clientData == clientData)) {
  198. handlerPtr->mask = mask;
  199. found = 1;
  200.     }
  201.     if (handlerPtr->nextPtr == NULL) {
  202. break;
  203.     }
  204. }
  205.     }
  206.     /*
  207.      * Create a new handler if no matching old handler was found.
  208.      */
  209.     if (!found) {
  210. handlerPtr->nextPtr = (TkEventHandler *)
  211. ckalloc(sizeof(TkEventHandler));
  212. handlerPtr = handlerPtr->nextPtr;
  213. initHandler:
  214. handlerPtr->mask = mask;
  215. handlerPtr->proc = proc;
  216. handlerPtr->clientData = clientData;
  217. handlerPtr->nextPtr = NULL;
  218.     }
  219.     /*
  220.      * No need to call XSelectInput:  Tk always selects on all events
  221.      * for all windows (needed to support bindings on classes and "all").
  222.      */
  223. }
  224. /*
  225.  *--------------------------------------------------------------
  226.  *
  227.  * Tk_DeleteEventHandler --
  228.  *
  229.  * Delete a previously-created handler.
  230.  *
  231.  * Results:
  232.  * None.
  233.  *
  234.  * Side effects:
  235.  * If there existed a handler as described by the
  236.  * parameters, the handler is deleted so that proc
  237.  * will not be invoked again.
  238.  *
  239.  *--------------------------------------------------------------
  240.  */
  241. void
  242. Tk_DeleteEventHandler(token, mask, proc, clientData)
  243.     Tk_Window token; /* Same as corresponding arguments passed */
  244.     unsigned long mask; /* previously to Tk_CreateEventHandler. */
  245.     Tk_EventProc *proc;
  246.     ClientData clientData;
  247. {
  248.     register TkEventHandler *handlerPtr;
  249.     register InProgress *ipPtr;
  250.     TkEventHandler *prevPtr;
  251.     register TkWindow *winPtr = (TkWindow *) token;
  252.     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
  253.             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  254.     /*
  255.      * Find the event handler to be deleted, or return
  256.      * immediately if it doesn't exist.
  257.      */
  258.     for (handlerPtr = winPtr->handlerList, prevPtr = NULL; ;
  259.     prevPtr = handlerPtr, handlerPtr = handlerPtr->nextPtr) {
  260. if (handlerPtr == NULL) {
  261.     return;
  262. }
  263. if ((handlerPtr->mask == mask) && (handlerPtr->proc == proc)
  264. && (handlerPtr->clientData == clientData)) {
  265.     break;
  266. }
  267.     }
  268.     /*
  269.      * If Tk_HandleEvent is about to process this handler, tell it to
  270.      * process the next one instead.
  271.      */
  272.     for (ipPtr = tsdPtr->pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) {
  273. if (ipPtr->nextHandler == handlerPtr) {
  274.     ipPtr->nextHandler = handlerPtr->nextPtr;
  275. }
  276.     }
  277.     /*
  278.      * Free resources associated with the handler.
  279.      */
  280.     if (prevPtr == NULL) {
  281. winPtr->handlerList = handlerPtr->nextPtr;
  282.     } else {
  283. prevPtr->nextPtr = handlerPtr->nextPtr;
  284.     }
  285.     ckfree((char *) handlerPtr);
  286.     /*
  287.      * No need to call XSelectInput:  Tk always selects on all events
  288.      * for all windows (needed to support bindings on classes and "all").
  289.      */
  290. }
  291. /*--------------------------------------------------------------
  292.  *
  293.  * Tk_CreateGenericHandler --
  294.  *
  295.  * Register a procedure to be called on each X event, regardless
  296.  * of display or window.  Generic handlers are useful for capturing
  297.  * events that aren't associated with windows, or events for windows
  298.  * not managed by Tk.
  299.  *
  300.  * Results:
  301.  * None.
  302.  *
  303.  * Side Effects:
  304.  * From now on, whenever an X event is given to Tk_HandleEvent,
  305.  * invoke proc, giving it clientData and the event as arguments.
  306.  *
  307.  *--------------------------------------------------------------
  308.  */
  309. void
  310. Tk_CreateGenericHandler(proc, clientData)
  311.      Tk_GenericProc *proc; /* Procedure to call on every event. */
  312.      ClientData clientData; /* One-word value to pass to proc. */
  313. {
  314.     GenericHandler *handlerPtr;
  315.     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
  316.             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  317.     
  318.     handlerPtr = (GenericHandler *) ckalloc (sizeof (GenericHandler));
  319.     
  320.     handlerPtr->proc = proc;
  321.     handlerPtr->clientData = clientData;
  322.     handlerPtr->deleteFlag = 0;
  323.     handlerPtr->nextPtr = NULL;
  324.     if (tsdPtr->genericList == NULL) {
  325. tsdPtr->genericList = handlerPtr;
  326.     } else {
  327. tsdPtr->lastGenericPtr->nextPtr = handlerPtr;
  328.     }
  329.     tsdPtr->lastGenericPtr = handlerPtr;
  330. }
  331. /*
  332.  *--------------------------------------------------------------
  333.  *
  334.  * Tk_DeleteGenericHandler --
  335.  *
  336.  * Delete a previously-created generic handler.
  337.  *
  338.  * Results:
  339.  * None.
  340.  *
  341.  * Side Effects:
  342.  * If there existed a handler as described by the parameters,
  343.  * that handler is logically deleted so that proc will not be
  344.  * invoked again.  The physical deletion happens in the event
  345.  * loop in Tk_HandleEvent.
  346.  *
  347.  *--------------------------------------------------------------
  348.  */
  349. void
  350. Tk_DeleteGenericHandler(proc, clientData)
  351.      Tk_GenericProc *proc;
  352.      ClientData clientData;
  353. {
  354.     GenericHandler * handler;
  355.     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
  356. Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  357.     
  358.     for (handler = tsdPtr->genericList; handler; handler = handler->nextPtr) {
  359. if ((handler->proc == proc) && (handler->clientData == clientData)) {
  360.     handler->deleteFlag = 1;
  361. }
  362.     }
  363. }
  364. /*--------------------------------------------------------------
  365.  *
  366.  * Tk_CreateClientMessageHandler --
  367.  *
  368.  * Register a procedure to be called on each ClientMessage event.
  369.  * ClientMessage handlers are useful for Drag&Drop extensions.
  370.  *
  371.  * Results:
  372.  * None.
  373.  *
  374.  * Side Effects:
  375.  * From now on, whenever a ClientMessage event is received that isn't
  376.  * a WM_PROTOCOL event or SelectionEvent, invoke proc, giving it
  377.  * tkwin and the event as arguments.
  378.  *
  379.  *--------------------------------------------------------------
  380.  */
  381. void
  382. Tk_CreateClientMessageHandler(proc)
  383.      Tk_ClientMessageProc *proc; /* Procedure to call on event. */
  384. {
  385.     GenericHandler *handlerPtr;
  386.     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
  387. Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  388.     /*
  389.      * We use a GenericHandler struct, because it's basically the same,
  390.      * except with an extra clientData field we'll never use.
  391.      */
  392.     handlerPtr = (GenericHandler *)
  393. ckalloc (sizeof (GenericHandler));
  394.     handlerPtr->proc = (Tk_GenericProc *) proc;
  395.     handlerPtr->clientData = NULL; /* never used */
  396.     handlerPtr->deleteFlag = 0;
  397.     handlerPtr->nextPtr = NULL;
  398.     if (tsdPtr->cmList == NULL) {
  399. tsdPtr->cmList = handlerPtr;
  400.     } else {
  401. tsdPtr->lastCmPtr->nextPtr = handlerPtr;
  402.     }
  403.     tsdPtr->lastCmPtr = handlerPtr;
  404. }
  405. /*
  406.  *--------------------------------------------------------------
  407.  *
  408.  * Tk_DeleteClientMessageHandler --
  409.  *
  410.  * Delete a previously-created ClientMessage handler.
  411.  *
  412.  * Results:
  413.  * None.
  414.  *
  415.  * Side Effects:
  416.  * If there existed a handler as described by the parameters,
  417.  * that handler is logically deleted so that proc will not be
  418.  * invoked again.  The physical deletion happens in the event
  419.  * loop in TkClientMessageEventProc.
  420.  *
  421.  *--------------------------------------------------------------
  422.  */
  423. void
  424. Tk_DeleteClientMessageHandler(proc)
  425.      Tk_ClientMessageProc *proc;
  426. {
  427.     GenericHandler * handler;
  428.     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
  429. Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  430.     for (handler = tsdPtr->cmList; handler != NULL;
  431.  handler = handler->nextPtr) {
  432. if (handler->proc == (Tk_GenericProc *) proc) {
  433.     handler->deleteFlag = 1;
  434. }
  435.     }
  436. }
  437. /*
  438.  *--------------------------------------------------------------
  439.  *
  440.  * TkEventInit --
  441.  *
  442.  * This procedures initializes all the event module 
  443.  *      structures used by the current thread.  It must be
  444.  *      called before any other procedure in this file is 
  445.  *      called.
  446.  *
  447.  * Results:
  448.  * None.
  449.  *
  450.  * Side Effects:
  451.  * None.
  452.  *
  453.  *--------------------------------------------------------------
  454.  */
  455. void
  456. TkEventInit _ANSI_ARGS_((void))
  457. {
  458.     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
  459. Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  460.     tsdPtr->handlersActive = 0;
  461.     tsdPtr->pendingPtr = NULL;
  462.     tsdPtr->genericList = NULL;
  463.     tsdPtr->lastGenericPtr = NULL;
  464.     tsdPtr->cmList = NULL;
  465.     tsdPtr->lastCmPtr = NULL;
  466.     tsdPtr->restrictProc = NULL;
  467.     tsdPtr->restrictArg = NULL;
  468. }
  469. /*
  470.  *--------------------------------------------------------------
  471.  *
  472.  * TkXErrorHandler --
  473.  *
  474.  * TkXErrorHandler is an error handler, to be installed
  475.  * via Tk_CreateErrorHandler, that will set a flag if an
  476.  * X error occurred.
  477.  *
  478.  * Results:
  479.  * Always returns 0, indicating that the X error was
  480.  * handled.
  481.  *
  482.  * Side effects:
  483.  * None.
  484.  *
  485.  *--------------------------------------------------------------
  486.  */
  487. static int
  488. TkXErrorHandler (clientData, errEventPtr)
  489.     ClientData clientData;      /* Pointer to flag we set       */
  490.     XErrorEvent *errEventPtr;   /* X error info                 */
  491. {
  492.     int *error;
  493.     error = (int *) clientData;
  494.     *error = 1;
  495.     return 0;
  496. }
  497. /*
  498.  *--------------------------------------------------------------
  499.  *
  500.  * ParentXId --
  501.  *
  502.  * Returns the parent of the given window, or "None"
  503.  * if the window doesn't exist.
  504.  *
  505.  * Results:
  506.  * Returns an X window ID.
  507.  *
  508.  * Side effects:
  509.  * None.
  510.  *
  511.  *--------------------------------------------------------------
  512.  */
  513. static Window
  514. ParentXId(display, w)
  515.     Display *display;
  516.     Window w;
  517. {
  518.     Tk_ErrorHandler handler;
  519.     int gotXError;
  520.     Status status;
  521.     Window parent;
  522.     Window root;
  523.     Window *childList;
  524.     unsigned int nChildren;
  525.     /* Handle errors ourselves. */
  526.     gotXError = 0;
  527.     handler = Tk_CreateErrorHandler(display, -1, -1, -1,
  528. TkXErrorHandler, (ClientData) (&gotXError));
  529.     /* Get the parent window. */
  530.     status = XQueryTree(display, w, &root, &parent, &childList, &nChildren);
  531.     /* Do some cleanup; gotta return "None" if we got an error. */
  532.     Tk_DeleteErrorHandler(handler);
  533.     XSync(display, False);
  534.     if (status != 0 && childList != NULL) {
  535. XFree(childList);
  536.     }
  537.     if (status == 0) {
  538.         parent = None;
  539.     }
  540.     return parent;
  541. }
  542. /*
  543.  *--------------------------------------------------------------
  544.  *
  545.  * Tk_HandleEvent --
  546.  *
  547.  * Given an event, invoke all the handlers that have
  548.  * been registered for the event.
  549.  *
  550.  * Results:
  551.  * None.
  552.  *
  553.  * Side effects:
  554.  * Depends on the handlers.
  555.  *
  556.  *--------------------------------------------------------------
  557.  */
  558. void
  559. Tk_HandleEvent(eventPtr)
  560.     XEvent *eventPtr; /* Event to dispatch. */
  561. {
  562.     register TkEventHandler *handlerPtr;
  563.     register GenericHandler *genericPtr;
  564.     register GenericHandler *genPrevPtr;
  565.     TkWindow *winPtr;
  566.     unsigned long mask;
  567.     InProgress ip;
  568.     Window handlerWindow;
  569.     Window parentXId;
  570.     TkDisplay *dispPtr;
  571.     Tcl_Interp *interp = (Tcl_Interp *) NULL;
  572.     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
  573. Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  574.     /*
  575.      * Hack for simulated X-events: Correct the state field
  576.      * of the event record to match with the ButtonPress
  577.      * and ButtonRelease events.
  578.      */
  579.     if (eventPtr->type==ButtonPress) {
  580. dispPtr = TkGetDisplay(eventPtr->xbutton.display);
  581. dispPtr->mouseButtonWindow = eventPtr->xbutton.window;
  582. eventPtr->xbutton.state |= dispPtr->mouseButtonState;
  583. switch (eventPtr->xbutton.button) {
  584.     case 1: dispPtr->mouseButtonState |= Button1Mask; break; 
  585.     case 2: dispPtr->mouseButtonState |= Button2Mask; break; 
  586.     case 3: dispPtr->mouseButtonState |= Button3Mask; break; 
  587. }
  588.     } else if (eventPtr->type==ButtonRelease) {
  589. dispPtr = TkGetDisplay(eventPtr->xbutton.display);
  590. dispPtr->mouseButtonWindow = 0;
  591. switch (eventPtr->xbutton.button) {
  592.     case 1: dispPtr->mouseButtonState &= ~Button1Mask; break; 
  593.     case 2: dispPtr->mouseButtonState &= ~Button2Mask; break; 
  594.     case 3: dispPtr->mouseButtonState &= ~Button3Mask; break; 
  595. }
  596. eventPtr->xbutton.state |= dispPtr->mouseButtonState;
  597.     } else if (eventPtr->type==MotionNotify) {
  598. dispPtr = TkGetDisplay(eventPtr->xmotion.display);
  599. if (dispPtr->mouseButtonState & (Button1Mask|Button2Mask|Button3Mask)) {
  600.     if (eventPtr->xbutton.window != dispPtr->mouseButtonWindow) {
  601.         /*
  602.          * This motion event should not be interpreted as a button
  603.          * press + motion event since this is not the same window
  604.          * the button was pressed down in.
  605.          */
  606.         dispPtr->mouseButtonState &=
  607.                 ~(Button1Mask|Button2Mask|Button3Mask);
  608.         dispPtr->mouseButtonWindow = 0;
  609.     } else {
  610.         eventPtr->xmotion.state |= dispPtr->mouseButtonState;
  611.     }
  612. }
  613.     }
  614.     /* 
  615.      * Next, invoke all the generic event handlers (those that are
  616.      * invoked for all events).  If a generic event handler reports that
  617.      * an event is fully processed, go no further.
  618.      */
  619.     for (genPrevPtr = NULL, genericPtr = tsdPtr->genericList;  
  620.             genericPtr != NULL; ) {
  621. if (genericPtr->deleteFlag) {
  622.     if (!tsdPtr->handlersActive) {
  623. GenericHandler *tmpPtr;
  624. /*
  625.  * This handler needs to be deleted and there are no
  626.  * calls pending through the handler, so now is a safe
  627.  * time to delete it.
  628.  */
  629. tmpPtr = genericPtr->nextPtr;
  630. if (genPrevPtr == NULL) {
  631.     tsdPtr->genericList = tmpPtr;
  632. } else {
  633.     genPrevPtr->nextPtr = tmpPtr;
  634. }
  635. if (tmpPtr == NULL) {
  636.     tsdPtr->lastGenericPtr = genPrevPtr;
  637. }
  638. (void) ckfree((char *) genericPtr);
  639. genericPtr = tmpPtr;
  640. continue;
  641.     }
  642. } else {
  643.     int done;
  644.     tsdPtr->handlersActive++;
  645.     done = (*genericPtr->proc)(genericPtr->clientData, eventPtr);
  646.     tsdPtr->handlersActive--;
  647.     if (done) {
  648. return;
  649.     }
  650. }
  651. genPrevPtr = genericPtr;
  652. genericPtr = genPrevPtr->nextPtr;
  653.     }
  654.     /*
  655.      * If the event is a MappingNotify event, find its display and
  656.      * refresh the keyboard mapping information for the display.
  657.      * After that there's nothing else to do with the event, so just
  658.      * quit.
  659.      */
  660.     if (eventPtr->type == MappingNotify) {
  661. dispPtr = TkGetDisplay(eventPtr->xmapping.display);
  662. if (dispPtr != NULL) {
  663.     XRefreshKeyboardMapping(&eventPtr->xmapping);
  664.     dispPtr->bindInfoStale = 1;
  665. }
  666. return;
  667.     }
  668.     /*
  669.      * Events selected by StructureNotify require special handling.
  670.      * They look the same as those selected by SubstructureNotify.
  671.      * The only difference is whether the "event" and "window" fields
  672.      * are the same.  Compare the two fields and convert StructureNotify
  673.      * to SubstructureNotify if necessary.
  674.      */
  675.     handlerWindow = eventPtr->xany.window;
  676.     mask = eventMasks[eventPtr->xany.type];
  677.     if (mask == StructureNotifyMask) {
  678. if (eventPtr->xmap.event != eventPtr->xmap.window) {
  679.     mask = SubstructureNotifyMask;
  680.     handlerWindow = eventPtr->xmap.event;
  681. }
  682.     }
  683.     winPtr = (TkWindow *) Tk_IdToWindow(eventPtr->xany.display, handlerWindow);
  684.     if (winPtr == NULL) {
  685. /*
  686.  * There isn't a TkWindow structure for this window.
  687.  * However, if the event is a PropertyNotify event then call
  688.  * the selection manager (it deals beneath-the-table with
  689.  * certain properties). Also, if the window's parent is a
  690.  * Tk window that has the TK_PROP_PROPCHANGE flag set, then
  691.  * we must propagate the PropertyNotify event up to the parent.
  692.  */
  693. if (eventPtr->type != PropertyNotify) {
  694.     return;
  695. }
  696. TkSelPropProc(eventPtr);
  697. /* Get handlerWindow's parent. */
  698. parentXId = ParentXId(eventPtr->xany.display, handlerWindow);
  699. if (parentXId == None) {
  700.     return;
  701. }
  702. winPtr = (TkWindow *) Tk_IdToWindow(eventPtr->xany.display, parentXId);
  703. if (winPtr == NULL) {
  704.     return;
  705. }
  706. if (!(winPtr->flags & TK_PROP_PROPCHANGE)) {
  707.     return;
  708. }
  709. handlerWindow = parentXId;
  710.     }
  711.     /*
  712.      * Once a window has started getting deleted, don't process any more
  713.      * events for it except for the DestroyNotify event.  This check is
  714.      * needed because a DestroyNotify handler could re-invoke the event
  715.      * loop, causing other pending events to be handled for the window
  716.      * (the window doesn't get totally expunged from our tables until
  717.      * after the DestroyNotify event has been completely handled).
  718.      */
  719.     if ((winPtr->flags & TK_ALREADY_DEAD)
  720.     && (eventPtr->type != DestroyNotify)) {
  721. return;
  722.     }
  723.     if (winPtr->mainPtr != NULL) {
  724.         /*
  725.          * Protect interpreter for this window from possible deletion
  726.          * while we are dealing with the event for this window. Thus,
  727.          * widget writers do not have to worry about protecting the
  728.          * interpreter in their own code.
  729.          */
  730.         
  731.         interp = winPtr->mainPtr->interp;
  732.         Tcl_Preserve((ClientData) interp);
  733.         
  734. /*
  735.  * Call focus-related code to look at FocusIn, FocusOut, Enter,
  736.  * and Leave events;  depending on its return value, ignore the
  737.  * event.
  738.  */
  739.     
  740. if ((mask & (FocusChangeMask|EnterWindowMask|LeaveWindowMask))
  741. && !TkFocusFilterEvent(winPtr, eventPtr)) {
  742.             Tcl_Release((ClientData) interp);
  743.     return;
  744. }
  745.     
  746. /*
  747.  * Redirect KeyPress and KeyRelease events to the focus window,
  748.  * or ignore them entirely if there is no focus window.  We also
  749.  * route the MouseWheel event to the focus window.  The MouseWheel
  750.  * event is an extension to the X event set.  Currently, it is only
  751.  * available on the Windows version of Tk.
  752.  */
  753.     
  754. #ifdef MAC_OSX_TK
  755.         /* MouseWheel events are not focus specific on Mac OS X */
  756. if (mask & (KeyPressMask|KeyReleaseMask)) {
  757. #else
  758. if (mask & (KeyPressMask|KeyReleaseMask|MouseWheelMask)) {
  759. #endif
  760.     winPtr->dispPtr->lastEventTime = eventPtr->xkey.time;
  761.     winPtr = TkFocusKeyEvent(winPtr, eventPtr);
  762.     if (winPtr == NULL) {
  763.                 Tcl_Release((ClientData) interp);
  764. return;
  765.     }
  766. }
  767.     
  768. /*
  769.  * Call a grab-related procedure to do special processing on
  770.  * pointer events.
  771.  */
  772.     
  773. if (mask & (ButtonPressMask|ButtonReleaseMask|PointerMotionMask
  774. |EnterWindowMask|LeaveWindowMask)) {
  775.     if (mask & (ButtonPressMask|ButtonReleaseMask)) {
  776. winPtr->dispPtr->lastEventTime = eventPtr->xbutton.time;
  777.     } else if (mask & PointerMotionMask) {
  778. winPtr->dispPtr->lastEventTime = eventPtr->xmotion.time;
  779.     } else {
  780. winPtr->dispPtr->lastEventTime = eventPtr->xcrossing.time;
  781.     }
  782.     if (TkPointerEvent(eventPtr, winPtr) == 0) {
  783.                 goto done;
  784.     }
  785. }
  786.     }
  787. #ifdef TK_USE_INPUT_METHODS
  788.     /*
  789.      * Pass the event to the input method(s), if there are any, and
  790.      * discard the event if the input method(s) insist.  Create the
  791.      * input context for the window if it hasn't already been done
  792.      * (XFilterEvent needs this context).  XIM is only ever enabled on
  793.      * Unix, but this hasn't been factored out of the generic code yet.
  794.      */
  795.     dispPtr = winPtr->dispPtr;
  796.     if ((dispPtr->flags & TK_DISPLAY_USE_IM)) {
  797. long im_event_mask = 0L;
  798. if (!(winPtr->flags & (TK_CHECKED_IC|TK_ALREADY_DEAD))) {
  799.     winPtr->flags |= TK_CHECKED_IC;
  800.     if (dispPtr->inputMethod != NULL) {
  801. #if TK_XIM_SPOT
  802. if (dispPtr->flags & TK_DISPLAY_XIM_SPOT) {
  803.     XVaNestedList preedit_attr;
  804.     XPoint spot = {0, 0};
  805.     if (dispPtr->inputXfs == NULL) {
  806. /*
  807.  * We only need to create one XFontSet
  808.  */
  809. char      **missing_list;
  810. int       missing_count;
  811. char      *def_string;
  812. dispPtr->inputXfs = XCreateFontSet(dispPtr->display,
  813. "-*-*-*-R-Normal--14-130-75-75-*-*",
  814. &missing_list, &missing_count, &def_string);
  815. if (missing_count > 0) {
  816.     XFreeStringList(missing_list);
  817. }
  818.     }
  819.     preedit_attr = XVaCreateNestedList(0, XNSpotLocation,
  820.     &spot, XNFontSet, dispPtr->inputXfs, NULL);
  821.     if (winPtr->inputContext != NULL)
  822.         panic("inputContext not NULL");
  823.     winPtr->inputContext = XCreateIC(dispPtr->inputMethod,
  824.     XNInputStyle, XIMPreeditPosition|XIMStatusNothing,
  825.     XNClientWindow, winPtr->window,
  826.     XNFocusWindow, winPtr->window,
  827.     XNPreeditAttributes, preedit_attr,
  828.     NULL);
  829.     XFree(preedit_attr);
  830. } else {
  831.     if (winPtr->inputContext != NULL)
  832.         panic("inputContext not NULL");
  833.     winPtr->inputContext = XCreateIC(dispPtr->inputMethod,
  834.     XNInputStyle, XIMPreeditNothing|XIMStatusNothing,
  835.     XNClientWindow, winPtr->window,
  836.     XNFocusWindow, winPtr->window,
  837.     NULL);
  838. }
  839. #else
  840. if (winPtr->inputContext != NULL)
  841.     panic("inputContext not NULL");
  842. winPtr->inputContext = XCreateIC(dispPtr->inputMethod,
  843. XNInputStyle, XIMPreeditNothing|XIMStatusNothing,
  844. XNClientWindow, winPtr->window,
  845. XNFocusWindow, winPtr->window,
  846. NULL);
  847. #endif
  848.     }
  849. }
  850. if (winPtr->inputContext != NULL &&
  851.     (eventPtr->xany.type == FocusIn)) {
  852.     XGetICValues(winPtr->inputContext,
  853.  XNFilterEvents, &im_event_mask, NULL);
  854.     if (im_event_mask != 0L) {
  855. XSelectInput(winPtr->display, winPtr->window,
  856.      winPtr->atts.event_mask | im_event_mask);
  857. XSetICFocus(winPtr->inputContext);
  858.     }
  859. }
  860. if (eventPtr->type == KeyPress || eventPtr->type == KeyRelease) {
  861.     if (XFilterEvent(eventPtr, None)) {
  862. goto done;
  863.     }
  864. }
  865.     }
  866. #endif /* TK_USE_INPUT_METHODS */
  867.     /*
  868.      * For events where it hasn't already been done, update the current
  869.      * time in the display.
  870.      */
  871.     if (eventPtr->type == PropertyNotify) {
  872. winPtr->dispPtr->lastEventTime = eventPtr->xproperty.time;
  873.     }
  874.     /*
  875.      * There's a potential interaction here with Tk_DeleteEventHandler.
  876.      * Read the documentation for pendingPtr.
  877.      */
  878.     ip.eventPtr = eventPtr;
  879.     ip.winPtr = winPtr;
  880.     ip.nextHandler = NULL;
  881.     ip.nextPtr = tsdPtr->pendingPtr;
  882.     tsdPtr->pendingPtr = &ip;
  883.     if (mask == 0) {
  884. if ((eventPtr->type == SelectionClear)
  885. || (eventPtr->type == SelectionRequest)
  886. || (eventPtr->type == SelectionNotify)) {
  887.     TkSelEventProc((Tk_Window) winPtr, eventPtr);
  888. } else if (eventPtr->type == ClientMessage) {
  889.     if (eventPtr->xclient.message_type ==
  890.     Tk_InternAtom((Tk_Window) winPtr, "WM_PROTOCOLS")) {
  891. TkWmProtocolEventProc(winPtr, eventPtr);
  892.     } else {
  893. /*
  894.  * Finally, invoke any ClientMessage event handlers.
  895.  */
  896. for (genPrevPtr = NULL, genericPtr = tsdPtr->cmList;
  897.      genericPtr != NULL; ) {
  898.     if (genericPtr->deleteFlag) {
  899. if (!tsdPtr->handlersActive) {
  900.     GenericHandler *tmpPtr;
  901.     /*
  902.      * This handler needs to be deleted and there are
  903.      * no calls pending through any handlers, so now
  904.      * is a safe time to delete it.
  905.      */
  906.     tmpPtr = genericPtr->nextPtr;
  907.     if (genPrevPtr == NULL) {
  908. tsdPtr->cmList = tmpPtr;
  909.     } else {
  910. genPrevPtr->nextPtr = tmpPtr;
  911.     }
  912.     if (tmpPtr == NULL) {
  913. tsdPtr->lastCmPtr = genPrevPtr;
  914.     }
  915.     (void) ckfree((char *) genericPtr);
  916.     genericPtr = tmpPtr;
  917.     continue;
  918. }
  919.     } else {
  920. int done;
  921. tsdPtr->handlersActive++;
  922. done = (*(Tk_ClientMessageProc *)genericPtr->proc)
  923.     ((Tk_Window) winPtr, eventPtr);
  924. tsdPtr->handlersActive--;
  925. if (done) {
  926.     break;
  927. }
  928.     }
  929.     genPrevPtr = genericPtr;
  930.     genericPtr = genPrevPtr->nextPtr;
  931. }
  932.     }
  933. }
  934.     } else {
  935. for (handlerPtr = winPtr->handlerList; handlerPtr != NULL; ) {
  936.     if ((handlerPtr->mask & mask) != 0) {
  937. ip.nextHandler = handlerPtr->nextPtr;
  938. (*(handlerPtr->proc))(handlerPtr->clientData, eventPtr);
  939. handlerPtr = ip.nextHandler;
  940.     } else {
  941. handlerPtr = handlerPtr->nextPtr;
  942.     }
  943. }
  944. /*
  945.  * Pass the event to the "bind" command mechanism.  But, don't
  946.  * do this for SubstructureNotify events.  The "bind" command
  947.  * doesn't support them anyway, and it's easier to filter out
  948.  * these events here than in the lower-level procedures.
  949.  */
  950. /*
  951.  * ...well, except when we use the tkwm patches, in which case
  952.  * we DO handle CreateNotify events, so we gotta pass 'em through.
  953.  */
  954. if ((ip.winPtr != None)
  955. && ((mask != SubstructureNotifyMask)
  956. || (eventPtr->type == CreateNotify))) {
  957.     TkBindEventProc(winPtr, eventPtr);
  958. }
  959.     }
  960.     tsdPtr->pendingPtr = ip.nextPtr;
  961. done:
  962.     /*
  963.      * Release the interpreter for this window so that it can be potentially
  964.      * deleted if requested.
  965.      */
  966.     
  967.     if (interp != (Tcl_Interp *) NULL) {
  968.         Tcl_Release((ClientData) interp);
  969.     }
  970. }
  971. /*
  972.  *--------------------------------------------------------------
  973.  *
  974.  * TkEventDeadWindow --
  975.  *
  976.  * This procedure is invoked when it is determined that
  977.  * a window is dead.  It cleans up event-related information
  978.  * about the window.
  979.  *
  980.  * Results:
  981.  * None.
  982.  *
  983.  * Side effects:
  984.  * Various things get cleaned up and recycled.
  985.  *
  986.  *--------------------------------------------------------------
  987.  */
  988. void
  989. TkEventDeadWindow(winPtr)
  990.     TkWindow *winPtr; /* Information about the window
  991.  * that is being deleted. */
  992. {
  993.     register TkEventHandler *handlerPtr;
  994.     register InProgress *ipPtr;
  995.     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
  996.             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  997.     /*
  998.      * While deleting all the handlers, be careful to check for
  999.      * Tk_HandleEvent being about to process one of the deleted
  1000.      * handlers.  If it is, tell it to quit (all of the handlers
  1001.      * are being deleted).
  1002.      */
  1003.     while (winPtr->handlerList != NULL) {
  1004. handlerPtr = winPtr->handlerList;
  1005. winPtr->handlerList = handlerPtr->nextPtr;
  1006. for (ipPtr = tsdPtr->pendingPtr; ipPtr != NULL; 
  1007.                 ipPtr = ipPtr->nextPtr) {
  1008.     if (ipPtr->nextHandler == handlerPtr) {
  1009. ipPtr->nextHandler = NULL;
  1010.     }
  1011.     if (ipPtr->winPtr == winPtr) {
  1012. ipPtr->winPtr = None;
  1013.     }
  1014. }
  1015. ckfree((char *) handlerPtr);
  1016.     }
  1017. }
  1018. /*
  1019.  *----------------------------------------------------------------------
  1020.  *
  1021.  * TkCurrentTime --
  1022.  *
  1023.  * Try to deduce the current time.  "Current time" means the time
  1024.  * of the event that led to the current code being executed, which
  1025.  * means the time in the most recently-nested invocation of
  1026.  * Tk_HandleEvent.
  1027.  *
  1028.  * Results:
  1029.  * The return value is the time from the current event, or
  1030.  * CurrentTime if there is no current event or if the current
  1031.  * event contains no time.
  1032.  *
  1033.  * Side effects:
  1034.  * None.
  1035.  *
  1036.  *----------------------------------------------------------------------
  1037.  */
  1038. Time
  1039. TkCurrentTime(dispPtr)
  1040.     TkDisplay *dispPtr; /* Display for which the time is desired. */
  1041. {
  1042.     register XEvent *eventPtr;
  1043.     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
  1044.             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  1045.     if (tsdPtr->pendingPtr == NULL) {
  1046. return dispPtr->lastEventTime;
  1047.     }
  1048.     eventPtr = tsdPtr->pendingPtr->eventPtr;
  1049.     switch (eventPtr->type) {
  1050. case ButtonPress:
  1051. case ButtonRelease:
  1052.     return eventPtr->xbutton.time;
  1053. case KeyPress:
  1054. case KeyRelease:
  1055.     return eventPtr->xkey.time;
  1056. case MotionNotify:
  1057.     return eventPtr->xmotion.time;
  1058. case EnterNotify:
  1059. case LeaveNotify:
  1060.     return eventPtr->xcrossing.time;
  1061. case PropertyNotify:
  1062.     return eventPtr->xproperty.time;
  1063.     }
  1064.     return dispPtr->lastEventTime;
  1065. }
  1066. /*
  1067.  *----------------------------------------------------------------------
  1068.  *
  1069.  * Tk_RestrictEvents --
  1070.  *
  1071.  * This procedure is used to globally restrict the set of events
  1072.  * that will be dispatched.  The restriction is done by filtering
  1073.  * all incoming X events through a procedure that determines
  1074.  * whether they are to be processed immediately, deferred, or
  1075.  * discarded.
  1076.  *
  1077.  * Results:
  1078.  * The return value is the previous restriction procedure in effect,
  1079.  * if there was one, or NULL if there wasn't.
  1080.  *
  1081.  * Side effects:
  1082.  * From now on, proc will be called to determine whether to process,
  1083.  * defer or discard each incoming X event.
  1084.  *
  1085.  *----------------------------------------------------------------------
  1086.  */
  1087. Tk_RestrictProc *
  1088. Tk_RestrictEvents(proc, arg, prevArgPtr)
  1089.     Tk_RestrictProc *proc; /* Procedure to call for each incoming
  1090.  * event. */
  1091.     ClientData arg; /* Arbitrary argument to pass to proc. */
  1092.     ClientData *prevArgPtr; /* Place to store information about previous
  1093.  * argument. */
  1094. {
  1095.     Tk_RestrictProc *prev;
  1096.     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
  1097.             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  1098.     prev = tsdPtr->restrictProc;
  1099.     *prevArgPtr = tsdPtr->restrictArg;
  1100.     tsdPtr->restrictProc = proc;
  1101.     tsdPtr->restrictArg = arg;
  1102.     return prev;
  1103. }
  1104. /*
  1105.  *----------------------------------------------------------------------
  1106.  *
  1107.  * Tk_CollapseMotionEvents --
  1108.  *
  1109.  * This procedure controls whether we collapse motion events in a
  1110.  * particular display or not.
  1111.  *
  1112.  * Results:
  1113.  * The return value is the previous collapse value in effect.
  1114.  *
  1115.  * Side effects:
  1116.  * Filtering of motion events may be changed after calling this.
  1117.  *
  1118.  *----------------------------------------------------------------------
  1119.  */
  1120. int
  1121. Tk_CollapseMotionEvents(display, collapse)
  1122.     Display *display; /* Display handling these events. */
  1123.     int collapse; /* boolean value that specifies whether
  1124.  * motion events should be collapsed. */
  1125. {
  1126.     TkDisplay *dispPtr = (TkDisplay *) display;
  1127.     int prev = (dispPtr->flags & TK_DISPLAY_COLLAPSE_MOTION_EVENTS);
  1128.     if (collapse) {
  1129. dispPtr->flags |= TK_DISPLAY_COLLAPSE_MOTION_EVENTS;
  1130.     } else {
  1131. dispPtr->flags &= ~TK_DISPLAY_COLLAPSE_MOTION_EVENTS;
  1132.     }
  1133.     return prev;
  1134. }
  1135. /*
  1136.  *----------------------------------------------------------------------
  1137.  *
  1138.  * Tk_QueueWindowEvent --
  1139.  *
  1140.  * Given an X-style window event, this procedure adds it to the
  1141.  * Tcl event queue at the given position.  This procedure also
  1142.  * performs mouse motion event collapsing if possible.
  1143.  *
  1144.  * Results:
  1145.  * None.
  1146.  *
  1147.  * Side effects:
  1148.  * Adds stuff to the event queue, which will eventually be
  1149.  * processed.
  1150.  *
  1151.  *----------------------------------------------------------------------
  1152.  */
  1153. void
  1154. Tk_QueueWindowEvent(eventPtr, position)
  1155.     XEvent *eventPtr; /* Event to add to queue.  This
  1156.  * procedures copies it before adding
  1157.  * it to the queue. */
  1158.     Tcl_QueuePosition position; /* Where to put it on the queue:
  1159.  * TCL_QUEUE_TAIL, TCL_QUEUE_HEAD,
  1160.  * or TCL_QUEUE_MARK. */
  1161. {
  1162.     TkWindowEvent *wevPtr;
  1163.     TkDisplay *dispPtr;
  1164.     /*
  1165.      * Find our display structure for the event's display.
  1166.      */
  1167.     for (dispPtr = TkGetDisplayList(); ; dispPtr = dispPtr->nextPtr) {
  1168. if (dispPtr == NULL) {
  1169.     return;
  1170. }
  1171. if (dispPtr->display == eventPtr->xany.display) {
  1172.     break;
  1173. }
  1174.     }
  1175.     /*
  1176.      * Don't filter motion events if the user 
  1177.      * defaulting to true (1), which could be set to false (0) when the
  1178.      * user wishes to receive all the motion data)
  1179.      */
  1180.     if (!(dispPtr->flags & TK_DISPLAY_COLLAPSE_MOTION_EVENTS)) {
  1181. wevPtr = (TkWindowEvent *) ckalloc(sizeof(TkWindowEvent));
  1182. wevPtr->header.proc = WindowEventProc;
  1183. wevPtr->event = *eventPtr;
  1184. Tcl_QueueEvent(&wevPtr->header, position);
  1185. return;
  1186.     }
  1187.     if ((dispPtr->delayedMotionPtr != NULL) && (position == TCL_QUEUE_TAIL)) {
  1188. if ((eventPtr->type == MotionNotify) && (eventPtr->xmotion.window
  1189. == dispPtr->delayedMotionPtr->event.xmotion.window)) {
  1190.     /*
  1191.      * The new event is a motion event in the same window as the
  1192.      * saved motion event.  Just replace the saved event with the
  1193.      * new one.
  1194.      */
  1195.     dispPtr->delayedMotionPtr->event = *eventPtr;
  1196.     return;
  1197. } else if ((eventPtr->type != GraphicsExpose)
  1198. && (eventPtr->type != NoExpose)
  1199. && (eventPtr->type != Expose)) {
  1200.     /*
  1201.      * The new event may conflict with the saved motion event.  Queue
  1202.      * the saved motion event now so that it will be processed before
  1203.      * the new event.
  1204.      */
  1205.     Tcl_QueueEvent(&dispPtr->delayedMotionPtr->header, position);
  1206.     dispPtr->delayedMotionPtr = NULL;
  1207.     Tcl_CancelIdleCall(DelayedMotionProc, (ClientData) dispPtr);
  1208. }
  1209.     }
  1210.     wevPtr = (TkWindowEvent *) ckalloc(sizeof(TkWindowEvent));
  1211.     wevPtr->header.proc = WindowEventProc;
  1212.     wevPtr->event = *eventPtr;
  1213.     if ((eventPtr->type == MotionNotify) && (position == TCL_QUEUE_TAIL)) {
  1214. /*
  1215.  * The new event is a motion event so don't queue it immediately;
  1216.  * save it around in case another motion event arrives that it can
  1217.  * be collapsed with.
  1218.  */
  1219. if (dispPtr->delayedMotionPtr != NULL) {
  1220.     panic("Tk_QueueWindowEvent found unexpected delayed motion event");
  1221. }
  1222. dispPtr->delayedMotionPtr = wevPtr;
  1223. Tcl_DoWhenIdle(DelayedMotionProc, (ClientData) dispPtr);
  1224.     } else {
  1225. Tcl_QueueEvent(&wevPtr->header, position);
  1226.     }
  1227. }
  1228. /*
  1229.  *---------------------------------------------------------------------------
  1230.  *
  1231.  * TkQueueEventForAllChildren --
  1232.  *
  1233.  * Given an XEvent, recursively queue the event for this window and
  1234.  * all non-toplevel children of the given window.  
  1235.  *
  1236.  * Results:
  1237.  * None.
  1238.  *
  1239.  * Side effects:
  1240.  * Events queued.
  1241.  *
  1242.  *---------------------------------------------------------------------------
  1243.  */
  1244. void
  1245. TkQueueEventForAllChildren(winPtr, eventPtr)
  1246.     TkWindow *winPtr;     /* Window to which event is sent. */
  1247.     XEvent *eventPtr;     /* The event to be sent. */
  1248. {
  1249.     TkWindow *childPtr;
  1250.     if (!Tk_IsMapped(winPtr)) {
  1251.         return;
  1252.     }
  1253.     
  1254.     eventPtr->xany.window = winPtr->window;
  1255.     Tk_QueueWindowEvent(eventPtr, TCL_QUEUE_TAIL);
  1256.     
  1257.     childPtr = winPtr->childList;
  1258.     while (childPtr != NULL) {
  1259. if (!Tk_TopWinHierarchy(childPtr)) {
  1260.     TkQueueEventForAllChildren(childPtr, eventPtr);
  1261. }
  1262. childPtr = childPtr->nextPtr;
  1263.     }
  1264. }
  1265. /*
  1266.  *----------------------------------------------------------------------
  1267.  *
  1268.  * WindowEventProc --
  1269.  *
  1270.  * This procedure is called by Tcl_DoOneEvent when a window event
  1271.  * reaches the front of the event queue.  This procedure is responsible
  1272.  * for actually handling the event.
  1273.  *
  1274.  * Results:
  1275.  * Returns 1 if the event was handled, meaning it should be removed
  1276.  * from the queue.  Returns 0 if the event was not handled, meaning
  1277.  * it should stay on the queue.  The event isn't handled if the
  1278.  * TCL_WINDOW_EVENTS bit isn't set in flags, if a restrict proc
  1279.  * prevents the event from being handled.
  1280.  *
  1281.  * Side effects:
  1282.  * Whatever the event handlers for the event do.
  1283.  *
  1284.  *----------------------------------------------------------------------
  1285.  */
  1286. static int
  1287. WindowEventProc(evPtr, flags)
  1288.     Tcl_Event *evPtr; /* Event to service. */
  1289.     int flags; /* Flags that indicate what events to
  1290.  * handle, such as TCL_WINDOW_EVENTS. */
  1291. {
  1292.     TkWindowEvent *wevPtr = (TkWindowEvent *) evPtr;
  1293.     Tk_RestrictAction result;
  1294.     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
  1295.             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  1296.     if (!(flags & TCL_WINDOW_EVENTS)) {
  1297. return 0;
  1298.     }
  1299.     if (tsdPtr->restrictProc != NULL) {
  1300. result = (*tsdPtr->restrictProc)(tsdPtr->restrictArg, &wevPtr->event);
  1301. if (result != TK_PROCESS_EVENT) {
  1302.     if (result == TK_DEFER_EVENT) {
  1303. return 0;
  1304.     } else {
  1305. /*
  1306.  * TK_DELETE_EVENT: return and say we processed the event,
  1307.  * even though we didn't do anything at all.
  1308.  */
  1309. return 1;
  1310.     }
  1311. }
  1312.     }
  1313.     Tk_HandleEvent(&wevPtr->event);
  1314.     return 1;
  1315. }
  1316. /*
  1317.  *----------------------------------------------------------------------
  1318.  *
  1319.  * DelayedMotionProc --
  1320.  *
  1321.  * This procedure is invoked as an idle handler when a mouse motion
  1322.  * event has been delayed.  It queues the delayed event so that it
  1323.  * will finally be serviced.
  1324.  *
  1325.  * Results:
  1326.  * None.
  1327.  *
  1328.  * Side effects:
  1329.  * The delayed mouse motion event gets added to the Tcl event
  1330.  * queue for servicing.
  1331.  *
  1332.  *----------------------------------------------------------------------
  1333.  */
  1334. static void
  1335. DelayedMotionProc(clientData)
  1336.     ClientData clientData; /* Pointer to display containing a delayed
  1337.  * motion event to be serviced. */
  1338. {
  1339.     TkDisplay *dispPtr = (TkDisplay *) clientData;
  1340.     if (dispPtr->delayedMotionPtr == NULL) {
  1341. panic("DelayedMotionProc found no delayed mouse motion event");
  1342.     }
  1343.     Tcl_QueueEvent(&dispPtr->delayedMotionPtr->header, TCL_QUEUE_TAIL);
  1344.     dispPtr->delayedMotionPtr = NULL;
  1345. }
  1346. /*
  1347.  *--------------------------------------------------------------
  1348.  *
  1349.  * Tk_MainLoop --
  1350.  *
  1351.  * Call Tcl_DoOneEvent over and over again in an infinite
  1352.  * loop as long as there exist any main windows.
  1353.  *
  1354.  * Results:
  1355.  * None.
  1356.  *
  1357.  * Side effects:
  1358.  * Arbitrary;  depends on handlers for events.
  1359.  *
  1360.  *--------------------------------------------------------------
  1361.  */
  1362. void
  1363. Tk_MainLoop()
  1364. {
  1365.     while (Tk_GetNumMainWindows() > 0) {
  1366. Tcl_DoOneEvent(0);
  1367.     }
  1368. }