/[dtapublic]/projs/dtats/trunk/shared_source/c_tk_base_7_5_w_mods/tkevent.c
ViewVC logotype

Diff of /projs/dtats/trunk/shared_source/c_tk_base_7_5_w_mods/tkevent.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.69  
changed lines
  Added in v.71

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25