4 * This file provides basic low-level facilities for managing
7 * Copyright (c) 1990-1994 The Regents of the University of California.
8 * Copyright (c) 1994-1995 Sun Microsystems, Inc.
9 * Copyright (c) 1998 by Scriptics Corporation.
11 * See the file "license.terms" for information on usage and redistribution
12 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
22 * There's a potential problem if a handler is deleted while it's
23 * current (i.e. its procedure is executing), since Tk_HandleEvent
24 * will need to read the handler's "nextPtr" field when the procedure
25 * returns. To handle this problem, structures of the type below
26 * indicate the next handler to be processed for any (recursively
27 * nested) dispatches in progress. The nextHandler fields get
28 * updated if the handlers pointed to are deleted. Tk_HandleEvent
29 * also needs to know if the entire window gets deleted; the winPtr
30 * field is set to zero if that particular window gets deleted.
33 typedef struct InProgress {
34 XEvent *eventPtr; /* Event currently being handled. */
35 TkWindow *winPtr; /* Window for event. Gets set to None if
36 * window is deleted while event is being
38 TkEventHandler *nextHandler; /* Next handler in search. */
39 struct InProgress *nextPtr; /* Next higher nested search. */
42 static InProgress *pendingPtr = NULL;
43 /* Topmost search in progress, or
47 * For each call to Tk_CreateGenericHandler, an instance of the following
48 * structure will be created. All of the active handlers are linked into a
52 typedef struct GenericHandler {
53 Tk_GenericProc *proc; /* Procedure to dispatch on all X events. */
54 ClientData clientData; /* Client data to pass to procedure. */
55 int deleteFlag; /* Flag to set when this handler is deleted. */
56 struct GenericHandler *nextPtr;
57 /* Next handler in list of all generic
58 * handlers, or NULL for end of list. */
61 static GenericHandler *genericList = NULL;
62 /* First handler in the list, or NULL. */
63 static GenericHandler *lastGenericPtr = NULL;
64 /* Last handler in list. */
67 * There's a potential problem if Tk_HandleEvent is entered recursively.
68 * A handler cannot be deleted physically until we have returned from
69 * calling it. Otherwise, we're looking at unallocated memory in advancing to
70 * its `next' entry. We deal with the problem by using the `delete flag' and
71 * deleting handlers only when it's known that there's no handler active.
73 * The following variable has a non-zero value when a handler is active.
76 static int genericHandlersActive = 0;
79 * The following structure is used for queueing X-style events on the
83 typedef struct TkWindowEvent {
84 Tcl_Event header; /* Standard information for all events. */
85 XEvent event; /* The X event. */
89 * Array of event masks corresponding to each X event:
92 static unsigned long eventMasks[TK_LASTEVENT] = {
95 KeyPressMask, /* KeyPress */
96 KeyReleaseMask, /* KeyRelease */
97 ButtonPressMask, /* ButtonPress */
98 ButtonReleaseMask, /* ButtonRelease */
99 PointerMotionMask|PointerMotionHintMask|ButtonMotionMask
100 |Button1MotionMask|Button2MotionMask|Button3MotionMask
101 |Button4MotionMask|Button5MotionMask,
103 EnterWindowMask, /* EnterNotify */
104 LeaveWindowMask, /* LeaveNotify */
105 FocusChangeMask, /* FocusIn */
106 FocusChangeMask, /* FocusOut */
107 KeymapStateMask, /* KeymapNotify */
108 ExposureMask, /* Expose */
109 ExposureMask, /* GraphicsExpose */
110 ExposureMask, /* NoExpose */
111 VisibilityChangeMask, /* VisibilityNotify */
112 SubstructureNotifyMask, /* CreateNotify */
113 StructureNotifyMask, /* DestroyNotify */
114 StructureNotifyMask, /* UnmapNotify */
115 StructureNotifyMask, /* MapNotify */
116 SubstructureRedirectMask, /* MapRequest */
117 StructureNotifyMask, /* ReparentNotify */
118 StructureNotifyMask, /* ConfigureNotify */
119 SubstructureRedirectMask, /* ConfigureRequest */
120 StructureNotifyMask, /* GravityNotify */
121 ResizeRedirectMask, /* ResizeRequest */
122 StructureNotifyMask, /* CirculateNotify */
123 SubstructureRedirectMask, /* CirculateRequest */
124 PropertyChangeMask, /* PropertyNotify */
125 0, /* SelectionClear */
126 0, /* SelectionRequest */
127 0, /* SelectionNotify */
128 ColormapChangeMask, /* ColormapNotify */
129 0, /* ClientMessage */
130 0, /* Mapping Notify */
131 VirtualEventMask, /* VirtualEvents */
132 ActivateMask, /* ActivateNotify */
133 ActivateMask, /* DeactivateNotify */
134 MouseWheelMask /* MouseWheelEvent */
138 * If someone has called Tk_RestrictEvents, the information below
142 static Tk_RestrictProc *restrictProc;
143 /* Procedure to call. NULL means no
144 * restrictProc is currently in effect. */
145 static ClientData restrictArg; /* Argument to pass to restrictProc. */
148 * Prototypes for procedures that are only referenced locally within
152 static void DelayedMotionProc _ANSI_ARGS_((ClientData clientData));
153 static int WindowEventProc _ANSI_ARGS_((Tcl_Event *evPtr,
157 *--------------------------------------------------------------
159 * Tk_CreateEventHandler --
161 * Arrange for a given procedure to be invoked whenever
162 * events from a given class occur in a given window.
168 * From now on, whenever an event of the type given by
169 * mask occurs for token and is processed by Tk_HandleEvent,
170 * proc will be called. See the manual entry for details
171 * of the calling sequence and return value for proc.
173 *--------------------------------------------------------------
177 Tk_CreateEventHandler(token, mask, proc, clientData)
178 Tk_Window token; /* Token for window in which to
180 unsigned long mask; /* Events for which proc should
182 Tk_EventProc *proc; /* Procedure to call for each
184 ClientData clientData; /* Arbitrary data to pass to proc. */
186 register TkEventHandler *handlerPtr;
187 register TkWindow *winPtr = (TkWindow *) token;
191 * Skim through the list of existing handlers to (a) compute the
192 * overall event mask for the window (so we can pass this new
193 * value to the X system) and (b) see if there's already a handler
194 * declared with the same callback and clientData (if so, just
195 * change the mask). If no existing handler matches, then create
200 if (winPtr->handlerList == NULL) {
201 handlerPtr = (TkEventHandler *) ckalloc(
202 (unsigned) sizeof(TkEventHandler));
203 winPtr->handlerList = handlerPtr;
206 for (handlerPtr = winPtr->handlerList; ;
207 handlerPtr = handlerPtr->nextPtr) {
208 if ((handlerPtr->proc == proc)
209 && (handlerPtr->clientData == clientData)) {
210 handlerPtr->mask = mask;
213 if (handlerPtr->nextPtr == NULL) {
220 * Create a new handler if no matching old handler was found.
224 handlerPtr->nextPtr = (TkEventHandler *)
225 ckalloc(sizeof(TkEventHandler));
226 handlerPtr = handlerPtr->nextPtr;
228 handlerPtr->mask = mask;
229 handlerPtr->proc = proc;
230 handlerPtr->clientData = clientData;
231 handlerPtr->nextPtr = NULL;
235 * No need to call XSelectInput: Tk always selects on all events
236 * for all windows (needed to support bindings on classes and "all").
241 *--------------------------------------------------------------
243 * Tk_DeleteEventHandler --
245 * Delete a previously-created handler.
251 * If there existed a handler as described by the
252 * parameters, the handler is deleted so that proc
253 * will not be invoked again.
255 *--------------------------------------------------------------
259 Tk_DeleteEventHandler(token, mask, proc, clientData)
260 Tk_Window token; /* Same as corresponding arguments passed */
261 unsigned long mask; /* previously to Tk_CreateEventHandler. */
263 ClientData clientData;
265 register TkEventHandler *handlerPtr;
266 register InProgress *ipPtr;
267 TkEventHandler *prevPtr;
268 register TkWindow *winPtr = (TkWindow *) token;
271 * Find the event handler to be deleted, or return
272 * immediately if it doesn't exist.
275 for (handlerPtr = winPtr->handlerList, prevPtr = NULL; ;
276 prevPtr = handlerPtr, handlerPtr = handlerPtr->nextPtr) {
277 if (handlerPtr == NULL) {
280 if ((handlerPtr->mask == mask) && (handlerPtr->proc == proc)
281 && (handlerPtr->clientData == clientData)) {
287 * If Tk_HandleEvent is about to process this handler, tell it to
288 * process the next one instead.
291 for (ipPtr = pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) {
292 if (ipPtr->nextHandler == handlerPtr) {
293 ipPtr->nextHandler = handlerPtr->nextPtr;
298 * Free resources associated with the handler.
301 if (prevPtr == NULL) {
302 winPtr->handlerList = handlerPtr->nextPtr;
304 prevPtr->nextPtr = handlerPtr->nextPtr;
306 ckfree((char *) handlerPtr);
310 * No need to call XSelectInput: Tk always selects on all events
311 * for all windows (needed to support bindings on classes and "all").
315 /*--------------------------------------------------------------
317 * Tk_CreateGenericHandler --
319 * Register a procedure to be called on each X event, regardless
320 * of display or window. Generic handlers are useful for capturing
321 * events that aren't associated with windows, or events for windows
328 * From now on, whenever an X event is given to Tk_HandleEvent,
329 * invoke proc, giving it clientData and the event as arguments.
331 *--------------------------------------------------------------
335 Tk_CreateGenericHandler(proc, clientData)
336 Tk_GenericProc *proc; /* Procedure to call on every event. */
337 ClientData clientData; /* One-word value to pass to proc. */
339 GenericHandler *handlerPtr;
341 handlerPtr = (GenericHandler *) ckalloc (sizeof (GenericHandler));
343 handlerPtr->proc = proc;
344 handlerPtr->clientData = clientData;
345 handlerPtr->deleteFlag = 0;
346 handlerPtr->nextPtr = NULL;
347 if (genericList == NULL) {
348 genericList = handlerPtr;
350 lastGenericPtr->nextPtr = handlerPtr;
352 lastGenericPtr = handlerPtr;
356 *--------------------------------------------------------------
358 * Tk_DeleteGenericHandler --
360 * Delete a previously-created generic handler.
366 * If there existed a handler as described by the parameters,
367 * that handler is logically deleted so that proc will not be
368 * invoked again. The physical deletion happens in the event
369 * loop in Tk_HandleEvent.
371 *--------------------------------------------------------------
375 Tk_DeleteGenericHandler(proc, clientData)
376 Tk_GenericProc *proc;
377 ClientData clientData;
379 GenericHandler * handler;
381 for (handler = genericList; handler; handler = handler->nextPtr) {
382 if ((handler->proc == proc) && (handler->clientData == clientData)) {
383 handler->deleteFlag = 1;
389 *--------------------------------------------------------------
393 * Given an event, invoke all the handlers that have
394 * been registered for the event.
400 * Depends on the handlers.
402 *--------------------------------------------------------------
406 Tk_HandleEvent(eventPtr)
407 XEvent *eventPtr; /* Event to dispatch. */
409 register TkEventHandler *handlerPtr;
410 register GenericHandler *genericPtr;
411 register GenericHandler *genPrevPtr;
415 Window handlerWindow;
417 Tcl_Interp *interp = (Tcl_Interp *) NULL;
420 * Next, invoke all the generic event handlers (those that are
421 * invoked for all events). If a generic event handler reports that
422 * an event is fully processed, go no further.
425 for (genPrevPtr = NULL, genericPtr = genericList; genericPtr != NULL; ) {
426 if (genericPtr->deleteFlag) {
427 if (!genericHandlersActive) {
428 GenericHandler *tmpPtr;
431 * This handler needs to be deleted and there are no
432 * calls pending through the handler, so now is a safe
436 tmpPtr = genericPtr->nextPtr;
437 if (genPrevPtr == NULL) {
438 genericList = tmpPtr;
440 genPrevPtr->nextPtr = tmpPtr;
442 if (tmpPtr == NULL) {
443 lastGenericPtr = genPrevPtr;
445 (void) ckfree((char *) genericPtr);
452 genericHandlersActive++;
453 done = (*genericPtr->proc)(genericPtr->clientData, eventPtr);
454 genericHandlersActive--;
459 genPrevPtr = genericPtr;
460 genericPtr = genPrevPtr->nextPtr;
464 * If the event is a MappingNotify event, find its display and
465 * refresh the keyboard mapping information for the display.
466 * After that there's nothing else to do with the event, so just
470 if (eventPtr->type == MappingNotify) {
471 dispPtr = TkGetDisplay(eventPtr->xmapping.display);
472 if (dispPtr != NULL) {
473 XRefreshKeyboardMapping(&eventPtr->xmapping);
474 dispPtr->bindInfoStale = 1;
480 * Events selected by StructureNotify require special handling.
481 * They look the same as those selected by SubstructureNotify.
482 * The only difference is whether the "event" and "window" fields
483 * are the same. Compare the two fields and convert StructureNotify
484 * to SubstructureNotify if necessary.
487 handlerWindow = eventPtr->xany.window;
488 mask = eventMasks[eventPtr->xany.type];
489 if (mask == StructureNotifyMask) {
490 if (eventPtr->xmap.event != eventPtr->xmap.window) {
491 mask = SubstructureNotifyMask;
492 handlerWindow = eventPtr->xmap.event;
495 winPtr = (TkWindow *) Tk_IdToWindow(eventPtr->xany.display, handlerWindow);
496 if (winPtr == NULL) {
499 * There isn't a TkWindow structure for this window.
500 * However, if the event is a PropertyNotify event then call
501 * the selection manager (it deals beneath-the-table with
502 * certain properties).
505 if (eventPtr->type == PropertyNotify) {
506 TkSelPropProc(eventPtr);
512 * Once a window has started getting deleted, don't process any more
513 * events for it except for the DestroyNotify event. This check is
514 * needed because a DestroyNotify handler could re-invoke the event
515 * loop, causing other pending events to be handled for the window
516 * (the window doesn't get totally expunged from our tables until
517 * after the DestroyNotify event has been completely handled).
520 if ((winPtr->flags & TK_ALREADY_DEAD)
521 && (eventPtr->type != DestroyNotify)) {
525 if (winPtr->mainPtr != NULL) {
528 * Protect interpreter for this window from possible deletion
529 * while we are dealing with the event for this window. Thus,
530 * widget writers do not have to worry about protecting the
531 * interpreter in their own code.
534 interp = winPtr->mainPtr->interp;
535 Tcl_Preserve((ClientData) interp);
538 * Call focus-related code to look at FocusIn, FocusOut, Enter,
539 * and Leave events; depending on its return value, ignore the
543 if ((mask & (FocusChangeMask|EnterWindowMask|LeaveWindowMask))
544 && !TkFocusFilterEvent(winPtr, eventPtr)) {
545 Tcl_Release((ClientData) interp);
550 * Redirect KeyPress and KeyRelease events to the focus window,
551 * or ignore them entirely if there is no focus window. We also
552 * route the MouseWheel event to the focus window. The MouseWheel
553 * event is an extension to the X event set. Currently, it is only
554 * available on the Windows version of Tk.
557 if (mask & (KeyPressMask|KeyReleaseMask|MouseWheelMask)) {
558 winPtr->dispPtr->lastEventTime = eventPtr->xkey.time;
559 winPtr = TkFocusKeyEvent(winPtr, eventPtr);
560 if (winPtr == NULL) {
561 Tcl_Release((ClientData) interp);
567 * Call a grab-related procedure to do special processing on
571 if (mask & (ButtonPressMask|ButtonReleaseMask|PointerMotionMask
572 |EnterWindowMask|LeaveWindowMask)) {
573 if (mask & (ButtonPressMask|ButtonReleaseMask)) {
574 winPtr->dispPtr->lastEventTime = eventPtr->xbutton.time;
575 } else if (mask & PointerMotionMask) {
576 winPtr->dispPtr->lastEventTime = eventPtr->xmotion.time;
578 winPtr->dispPtr->lastEventTime = eventPtr->xcrossing.time;
580 if (TkPointerEvent(eventPtr, winPtr) == 0) {
586 #ifdef TK_USE_INPUT_METHODS
588 * Pass the event to the input method(s), if there are any, and
589 * discard the event if the input method(s) insist. Create the
590 * input context for the window if it hasn't already been done
591 * (XFilterEvent needs this context).
594 if (!(winPtr->flags & TK_CHECKED_IC)) {
595 if (winPtr->dispPtr->inputMethod != NULL) {
596 winPtr->inputContext = XCreateIC(
597 winPtr->dispPtr->inputMethod, XNInputStyle,
598 XIMPreeditNothing|XIMStatusNothing,
599 XNClientWindow, winPtr->window,
600 XNFocusWindow, winPtr->window, NULL);
602 winPtr->flags |= TK_CHECKED_IC;
604 if (XFilterEvent(eventPtr, None)) {
607 #endif /* TK_USE_INPUT_METHODS */
610 * For events where it hasn't already been done, update the current
611 * time in the display.
614 if (eventPtr->type == PropertyNotify) {
615 winPtr->dispPtr->lastEventTime = eventPtr->xproperty.time;
619 * There's a potential interaction here with Tk_DeleteEventHandler.
620 * Read the documentation for pendingPtr.
623 ip.eventPtr = eventPtr;
625 ip.nextHandler = NULL;
626 ip.nextPtr = pendingPtr;
629 if ((eventPtr->type == SelectionClear)
630 || (eventPtr->type == SelectionRequest)
631 || (eventPtr->type == SelectionNotify)) {
632 TkSelEventProc((Tk_Window) winPtr, eventPtr);
633 } else if ((eventPtr->type == ClientMessage)
634 && (eventPtr->xclient.message_type ==
635 Tk_InternAtom((Tk_Window) winPtr, "WM_PROTOCOLS"))) {
636 TkWmProtocolEventProc(winPtr, eventPtr);
639 for (handlerPtr = winPtr->handlerList; handlerPtr != NULL; ) {
640 if ((handlerPtr->mask & mask) != 0) {
641 ip.nextHandler = handlerPtr->nextPtr;
642 (*(handlerPtr->proc))(handlerPtr->clientData, eventPtr);
643 handlerPtr = ip.nextHandler;
645 handlerPtr = handlerPtr->nextPtr;
650 * Pass the event to the "bind" command mechanism. But, don't
651 * do this for SubstructureNotify events. The "bind" command
652 * doesn't support them anyway, and it's easier to filter out
653 * these events here than in the lower-level procedures.
656 if ((ip.winPtr != None) && (mask != SubstructureNotifyMask)) {
657 TkBindEventProc(winPtr, eventPtr);
660 pendingPtr = ip.nextPtr;
664 * Release the interpreter for this window so that it can be potentially
665 * deleted if requested.
668 if (interp != (Tcl_Interp *) NULL) {
669 Tcl_Release((ClientData) interp);
674 *--------------------------------------------------------------
676 * TkEventDeadWindow --
678 * This procedure is invoked when it is determined that
679 * a window is dead. It cleans up event-related information
686 * Various things get cleaned up and recycled.
688 *--------------------------------------------------------------
692 TkEventDeadWindow(winPtr)
693 TkWindow *winPtr; /* Information about the window
694 * that is being deleted. */
696 register TkEventHandler *handlerPtr;
697 register InProgress *ipPtr;
700 * While deleting all the handlers, be careful to check for
701 * Tk_HandleEvent being about to process one of the deleted
702 * handlers. If it is, tell it to quit (all of the handlers
703 * are being deleted).
706 while (winPtr->handlerList != NULL) {
707 handlerPtr = winPtr->handlerList;
708 winPtr->handlerList = handlerPtr->nextPtr;
709 for (ipPtr = pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) {
710 if (ipPtr->nextHandler == handlerPtr) {
711 ipPtr->nextHandler = NULL;
713 if (ipPtr->winPtr == winPtr) {
714 ipPtr->winPtr = None;
717 ckfree((char *) handlerPtr);
722 *----------------------------------------------------------------------
726 * Try to deduce the current time. "Current time" means the time
727 * of the event that led to the current code being executed, which
728 * means the time in the most recently-nested invocation of
732 * The return value is the time from the current event, or
733 * CurrentTime if there is no current event or if the current
734 * event contains no time.
739 *----------------------------------------------------------------------
743 TkCurrentTime(dispPtr)
744 TkDisplay *dispPtr; /* Display for which the time is desired. */
746 register XEvent *eventPtr;
748 if (pendingPtr == NULL) {
749 return dispPtr->lastEventTime;
751 eventPtr = pendingPtr->eventPtr;
752 switch (eventPtr->type) {
755 return eventPtr->xbutton.time;
758 return eventPtr->xkey.time;
760 return eventPtr->xmotion.time;
763 return eventPtr->xcrossing.time;
765 return eventPtr->xproperty.time;
767 return dispPtr->lastEventTime;
771 *----------------------------------------------------------------------
773 * Tk_RestrictEvents --
775 * This procedure is used to globally restrict the set of events
776 * that will be dispatched. The restriction is done by filtering
777 * all incoming X events through a procedure that determines
778 * whether they are to be processed immediately, deferred, or
782 * The return value is the previous restriction procedure in effect,
783 * if there was one, or NULL if there wasn't.
786 * From now on, proc will be called to determine whether to process,
787 * defer or discard each incoming X event.
789 *----------------------------------------------------------------------
793 Tk_RestrictEvents(proc, arg, prevArgPtr)
794 Tk_RestrictProc *proc; /* Procedure to call for each incoming
796 ClientData arg; /* Arbitrary argument to pass to proc. */
797 ClientData *prevArgPtr; /* Place to store information about previous
800 Tk_RestrictProc *prev;
803 *prevArgPtr = restrictArg;
810 *----------------------------------------------------------------------
812 * Tk_QueueWindowEvent --
814 * Given an X-style window event, this procedure adds it to the
815 * Tcl event queue at the given position. This procedure also
816 * performs mouse motion event collapsing if possible.
822 * Adds stuff to the event queue, which will eventually be
825 *----------------------------------------------------------------------
829 Tk_QueueWindowEvent(eventPtr, position)
830 XEvent *eventPtr; /* Event to add to queue. This
831 * procedures copies it before adding
832 * it to the queue. */
833 Tcl_QueuePosition position; /* Where to put it on the queue:
834 * TCL_QUEUE_TAIL, TCL_QUEUE_HEAD,
835 * or TCL_QUEUE_MARK. */
837 TkWindowEvent *wevPtr;
841 * Find our display structure for the event's display.
844 for (dispPtr = tkDisplayList; ; dispPtr = dispPtr->nextPtr) {
845 if (dispPtr == NULL) {
848 if (dispPtr->display == eventPtr->xany.display) {
853 if ((dispPtr->delayedMotionPtr != NULL) && (position == TCL_QUEUE_TAIL)) {
854 if ((eventPtr->type == MotionNotify) && (eventPtr->xmotion.window
855 == dispPtr->delayedMotionPtr->event.xmotion.window)) {
857 * The new event is a motion event in the same window as the
858 * saved motion event. Just replace the saved event with the
862 dispPtr->delayedMotionPtr->event = *eventPtr;
864 } else if ((eventPtr->type != GraphicsExpose)
865 && (eventPtr->type != NoExpose)
866 && (eventPtr->type != Expose)) {
868 * The new event may conflict with the saved motion event. Queue
869 * the saved motion event now so that it will be processed before
873 Tcl_QueueEvent(&dispPtr->delayedMotionPtr->header, position);
874 dispPtr->delayedMotionPtr = NULL;
875 Tcl_CancelIdleCall(DelayedMotionProc, (ClientData) dispPtr);
879 wevPtr = (TkWindowEvent *) ckalloc(sizeof(TkWindowEvent));
880 wevPtr->header.proc = WindowEventProc;
881 wevPtr->event = *eventPtr;
882 if ((eventPtr->type == MotionNotify) && (position == TCL_QUEUE_TAIL)) {
884 * The new event is a motion event so don't queue it immediately;
885 * save it around in case another motion event arrives that it can
889 if (dispPtr->delayedMotionPtr != NULL) {
890 panic("Tk_QueueWindowEvent found unexpected delayed motion event");
892 dispPtr->delayedMotionPtr = wevPtr;
893 Tcl_DoWhenIdle(DelayedMotionProc, (ClientData) dispPtr);
895 Tcl_QueueEvent(&wevPtr->header, position);
900 *---------------------------------------------------------------------------
902 * TkQueueEventForAllChildren --
904 * Given an XEvent, recursively queue the event for this window and
905 * all non-toplevel children of the given window.
913 *---------------------------------------------------------------------------
917 TkQueueEventForAllChildren(winPtr, eventPtr)
918 TkWindow *winPtr; /* Window to which event is sent. */
919 XEvent *eventPtr; /* The event to be sent. */
923 eventPtr->xany.window = winPtr->window;
924 Tk_QueueWindowEvent(eventPtr, TCL_QUEUE_TAIL);
926 childPtr = winPtr->childList;
927 while (childPtr != NULL) {
928 if (!Tk_IsTopLevel(childPtr)) {
929 TkQueueEventForAllChildren(childPtr, eventPtr);
931 childPtr = childPtr->nextPtr;
936 *----------------------------------------------------------------------
940 * This procedure is called by Tcl_DoOneEvent when a window event
941 * reaches the front of the event queue. This procedure is responsible
942 * for actually handling the event.
945 * Returns 1 if the event was handled, meaning it should be removed
946 * from the queue. Returns 0 if the event was not handled, meaning
947 * it should stay on the queue. The event isn't handled if the
948 * TCL_WINDOW_EVENTS bit isn't set in flags, if a restrict proc
949 * prevents the event from being handled.
952 * Whatever the event handlers for the event do.
954 *----------------------------------------------------------------------
958 WindowEventProc(evPtr, flags)
959 Tcl_Event *evPtr; /* Event to service. */
960 int flags; /* Flags that indicate what events to
961 * handle, such as TCL_WINDOW_EVENTS. */
963 TkWindowEvent *wevPtr = (TkWindowEvent *) evPtr;
964 Tk_RestrictAction result;
966 if (!(flags & TCL_WINDOW_EVENTS)) {
969 if (restrictProc != NULL) {
970 result = (*restrictProc)(restrictArg, &wevPtr->event);
971 if (result != TK_PROCESS_EVENT) {
972 if (result == TK_DEFER_EVENT) {
976 * TK_DELETE_EVENT: return and say we processed the event,
977 * even though we didn't do anything at all.
983 Tk_HandleEvent(&wevPtr->event);
988 *----------------------------------------------------------------------
990 * DelayedMotionProc --
992 * This procedure is invoked as an idle handler when a mouse motion
993 * event has been delayed. It queues the delayed event so that it
994 * will finally be serviced.
1000 * The delayed mouse motion event gets added to the Tcl event
1001 * queue for servicing.
1003 *----------------------------------------------------------------------
1007 DelayedMotionProc(clientData)
1008 ClientData clientData; /* Pointer to display containing a delayed
1009 * motion event to be serviced. */
1011 TkDisplay *dispPtr = (TkDisplay *) clientData;
1013 if (dispPtr->delayedMotionPtr == NULL) {
1014 panic("DelayedMotionProc found no delayed mouse motion event");
1016 Tcl_QueueEvent(&dispPtr->delayedMotionPtr->header, TCL_QUEUE_TAIL);
1017 dispPtr->delayedMotionPtr = NULL;
1021 *--------------------------------------------------------------
1025 * Call Tcl_DoOneEvent over and over again in an infinite
1026 * loop as long as there exist any main windows.
1032 * Arbitrary; depends on handlers for events.
1034 *--------------------------------------------------------------
1040 while (Tk_GetNumMainWindows() > 0) {