1/*
2 * tkEvent.c --
3 *
4 *	This file provides basic low-level facilities for managing X events in
5 *	Tk.
6 *
7 * Copyright (c) 1990-1994 The Regents of the University of California.
8 * Copyright (c) 1994-1995 Sun Microsystems, Inc.
9 * Copyright (c) 1998-2000 Ajuba Solutions.
10 * Copyright (c) 2004 George Peter Staplin
11 *
12 * See the file "license.terms" for information on usage and redistribution of
13 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
14 *
15 * RCS: @(#) $Id$
16 */
17
18#include "tkInt.h"
19
20/*
21 * There's a potential problem if a handler is deleted while it's current
22 * (i.e. its function is executing), since Tk_HandleEvent will need to read
23 * the handler's "nextPtr" field when the function returns. To handle this
24 * problem, structures of the type below indicate the next handler to be
25 * processed for any (recursively nested) dispatches in progress. The
26 * nextHandler fields get updated if the handlers pointed to are deleted.
27 * Tk_HandleEvent also needs to know if the entire window gets deleted; the
28 * winPtr field is set to zero if that particular window gets deleted.
29 */
30
31typedef struct InProgress {
32    XEvent *eventPtr;		/* Event currently being handled. */
33    TkWindow *winPtr;		/* Window for event. Gets set to None if
34				 * window is deleted while event is being
35				 * handled. */
36    TkEventHandler *nextHandler;/* Next handler in search. */
37    struct InProgress *nextPtr;	/* Next higher nested search. */
38} InProgress;
39
40/*
41 * For each call to Tk_CreateGenericHandler or Tk_CreateClientMessageHandler,
42 * an instance of the following structure will be created. All of the active
43 * handlers are linked into a list.
44 */
45
46typedef struct GenericHandler {
47    Tk_GenericProc *proc;	/* Function to dispatch on all X events. */
48    ClientData clientData;	/* Client data to pass to function. */
49    int deleteFlag;		/* Flag to set when this handler is
50				 * deleted. */
51    struct GenericHandler *nextPtr;
52				/* Next handler in list of all generic
53				 * handlers, or NULL for end of list. */
54} GenericHandler;
55
56/*
57 * There's a potential problem if Tk_HandleEvent is entered recursively. A
58 * handler cannot be deleted physically until we have returned from calling
59 * it. Otherwise, we're looking at unallocated memory in advancing to its
60 * `next' entry. We deal with the problem by using the `delete flag' and
61 * deleting handlers only when it's known that there's no handler active.
62 */
63
64/*
65 * The following structure is used for queueing X-style events on the Tcl
66 * event queue.
67 */
68
69typedef struct TkWindowEvent {
70    Tcl_Event header;		/* Standard information for all events. */
71    XEvent event;		/* The X event. */
72} TkWindowEvent;
73
74/*
75 * Array of event masks corresponding to each X event:
76 */
77
78static unsigned long realEventMasks[MappingNotify+1] = {
79    0,
80    0,
81    KeyPressMask,			/* KeyPress */
82    KeyReleaseMask,			/* KeyRelease */
83    ButtonPressMask,			/* ButtonPress */
84    ButtonReleaseMask,			/* ButtonRelease */
85    PointerMotionMask|PointerMotionHintMask|ButtonMotionMask
86	    |Button1MotionMask|Button2MotionMask|Button3MotionMask
87	    |Button4MotionMask|Button5MotionMask,
88					/* MotionNotify */
89    EnterWindowMask,			/* EnterNotify */
90    LeaveWindowMask,			/* LeaveNotify */
91    FocusChangeMask,			/* FocusIn */
92    FocusChangeMask,			/* FocusOut */
93    KeymapStateMask,			/* KeymapNotify */
94    ExposureMask,			/* Expose */
95    ExposureMask,			/* GraphicsExpose */
96    ExposureMask,			/* NoExpose */
97    VisibilityChangeMask,		/* VisibilityNotify */
98    SubstructureNotifyMask,		/* CreateNotify */
99    StructureNotifyMask,		/* DestroyNotify */
100    StructureNotifyMask,		/* UnmapNotify */
101    StructureNotifyMask,		/* MapNotify */
102    SubstructureRedirectMask,		/* MapRequest */
103    StructureNotifyMask,		/* ReparentNotify */
104    StructureNotifyMask,		/* ConfigureNotify */
105    SubstructureRedirectMask,		/* ConfigureRequest */
106    StructureNotifyMask,		/* GravityNotify */
107    ResizeRedirectMask,			/* ResizeRequest */
108    StructureNotifyMask,		/* CirculateNotify */
109    SubstructureRedirectMask,		/* CirculateRequest */
110    PropertyChangeMask,			/* PropertyNotify */
111    0,					/* SelectionClear */
112    0,					/* SelectionRequest */
113    0,					/* SelectionNotify */
114    ColormapChangeMask,			/* ColormapNotify */
115    0,					/* ClientMessage */
116    0					/* Mapping Notify */
117};
118
119static unsigned long virtualEventMasks[TK_LASTEVENT-VirtualEvent] = {
120    VirtualEventMask,			/* VirtualEvents */
121    ActivateMask,			/* ActivateNotify */
122    ActivateMask,			/* DeactivateNotify */
123    MouseWheelMask			/* MouseWheelEvent */
124};
125
126/*
127 * For each exit handler created with a call to TkCreateExitHandler or
128 * TkCreateThreadExitHandler there is a structure of the following type:
129 */
130
131typedef struct ExitHandler {
132    Tcl_ExitProc *proc;		/* Function to call when process exits. */
133    ClientData clientData;	/* One word of information to pass to proc. */
134    struct ExitHandler *nextPtr;/* Next in list of all exit handlers for this
135				 * application, or NULL for end of list. */
136} ExitHandler;
137
138/*
139 * The structure below is used to store Data for the Event module that must be
140 * kept thread-local. The "dataKey" is used to fetch the thread-specific
141 * storage for the current thread.
142 */
143
144typedef struct ThreadSpecificData {
145    int handlersActive;		/* The following variable has a non-zero value
146				 * when a handler is active. */
147    InProgress *pendingPtr;	/* Topmost search in progress, or NULL if
148				 * none. */
149
150    /*
151     * List of generic handler records.
152     */
153
154    GenericHandler *genericList;/* First handler in the list, or NULL. */
155    GenericHandler *lastGenericPtr;
156				/* Last handler in list. */
157
158    /*
159     * List of client message handler records.
160     */
161
162    GenericHandler *cmList;	/* First handler in the list, or NULL. */
163    GenericHandler *lastCmPtr;	/* Last handler in list. */
164
165    /*
166     * If someone has called Tk_RestrictEvents, the information below keeps
167     * track of it.
168     */
169
170    Tk_RestrictProc *restrictProc;
171				/* Function to call. NULL means no
172				 * restrictProc is currently in effect. */
173    ClientData restrictArg;	/* Argument to pass to restrictProc. */
174    ExitHandler *firstExitPtr;	/* First in list of all exit handlers for this
175				 * thread. */
176    int inExit;			/* True when this thread is exiting. This is
177				 * used as a hack to decide to close the
178				 * standard channels. */
179} ThreadSpecificData;
180static Tcl_ThreadDataKey dataKey;
181
182/*
183 * There are both per-process and per-thread exit handlers. The first list is
184 * controlled by a mutex. The other is in thread local storage.
185 */
186
187static ExitHandler *firstExitPtr = NULL;
188				/* First in list of all exit handlers for
189				 * application. */
190TCL_DECLARE_MUTEX(exitMutex)
191
192/*
193 * Prototypes for functions that are only referenced locally within this file.
194 */
195
196static void		CleanUpTkEvent(XEvent *eventPtr);
197static void		DelayedMotionProc(ClientData clientData);
198static int		GetButtonMask(unsigned int Button);
199static unsigned long    GetEventMaskFromXEvent(XEvent *eventPtr);
200static TkWindow *	GetTkWindowFromXEvent(XEvent *eventPtr);
201static void		InvokeClientMessageHandlers(ThreadSpecificData *tsdPtr,
202			    Tk_Window tkwin, XEvent *eventPtr);
203static int		InvokeFocusHandlers(TkWindow **winPtrPtr,
204			    unsigned long mask, XEvent *eventPtr);
205static int		InvokeGenericHandlers(ThreadSpecificData *tsdPtr,
206			    XEvent *eventPtr);
207static int		InvokeMouseHandlers(TkWindow *winPtr,
208			    unsigned long mask, XEvent *eventPtr);
209static Window		ParentXId(Display *display, Window w);
210static int		RefreshKeyboardMappingIfNeeded(XEvent *eventPtr);
211static int		TkXErrorHandler(ClientData clientData,
212			    XErrorEvent *errEventPtr);
213static void		UpdateButtonEventState(XEvent *eventPtr);
214static int		WindowEventProc(Tcl_Event *evPtr, int flags);
215#ifdef TK_USE_INPUT_METHODS
216static void		CreateXIC(TkWindow *winPtr);
217#endif /* TK_USE_INPUT_METHODS */
218
219/*
220 *----------------------------------------------------------------------
221 *
222 * InvokeFocusHandlers --
223 *
224 *	Call focus-related code to look at FocusIn, FocusOut, Enter, and Leave
225 *	events; depending on its return value, ignore the event.
226 *
227 * Results:
228 *	0 further processing can be done on the event.
229 *	1 we are done with the event passed.
230 *
231 * Side effects:
232 *	The *winPtrPtr in the caller may be changed to the TkWindow for the
233 *	window with focus.
234 *
235 *----------------------------------------------------------------------
236 */
237
238static int
239InvokeFocusHandlers(
240    TkWindow **winPtrPtr,
241    unsigned long mask,
242    XEvent *eventPtr)
243{
244    if ((mask & (FocusChangeMask|EnterWindowMask|LeaveWindowMask))
245	    && (TkFocusFilterEvent(*winPtrPtr, eventPtr) == 0)) {
246	return 1;
247    }
248
249    /*
250     * MouseWheel events are not focus specific on Mac OS X.
251     */
252
253#ifdef MAC_OSX_TK
254#define FOCUS_DIRECTED_EVENT_MASK (KeyPressMask|KeyReleaseMask)
255#else
256#define	FOCUS_DIRECTED_EVENT_MASK (KeyPressMask|KeyReleaseMask|MouseWheelMask)
257#endif
258
259    if (mask & FOCUS_DIRECTED_EVENT_MASK) {
260	(*winPtrPtr)->dispPtr->lastEventTime = eventPtr->xkey.time;
261	*winPtrPtr = TkFocusKeyEvent(*winPtrPtr, eventPtr);
262	if (*winPtrPtr == NULL) {
263	    return 1;
264	}
265    }
266
267    return 0;
268}
269
270/*
271 *----------------------------------------------------------------------
272 *
273 * InvokeMouseHandlers --
274 *
275 *	Call a grab-related function to do special processing on pointer
276 *	events.
277 *
278 * Results:
279 *	0 further processing can be done on the event.
280 *	1 we are done with the event passed.
281 *
282 * Side effects:
283 *	New events may be queued from TkPointerEvent and grabs may be added
284 *	and/or removed. The eventPtr may be changed by TkPointerEvent in some
285 *	cases.
286 *
287 *----------------------------------------------------------------------
288 */
289
290static int
291InvokeMouseHandlers(
292    TkWindow *winPtr,
293    unsigned long mask,
294    XEvent *eventPtr)
295{
296    if (mask & (ButtonPressMask|ButtonReleaseMask|PointerMotionMask
297	    |EnterWindowMask|LeaveWindowMask)) {
298
299	if (mask & (ButtonPressMask|ButtonReleaseMask)) {
300	    winPtr->dispPtr->lastEventTime = eventPtr->xbutton.time;
301	} else if (mask & PointerMotionMask) {
302	    winPtr->dispPtr->lastEventTime = eventPtr->xmotion.time;
303	} else {
304	    winPtr->dispPtr->lastEventTime = eventPtr->xcrossing.time;
305	}
306
307	if (TkPointerEvent(eventPtr, winPtr) == 0) {
308	    /*
309	     * The event should be ignored to make grab work correctly (as the
310	     * comment for TkPointerEvent states).
311	     */
312
313	    return 1;
314	}
315    }
316
317    return 0;
318}
319
320/*
321 *----------------------------------------------------------------------
322 *
323 * CreateXIC --
324 *
325 *	Create the X input context for our winPtr.
326 *	XIM is only ever enabled on Unix.
327 *
328 *----------------------------------------------------------------------
329 */
330
331#if defined(TK_USE_INPUT_METHODS)
332static void
333CreateXIC(
334    TkWindow *winPtr)
335{
336    TkDisplay *dispPtr = winPtr->dispPtr;
337    long im_event_mask = 0L;
338    const char *preedit_attname = NULL;
339    XVaNestedList preedit_attlist = NULL;
340
341    if (dispPtr->inputStyle & XIMPreeditPosition) {
342	XPoint spot = {0, 0};
343
344	preedit_attname = XNPreeditAttributes;
345	preedit_attlist = XVaCreateNestedList(0,
346		XNSpotLocation, &spot,
347		XNFontSet, dispPtr->inputXfs,
348		NULL);
349    }
350
351    winPtr->inputContext = XCreateIC(dispPtr->inputMethod,
352	    XNInputStyle, dispPtr->inputStyle,
353	    XNClientWindow, winPtr->window,
354	    XNFocusWindow, winPtr->window,
355	    preedit_attname, preedit_attlist,
356	    NULL);
357
358    if (preedit_attlist) {
359	XFree(preedit_attlist);
360    }
361
362
363    if (winPtr->inputContext == NULL) {
364	/* XCreateIC failed. */
365        return;
366    }
367
368    /*
369     * Adjust the window's event mask if the IM requires it.
370     */
371    XGetICValues(winPtr->inputContext, XNFilterEvents, &im_event_mask, NULL);
372    if ((winPtr->atts.event_mask & im_event_mask) != im_event_mask) {
373	winPtr->atts.event_mask |= im_event_mask;
374	XSelectInput(winPtr->display, winPtr->window, winPtr->atts.event_mask);
375    }
376}
377#endif
378
379/*
380 *----------------------------------------------------------------------
381 *
382 * GetTkWindowFromXEvent --
383 *
384 *	Attempt to find which TkWindow is associated with an event. If it
385 *	fails we attempt to get the TkWindow from the parent for a property
386 *	notification.
387 *
388 * Results:
389 *	The TkWindow associated with the event or NULL.
390 *
391 * Side effects:
392 *	TkSelPropProc may influence selection on windows not known to Tk.
393 *
394 *----------------------------------------------------------------------
395 */
396
397static TkWindow *
398GetTkWindowFromXEvent(
399    XEvent *eventPtr)
400{
401    TkWindow *winPtr;
402    Window parentXId, handlerWindow = eventPtr->xany.window;
403
404    if ((eventPtr->xany.type == StructureNotifyMask)
405	    && (eventPtr->xmap.event != eventPtr->xmap.window)) {
406	handlerWindow = eventPtr->xmap.event;
407    }
408
409    winPtr = (TkWindow *) Tk_IdToWindow(eventPtr->xany.display, handlerWindow);
410
411    if (winPtr == NULL) {
412	/*
413	 * There isn't a TkWindow structure for this window. However, if the
414	 * event is a PropertyNotify event then call the selection manager (it
415	 * deals beneath-the-table with certain properties). Also, if the
416	 * window's parent is a Tk window that has the TK_PROP_PROPCHANGE flag
417	 * set, then we must propagate the PropertyNotify event up to the
418	 * parent.
419	 */
420
421	if (eventPtr->type != PropertyNotify) {
422	    return NULL;
423	}
424	TkSelPropProc(eventPtr);
425	parentXId = ParentXId(eventPtr->xany.display, handlerWindow);
426	if (parentXId == None) {
427	    return NULL;
428	}
429	winPtr = (TkWindow *) Tk_IdToWindow(eventPtr->xany.display, parentXId);
430	if (winPtr == NULL) {
431	    return NULL;
432	}
433	if (!(winPtr->flags & TK_PROP_PROPCHANGE)) {
434	    return NULL;
435	}
436    }
437    return winPtr;
438}
439
440/*
441 *----------------------------------------------------------------------
442 *
443 * GetEventMaskFromXEvent --
444 *
445 *	The event type is looked up in our eventMasks tables, and may be
446 *	changed to a different mask depending on the state of the event and
447 *	window members.
448 *
449 * Results:
450 *	The mask for the event.
451 *
452 * Side effects:
453 *	None.
454 *
455 *----------------------------------------------------------------------
456 */
457
458static unsigned long
459GetEventMaskFromXEvent(
460    XEvent *eventPtr)
461{
462    unsigned long mask;
463
464    /*
465     * Get the event mask from the correct table. Note that there are two
466     * tables here because that means we no longer need this code to rely on
467     * the exact value of VirtualEvent, which has caused us problems in the
468     * past when X11 changed the value of LASTEvent. [Bug ???]
469     */
470
471    if (eventPtr->xany.type <= MappingNotify) {
472	mask = realEventMasks[eventPtr->xany.type];
473    } else if (eventPtr->xany.type >= VirtualEvent
474	    && eventPtr->xany.type<TK_LASTEVENT) {
475	mask = virtualEventMasks[eventPtr->xany.type - VirtualEvent];
476    } else {
477	mask = 0;
478    }
479
480    /*
481     * Events selected by StructureNotify require special handling. They look
482     * the same as those selected by SubstructureNotify. The only difference
483     * is whether the "event" and "window" fields are the same. Compare the
484     * two fields and convert StructureNotify to SubstructureNotify if
485     * necessary.
486     */
487
488    if (mask == StructureNotifyMask) {
489	if (eventPtr->xmap.event != eventPtr->xmap.window) {
490	    mask = SubstructureNotifyMask;
491	}
492    }
493    return mask;
494}
495
496/*
497 *----------------------------------------------------------------------
498 *
499 * RefreshKeyboardMappingIfNeeded --
500 *
501 *	If the event is a MappingNotify event, find its display and refresh
502 *	the keyboard mapping information for the display.
503 *
504 * Results:
505 *	0 if the event was not a MappingNotify event
506 *	1 if the event was a MappingNotify event
507 *
508 * Side effects:
509 *	None.
510 *
511 *----------------------------------------------------------------------
512 */
513
514static int
515RefreshKeyboardMappingIfNeeded(
516    XEvent *eventPtr)
517{
518    TkDisplay *dispPtr;
519
520    if (eventPtr->type == MappingNotify) {
521	dispPtr = TkGetDisplay(eventPtr->xmapping.display);
522	if (dispPtr != NULL) {
523	    XRefreshKeyboardMapping(&eventPtr->xmapping);
524	    dispPtr->bindInfoStale = 1;
525	}
526	return 1;
527    }
528    return 0;
529}
530
531/*
532 *----------------------------------------------------------------------
533 *
534 * GetButtonMask --
535 *
536 *	Return the proper Button${n}Mask for the button.
537 *
538 * Results:
539 *	A button mask.
540 *
541 * Side effects:
542 *	None.
543 *
544 *----------------------------------------------------------------------
545 */
546
547static int
548GetButtonMask(
549    unsigned int button)
550{
551    switch (button) {
552    case 1:
553	return Button1Mask;
554    case 2:
555	return Button2Mask;
556    case 3:
557	return Button3Mask;
558    case 4:
559	return Button4Mask;
560    case 5:
561	return Button5Mask;
562    }
563    return 0;
564}
565
566/*
567 *----------------------------------------------------------------------
568 *
569 * UpdateButtonEventState --
570 *
571 *	Update the button event state in our TkDisplay using the XEvent
572 *	passed. We also may modify the the XEvent passed to fit some aspects
573 *	of our TkDisplay.
574 *
575 * Results:
576 *	None.
577 *
578 * Side effects:
579 *	The TkDisplay's private button state may be modified. The eventPtr's
580 *	state may be updated to reflect masks stored in our TkDisplay that the
581 *	event doesn't contain. The eventPtr may also be modified to not
582 *	contain a button state for the window in which it was not pressed in.
583 *
584 *----------------------------------------------------------------------
585 */
586
587static void
588UpdateButtonEventState(
589    XEvent *eventPtr)
590{
591    TkDisplay *dispPtr;
592    int allButtonsMask = Button1Mask | Button2Mask | Button3Mask
593	    | Button4Mask | Button5Mask;
594
595    switch (eventPtr->type) {
596    case ButtonPress:
597	dispPtr = TkGetDisplay(eventPtr->xbutton.display);
598	dispPtr->mouseButtonWindow = eventPtr->xbutton.window;
599	eventPtr->xbutton.state |= dispPtr->mouseButtonState;
600
601	dispPtr->mouseButtonState |= GetButtonMask(eventPtr->xbutton.button);
602	break;
603
604    case ButtonRelease:
605	dispPtr = TkGetDisplay(eventPtr->xbutton.display);
606	dispPtr->mouseButtonWindow = None;
607	dispPtr->mouseButtonState &= ~GetButtonMask(eventPtr->xbutton.button);
608	eventPtr->xbutton.state |= dispPtr->mouseButtonState;
609	break;
610
611    case MotionNotify:
612	dispPtr = TkGetDisplay(eventPtr->xmotion.display);
613	if (dispPtr->mouseButtonState & allButtonsMask) {
614	    if (eventPtr->xbutton.window != dispPtr->mouseButtonWindow) {
615		/*
616		 * This motion event should not be interpreted as a button
617		 * press + motion event since this is not the same window the
618		 * button was pressed down in.
619		 */
620
621		dispPtr->mouseButtonState &= ~allButtonsMask;
622		dispPtr->mouseButtonWindow = None;
623	    } else {
624		eventPtr->xmotion.state |= dispPtr->mouseButtonState;
625	    }
626	}
627	break;
628    }
629}
630
631/*
632 *----------------------------------------------------------------------
633 *
634 * InvokeClientMessageHandlers --
635 *
636 *	Iterate the list of handlers and invoke the function pointer for each.
637 *
638 * Results:
639 *	None.
640 *
641 * Side effects:
642 *	Handlers may be deleted and events may be sent to handlers.
643 *
644 *----------------------------------------------------------------------
645 */
646
647static void
648InvokeClientMessageHandlers(
649    ThreadSpecificData *tsdPtr,
650    Tk_Window tkwin,
651    XEvent *eventPtr)
652{
653    GenericHandler *prevPtr, *tmpPtr, *curPtr = tsdPtr->cmList;
654
655    for (prevPtr = NULL; curPtr != NULL; ) {
656	if (curPtr->deleteFlag) {
657	    if (!tsdPtr->handlersActive) {
658		/*
659		 * This handler needs to be deleted and there are no calls
660		 * pending through any handlers, so now is a safe time to
661		 * delete it.
662		 */
663
664		tmpPtr = curPtr->nextPtr;
665		if (prevPtr == NULL) {
666		    tsdPtr->cmList = tmpPtr;
667		} else {
668		    prevPtr->nextPtr = tmpPtr;
669		}
670		if (tmpPtr == NULL) {
671		    tsdPtr->lastCmPtr = prevPtr;
672		}
673		(void) ckfree((char *) curPtr);
674		curPtr = tmpPtr;
675		continue;
676	    }
677	} else {
678	    int done;
679
680	    tsdPtr->handlersActive++;
681	    done = (*(Tk_ClientMessageProc *)curPtr->proc)(tkwin, eventPtr);
682	    tsdPtr->handlersActive--;
683	    if (done) {
684		break;
685	    }
686	}
687	prevPtr = curPtr;
688	curPtr = curPtr->nextPtr;
689    }
690}
691
692/*
693 *----------------------------------------------------------------------
694 *
695 * InvokeGenericHandlers --
696 *
697 *	Iterate the list of handlers and invoke the function pointer for each.
698 *	If the handler invoked returns a non-zero value then we are done.
699 *
700 * Results:
701 *	0 when the event wasn't handled by a handler. Non-zero when it was
702 *	processed and handled by a handler.
703 *
704 * Side effects:
705 *	Handlers may be deleted and events may be sent to handlers.
706 *
707 *----------------------------------------------------------------------
708 */
709
710static int
711InvokeGenericHandlers(
712    ThreadSpecificData *tsdPtr,
713    XEvent *eventPtr)
714{
715    GenericHandler *prevPtr, *tmpPtr, *curPtr = tsdPtr->genericList;
716
717    for (prevPtr = NULL; curPtr != NULL; ) {
718	if (curPtr->deleteFlag) {
719	    if (!tsdPtr->handlersActive) {
720		/*
721		 * This handler needs to be deleted and there are no calls
722		 * pending through the handler, so now is a safe time to
723		 * delete it.
724		 */
725
726		tmpPtr = curPtr->nextPtr;
727		if (prevPtr == NULL) {
728		    tsdPtr->genericList = tmpPtr;
729		} else {
730		    prevPtr->nextPtr = tmpPtr;
731		}
732		if (tmpPtr == NULL) {
733		    tsdPtr->lastGenericPtr = prevPtr;
734		}
735		(void) ckfree((char *) curPtr);
736		curPtr = tmpPtr;
737		continue;
738	    }
739	} else {
740	    int done;
741
742	    tsdPtr->handlersActive++;
743	    done = (*curPtr->proc)(curPtr->clientData, eventPtr);
744	    tsdPtr->handlersActive--;
745	    if (done) {
746		return done;
747	    }
748	}
749	prevPtr = curPtr;
750	curPtr = curPtr->nextPtr;
751    }
752    return 0;
753}
754
755/*
756 *----------------------------------------------------------------------
757 *
758 * Tk_CreateEventHandler --
759 *
760 *	Arrange for a given function to be invoked whenever events from a
761 *	given class occur in a given window.
762 *
763 * Results:
764 *	None.
765 *
766 * Side effects:
767 *	From now on, whenever an event of the type given by mask occurs for
768 *	token and is processed by Tk_HandleEvent, proc will be called. See the
769 *	manual entry for details of the calling sequence and return value for
770 *	proc.
771 *
772 *----------------------------------------------------------------------
773 */
774
775void
776Tk_CreateEventHandler(
777    Tk_Window token,		/* Token for window in which to create
778				 * handler. */
779    unsigned long mask,		/* Events for which proc should be called. */
780    Tk_EventProc *proc,		/* Function to call for each selected event */
781    ClientData clientData)	/* Arbitrary data to pass to proc. */
782{
783    register TkEventHandler *handlerPtr;
784    register TkWindow *winPtr = (TkWindow *) token;
785
786    /*
787     * Skim through the list of existing handlers to (a) compute the overall
788     * event mask for the window (so we can pass this new value to the X
789     * system) and (b) see if there's already a handler declared with the same
790     * callback and clientData (if so, just change the mask). If no existing
791     * handler matches, then create a new handler.
792     */
793
794    if (winPtr->handlerList == NULL) {
795	/*
796	 * No event handlers defined at all, so must create.
797	 */
798
799	handlerPtr = (TkEventHandler *) ckalloc(sizeof(TkEventHandler));
800	winPtr->handlerList = handlerPtr;
801    } else {
802	int found = 0;
803
804	for (handlerPtr = winPtr->handlerList; ;
805		handlerPtr = handlerPtr->nextPtr) {
806	    if ((handlerPtr->proc == proc)
807		    && (handlerPtr->clientData == clientData)) {
808		handlerPtr->mask = mask;
809		found = 1;
810	    }
811	    if (handlerPtr->nextPtr == NULL) {
812		break;
813	    }
814	}
815
816	/*
817	 * If we found anything, we're done because we do not need to use
818	 * XSelectInput; Tk always selects on all events anyway in order to
819	 * support binding on classes, 'all' and other bind-tags.
820	 */
821
822	if (found) {
823	    return;
824	}
825
826	/*
827	 * No event handler matched, so create a new one.
828	 */
829
830	handlerPtr->nextPtr = (TkEventHandler *)
831		ckalloc(sizeof(TkEventHandler));
832	handlerPtr = handlerPtr->nextPtr;
833    }
834
835    /*
836     * Initialize the new event handler.
837     */
838
839    handlerPtr->mask = mask;
840    handlerPtr->proc = proc;
841    handlerPtr->clientData = clientData;
842    handlerPtr->nextPtr = NULL;
843
844    /*
845     * No need to call XSelectInput: Tk always selects on all events for all
846     * windows (needed to support bindings on classes and "all").
847     */
848}
849
850/*
851 *----------------------------------------------------------------------
852 *
853 * Tk_DeleteEventHandler --
854 *
855 *	Delete a previously-created handler.
856 *
857 * Results:
858 *	None.
859 *
860 * Side effects:
861 *	If there existed a handler as described by the parameters, the handler
862 *	is deleted so that proc will not be invoked again.
863 *
864 *----------------------------------------------------------------------
865 */
866
867void
868Tk_DeleteEventHandler(
869    Tk_Window token,		/* Same as corresponding arguments passed */
870    unsigned long mask,		/* previously to Tk_CreateEventHandler. */
871    Tk_EventProc *proc,
872    ClientData clientData)
873{
874    register TkEventHandler *handlerPtr;
875    register InProgress *ipPtr;
876    TkEventHandler *prevPtr;
877    register TkWindow *winPtr = (TkWindow *) token;
878    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
879	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
880
881    /*
882     * Find the event handler to be deleted, or return immediately if it
883     * doesn't exist.
884     */
885
886    for (handlerPtr = winPtr->handlerList, prevPtr = NULL; ;
887	    prevPtr = handlerPtr, handlerPtr = handlerPtr->nextPtr) {
888	if (handlerPtr == NULL) {
889	    return;
890	}
891	if ((handlerPtr->mask == mask) && (handlerPtr->proc == proc)
892		&& (handlerPtr->clientData == clientData)) {
893	    break;
894	}
895    }
896
897    /*
898     * If Tk_HandleEvent is about to process this handler, tell it to process
899     * the next one instead.
900     */
901
902    for (ipPtr = tsdPtr->pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) {
903	if (ipPtr->nextHandler == handlerPtr) {
904	    ipPtr->nextHandler = handlerPtr->nextPtr;
905	}
906    }
907
908    /*
909     * Free resources associated with the handler.
910     */
911
912    if (prevPtr == NULL) {
913	winPtr->handlerList = handlerPtr->nextPtr;
914    } else {
915	prevPtr->nextPtr = handlerPtr->nextPtr;
916    }
917    ckfree((char *) handlerPtr);
918
919    /*
920     * No need to call XSelectInput: Tk always selects on all events for all
921     * windows (needed to support bindings on classes and "all").
922     */
923}
924
925/*----------------------------------------------------------------------
926 *
927 * Tk_CreateGenericHandler --
928 *
929 *	Register a function to be called on each X event, regardless of
930 *	display or window. Generic handlers are useful for capturing events
931 *	that aren't associated with windows, or events for windows not managed
932 *	by Tk.
933 *
934 * Results:
935 *	None.
936 *
937 * Side Effects:
938 *	From now on, whenever an X event is given to Tk_HandleEvent, invoke
939 *	proc, giving it clientData and the event as arguments.
940 *
941 *----------------------------------------------------------------------
942 */
943
944void
945Tk_CreateGenericHandler(
946    Tk_GenericProc *proc,	/* Function to call on every event. */
947    ClientData clientData)	/* One-word value to pass to proc. */
948{
949    GenericHandler *handlerPtr;
950    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
951	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
952
953    handlerPtr = (GenericHandler *) ckalloc(sizeof(GenericHandler));
954
955    handlerPtr->proc		= proc;
956    handlerPtr->clientData	= clientData;
957    handlerPtr->deleteFlag	= 0;
958    handlerPtr->nextPtr		= NULL;
959    if (tsdPtr->genericList == NULL) {
960	tsdPtr->genericList	= handlerPtr;
961    } else {
962	tsdPtr->lastGenericPtr->nextPtr = handlerPtr;
963    }
964    tsdPtr->lastGenericPtr	= handlerPtr;
965}
966
967/*
968 *----------------------------------------------------------------------
969 *
970 * Tk_DeleteGenericHandler --
971 *
972 *	Delete a previously-created generic handler.
973 *
974 * Results:
975 *	None.
976 *
977 * Side Effects:
978 *	If there existed a handler as described by the parameters, that
979 *	handler is logically deleted so that proc will not be invoked again.
980 *	The physical deletion happens in the event loop in Tk_HandleEvent.
981 *
982 *----------------------------------------------------------------------
983 */
984
985void
986Tk_DeleteGenericHandler(
987    Tk_GenericProc *proc,
988    ClientData clientData)
989{
990    GenericHandler * handler;
991    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
992	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
993
994    for (handler=tsdPtr->genericList ; handler ; handler=handler->nextPtr) {
995	if ((handler->proc == proc) && (handler->clientData == clientData)) {
996	    handler->deleteFlag = 1;
997	}
998    }
999}
1000
1001/*----------------------------------------------------------------------
1002 *
1003 * Tk_CreateClientMessageHandler --
1004 *
1005 *	Register a function to be called on each ClientMessage event.
1006 *	ClientMessage handlers are useful for Drag&Drop extensions.
1007 *
1008 * Results:
1009 *	None.
1010 *
1011 * Side Effects:
1012 *	From now on, whenever a ClientMessage event is received that isn't a
1013 *	WM_PROTOCOL event or SelectionEvent, invoke proc, giving it tkwin and
1014 *	the event as arguments.
1015 *
1016 *----------------------------------------------------------------------
1017 */
1018
1019void
1020Tk_CreateClientMessageHandler(
1021    Tk_ClientMessageProc *proc)	/* Function to call on event. */
1022{
1023    GenericHandler *handlerPtr;
1024    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
1025	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1026
1027    /*
1028     * We use a GenericHandler struct, because it's basically the same, except
1029     * with an extra clientData field we'll never use.
1030     */
1031
1032    handlerPtr = (GenericHandler *) ckalloc(sizeof(GenericHandler));
1033
1034    handlerPtr->proc = (Tk_GenericProc *) proc;
1035    handlerPtr->clientData = NULL;	/* never used */
1036    handlerPtr->deleteFlag = 0;
1037    handlerPtr->nextPtr = NULL;
1038    if (tsdPtr->cmList == NULL) {
1039	tsdPtr->cmList = handlerPtr;
1040    } else {
1041	tsdPtr->lastCmPtr->nextPtr = handlerPtr;
1042    }
1043    tsdPtr->lastCmPtr = handlerPtr;
1044}
1045
1046/*
1047 *----------------------------------------------------------------------
1048 *
1049 * Tk_DeleteClientMessageHandler --
1050 *
1051 *	Delete a previously-created ClientMessage handler.
1052 *
1053 * Results:
1054 *	None.
1055 *
1056 * Side Effects:
1057 *	If there existed a handler as described by the parameters, that
1058 *	handler is logically deleted so that proc will not be invoked again.
1059 *	The physical deletion happens in the event loop in
1060 *	TkClientMessageEventProc.
1061 *
1062 *----------------------------------------------------------------------
1063 */
1064
1065void
1066Tk_DeleteClientMessageHandler(
1067    Tk_ClientMessageProc *proc)
1068{
1069    GenericHandler * handler;
1070    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
1071	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1072
1073    for (handler=tsdPtr->cmList ; handler!=NULL ; handler=handler->nextPtr) {
1074	if (handler->proc == (Tk_GenericProc *) proc) {
1075	    handler->deleteFlag = 1;
1076	}
1077    }
1078}
1079
1080/*
1081 *----------------------------------------------------------------------
1082 *
1083 * TkEventInit --
1084 *
1085 *	This functions initializes all the event module structures used by the
1086 *	current thread. It must be called before any other function in this
1087 *	file is called.
1088 *
1089 * Results:
1090 *	None.
1091 *
1092 * Side Effects:
1093 *	None.
1094 *
1095 *----------------------------------------------------------------------
1096 */
1097
1098void
1099TkEventInit(void)
1100{
1101    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
1102	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1103
1104    tsdPtr->handlersActive	= 0;
1105    tsdPtr->pendingPtr		= NULL;
1106    tsdPtr->genericList		= NULL;
1107    tsdPtr->lastGenericPtr	= NULL;
1108    tsdPtr->cmList		= NULL;
1109    tsdPtr->lastCmPtr		= NULL;
1110    tsdPtr->restrictProc	= NULL;
1111    tsdPtr->restrictArg		= NULL;
1112}
1113
1114/*
1115 *----------------------------------------------------------------------
1116 *
1117 * TkXErrorHandler --
1118 *
1119 *	TkXErrorHandler is an error handler, to be installed via
1120 *	Tk_CreateErrorHandler, that will set a flag if an X error occurred.
1121 *
1122 * Results:
1123 *	Always returns 0, indicating that the X error was handled.
1124 *
1125 * Side effects:
1126 *	None.
1127 *
1128 *----------------------------------------------------------------------
1129 */
1130
1131static int
1132TkXErrorHandler(
1133    ClientData clientData,	/* Pointer to flag we set. */
1134    XErrorEvent *errEventPtr)	/* X error info. */
1135{
1136    int *error;
1137
1138    error = (int *) clientData;
1139    *error = 1;
1140    return 0;
1141}
1142
1143/*
1144 *----------------------------------------------------------------------
1145 *
1146 * ParentXId --
1147 *
1148 *	Returns the parent of the given window, or "None" if the window
1149 *	doesn't exist.
1150 *
1151 * Results:
1152 *	Returns an X window ID.
1153 *
1154 * Side effects:
1155 *	None.
1156 *
1157 *----------------------------------------------------------------------
1158 */
1159
1160static Window
1161ParentXId(
1162    Display *display,
1163    Window w)
1164{
1165    Tk_ErrorHandler handler;
1166    int gotXError;
1167    Status status;
1168    Window parent;
1169    Window root;
1170    Window *childList;
1171    unsigned int nChildren;
1172
1173    /*
1174     * Handle errors ourselves.
1175     */
1176
1177    gotXError = 0;
1178    handler = Tk_CreateErrorHandler(display, -1, -1, -1,
1179	    TkXErrorHandler, (ClientData) (&gotXError));
1180
1181    /*
1182     * Get the parent window.
1183     */
1184
1185    status = XQueryTree(display, w, &root, &parent, &childList, &nChildren);
1186
1187    /*
1188     * Do some cleanup; gotta return "None" if we got an error.
1189     */
1190
1191    Tk_DeleteErrorHandler(handler);
1192    XSync(display, False);
1193    if (status != 0 && childList != NULL) {
1194	XFree(childList);
1195    }
1196    if (status == 0) {
1197	parent = None;
1198    }
1199
1200    return parent;
1201}
1202
1203/*
1204 *----------------------------------------------------------------------
1205 *
1206 * Tk_HandleEvent --
1207 *
1208 *	Given an event, invoke all the handlers that have been registered for
1209 *	the event.
1210 *
1211 * Results:
1212 *	None.
1213 *
1214 * Side effects:
1215 *	Depends on the handlers.
1216 *
1217 *----------------------------------------------------------------------
1218 */
1219
1220void
1221Tk_HandleEvent(
1222    XEvent *eventPtr)	/* Event to dispatch. */
1223{
1224    register TkEventHandler *handlerPtr;
1225    TkWindow *winPtr;
1226    unsigned long mask;
1227    InProgress ip;
1228    Tcl_Interp *interp = NULL;
1229    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
1230	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1231
1232    UpdateButtonEventState(eventPtr);
1233
1234    /*
1235     * If the generic handler processed this event we are done and can return.
1236     */
1237
1238    if (InvokeGenericHandlers(tsdPtr, eventPtr)) {
1239	goto releaseEventResources;
1240    }
1241
1242    if (RefreshKeyboardMappingIfNeeded(eventPtr)) {
1243	/*
1244	 * We are done with a MappingNotify event.
1245	 */
1246
1247	goto releaseEventResources;
1248    }
1249
1250    mask = GetEventMaskFromXEvent(eventPtr);
1251    winPtr = GetTkWindowFromXEvent(eventPtr);
1252
1253    if (winPtr == NULL) {
1254	goto releaseEventResources;
1255    }
1256
1257    /*
1258     * Once a window has started getting deleted, don't process any more
1259     * events for it except for the DestroyNotify event. This check is needed
1260     * because a DestroyNotify handler could re-invoke the event loop, causing
1261     * other pending events to be handled for the window (the window doesn't
1262     * get totally expunged from our tables until after the DestroyNotify
1263     * event has been completely handled).
1264     */
1265
1266    if ((winPtr->flags & TK_ALREADY_DEAD)
1267	    && (eventPtr->type != DestroyNotify)) {
1268	goto releaseEventResources;
1269    }
1270
1271    if (winPtr->mainPtr != NULL) {
1272	int result;
1273
1274	interp = winPtr->mainPtr->interp;
1275
1276	/*
1277	 * Protect interpreter for this window from possible deletion while we
1278	 * are dealing with the event for this window. Thus, widget writers do
1279	 * not have to worry about protecting the interpreter in their own
1280	 * code.
1281	 */
1282
1283	Tcl_Preserve((ClientData) interp);
1284
1285	result = ((InvokeFocusHandlers(&winPtr, mask, eventPtr))
1286		|| (InvokeMouseHandlers(winPtr, mask, eventPtr)));
1287
1288	if (result) {
1289	    goto releaseInterpreter;
1290	}
1291    }
1292
1293    /*
1294     * Create the input context for the window if it hasn't already been done
1295     * (XFilterEvent needs this context). When the event is a FocusIn event,
1296     * set the input context focus to the receiving window. This code is only
1297     * ever active for X11.
1298     */
1299
1300#ifdef TK_USE_INPUT_METHODS
1301    if ((winPtr->dispPtr->flags & TK_DISPLAY_USE_IM)) {
1302	if (!(winPtr->flags & (TK_CHECKED_IC|TK_ALREADY_DEAD))) {
1303	    winPtr->flags |= TK_CHECKED_IC;
1304	    if (winPtr->dispPtr->inputMethod != NULL) {
1305		CreateXIC(winPtr);
1306	    }
1307	}
1308	if (eventPtr->type == FocusIn && winPtr->inputContext != NULL) {
1309	    XSetICFocus(winPtr->inputContext);
1310	}
1311    }
1312#endif
1313
1314    /*
1315     * For events where it hasn't already been done, update the current time
1316     * in the display.
1317     */
1318
1319    if (eventPtr->type == PropertyNotify) {
1320	winPtr->dispPtr->lastEventTime = eventPtr->xproperty.time;
1321    }
1322
1323    /*
1324     * There's a potential interaction here with Tk_DeleteEventHandler. Read
1325     * the documentation for pendingPtr.
1326     */
1327
1328    ip.eventPtr = eventPtr;
1329    ip.winPtr = winPtr;
1330    ip.nextHandler = NULL;
1331    ip.nextPtr = tsdPtr->pendingPtr;
1332    tsdPtr->pendingPtr = &ip;
1333    if (mask == 0) {
1334	if ((eventPtr->type == SelectionClear)
1335		|| (eventPtr->type == SelectionRequest)
1336		|| (eventPtr->type == SelectionNotify)) {
1337	    TkSelEventProc((Tk_Window) winPtr, eventPtr);
1338	} else if (eventPtr->type == ClientMessage) {
1339	    if (eventPtr->xclient.message_type ==
1340		    Tk_InternAtom((Tk_Window) winPtr, "WM_PROTOCOLS")) {
1341		TkWmProtocolEventProc(winPtr, eventPtr);
1342	    } else {
1343		InvokeClientMessageHandlers(tsdPtr, (Tk_Window)winPtr,
1344			eventPtr);
1345	    }
1346	}
1347    } else {
1348	for (handlerPtr = winPtr->handlerList; handlerPtr != NULL; ) {
1349	    if ((handlerPtr->mask & mask) != 0) {
1350		ip.nextHandler = handlerPtr->nextPtr;
1351		(*(handlerPtr->proc))(handlerPtr->clientData, eventPtr);
1352		handlerPtr = ip.nextHandler;
1353	    } else {
1354		handlerPtr = handlerPtr->nextPtr;
1355	    }
1356	}
1357
1358	/*
1359	 * Pass the event to the "bind" command mechanism. But, don't do this
1360	 * for SubstructureNotify events. The "bind" command doesn't support
1361	 * them anyway, and it's easier to filter out these events here than
1362	 * in the lower-level functions.
1363	 */
1364
1365	/*
1366	 * ...well, except when we use the tkwm patches, in which case we DO
1367	 * handle CreateNotify events, so we gotta pass 'em through.
1368	 */
1369
1370	if ((ip.winPtr != None)
1371		&& ((mask != SubstructureNotifyMask)
1372		|| (eventPtr->type == CreateNotify))) {
1373	    TkBindEventProc(winPtr, eventPtr);
1374	}
1375    }
1376    tsdPtr->pendingPtr = ip.nextPtr;
1377
1378    /*
1379     * Release the interpreter for this window so that it can be potentially
1380     * deleted if requested.
1381     */
1382
1383  releaseInterpreter:
1384    if (interp != NULL) {
1385	Tcl_Release((ClientData) interp);
1386    }
1387
1388    /*
1389     * Release the user_data from the event (if it is a virtual event and the
1390     * field was non-NULL in the first place.) Note that this is done using a
1391     * Tcl_Obj interface, and we set the field back to NULL afterwards out of
1392     * paranoia. Also clean up any cached %A substitutions from key events.
1393     */
1394
1395  releaseEventResources:
1396    CleanUpTkEvent(eventPtr);
1397}
1398
1399/*
1400 *----------------------------------------------------------------------
1401 *
1402 * TkEventDeadWindow --
1403 *
1404 *	This function is invoked when it is determined that a window is dead.
1405 *	It cleans up event-related information about the window.
1406 *
1407 * Results:
1408 *	None.
1409 *
1410 * Side effects:
1411 *	Various things get cleaned up and recycled.
1412 *
1413 *----------------------------------------------------------------------
1414 */
1415
1416void
1417TkEventDeadWindow(
1418    TkWindow *winPtr)		/* Information about the window that is being
1419				 * deleted. */
1420{
1421    register TkEventHandler *handlerPtr;
1422    register InProgress *ipPtr;
1423    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
1424	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1425
1426    /*
1427     * While deleting all the handlers, be careful to check for Tk_HandleEvent
1428     * being about to process one of the deleted handlers. If it is, tell it
1429     * to quit (all of the handlers are being deleted).
1430     */
1431
1432    while (winPtr->handlerList != NULL) {
1433	handlerPtr = winPtr->handlerList;
1434	winPtr->handlerList = handlerPtr->nextPtr;
1435	for (ipPtr = tsdPtr->pendingPtr; ipPtr != NULL;
1436		ipPtr = ipPtr->nextPtr) {
1437	    if (ipPtr->nextHandler == handlerPtr) {
1438		ipPtr->nextHandler = NULL;
1439	    }
1440	    if (ipPtr->winPtr == winPtr) {
1441		ipPtr->winPtr = None;
1442	    }
1443	}
1444	ckfree((char *) handlerPtr);
1445    }
1446}
1447
1448/*
1449 *----------------------------------------------------------------------
1450 *
1451 * TkCurrentTime --
1452 *
1453 *	Try to deduce the current time. "Current time" means the time of the
1454 *	event that led to the current code being executed, which means the
1455 *	time in the most recently-nested invocation of Tk_HandleEvent.
1456 *
1457 * Results:
1458 *	The return value is the time from the current event, or CurrentTime if
1459 *	there is no current event or if the current event contains no time.
1460 *
1461 * Side effects:
1462 *	None.
1463 *
1464 *----------------------------------------------------------------------
1465 */
1466
1467Time
1468TkCurrentTime(
1469    TkDisplay *dispPtr)		/* Display for which the time is desired. */
1470{
1471    register XEvent *eventPtr;
1472    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
1473	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1474
1475    if (tsdPtr->pendingPtr == NULL) {
1476	return dispPtr->lastEventTime;
1477    }
1478    eventPtr = tsdPtr->pendingPtr->eventPtr;
1479    switch (eventPtr->type) {
1480    case ButtonPress:
1481    case ButtonRelease:
1482	return eventPtr->xbutton.time;
1483    case KeyPress:
1484    case KeyRelease:
1485	return eventPtr->xkey.time;
1486    case MotionNotify:
1487	return eventPtr->xmotion.time;
1488    case EnterNotify:
1489    case LeaveNotify:
1490	return eventPtr->xcrossing.time;
1491    case PropertyNotify:
1492	return eventPtr->xproperty.time;
1493    }
1494    return dispPtr->lastEventTime;
1495}
1496
1497/*
1498 *----------------------------------------------------------------------
1499 *
1500 * Tk_RestrictEvents --
1501 *
1502 *	This function is used to globally restrict the set of events that will
1503 *	be dispatched. The restriction is done by filtering all incoming X
1504 *	events through a function that determines whether they are to be
1505 *	processed immediately, deferred, or discarded.
1506 *
1507 * Results:
1508 *	The return value is the previous restriction function in effect, if
1509 *	there was one, or NULL if there wasn't.
1510 *
1511 * Side effects:
1512 *	From now on, proc will be called to determine whether to process,
1513 *	defer or discard each incoming X event.
1514 *
1515 *----------------------------------------------------------------------
1516 */
1517
1518Tk_RestrictProc *
1519Tk_RestrictEvents(
1520    Tk_RestrictProc *proc,	/* Function to call for each incoming event */
1521    ClientData arg,		/* Arbitrary argument to pass to proc. */
1522    ClientData *prevArgPtr)	/* Place to store information about previous
1523				 * argument. */
1524{
1525    Tk_RestrictProc *prev;
1526    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
1527	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1528
1529    prev = tsdPtr->restrictProc;
1530    *prevArgPtr = tsdPtr->restrictArg;
1531    tsdPtr->restrictProc = proc;
1532    tsdPtr->restrictArg = arg;
1533    return prev;
1534}
1535
1536/*
1537 *----------------------------------------------------------------------
1538 *
1539 * Tk_CollapseMotionEvents --
1540 *
1541 *	This function controls whether we collapse motion events in a
1542 *	particular display or not.
1543 *
1544 * Results:
1545 *	The return value is the previous collapse value in effect.
1546 *
1547 * Side effects:
1548 *	Filtering of motion events may be changed after calling this.
1549 *
1550 *----------------------------------------------------------------------
1551 */
1552
1553int
1554Tk_CollapseMotionEvents(
1555    Display *display,		/* Display handling these events. */
1556    int collapse)		/* Boolean value that specifies whether motion
1557				 * events should be collapsed. */
1558{
1559    TkDisplay *dispPtr = (TkDisplay *) display;
1560    int prev = (dispPtr->flags & TK_DISPLAY_COLLAPSE_MOTION_EVENTS);
1561
1562    if (collapse) {
1563	dispPtr->flags |= TK_DISPLAY_COLLAPSE_MOTION_EVENTS;
1564    } else {
1565	dispPtr->flags &= ~TK_DISPLAY_COLLAPSE_MOTION_EVENTS;
1566    }
1567    return prev;
1568}
1569
1570/*
1571 *----------------------------------------------------------------------
1572 *
1573 * Tk_QueueWindowEvent --
1574 *
1575 *	Given an X-style window event, this function adds it to the Tcl event
1576 *	queue at the given position. This function also performs mouse motion
1577 *	event collapsing if possible.
1578 *
1579 * Results:
1580 *	None.
1581 *
1582 * Side effects:
1583 *	Adds stuff to the event queue, which will eventually be processed.
1584 *
1585 *----------------------------------------------------------------------
1586 */
1587
1588void
1589Tk_QueueWindowEvent(
1590    XEvent *eventPtr,		/* Event to add to queue. This function copies
1591				 * it before adding it to the queue. */
1592    Tcl_QueuePosition position)	/* Where to put it on the queue:
1593				 * TCL_QUEUE_TAIL, TCL_QUEUE_HEAD, or
1594				 * TCL_QUEUE_MARK. */
1595{
1596    TkWindowEvent *wevPtr;
1597    TkDisplay *dispPtr;
1598
1599    /*
1600     * Find our display structure for the event's display.
1601     */
1602
1603    for (dispPtr = TkGetDisplayList(); ; dispPtr = dispPtr->nextPtr) {
1604	if (dispPtr == NULL) {
1605	    return;
1606	}
1607	if (dispPtr->display == eventPtr->xany.display) {
1608	    break;
1609	}
1610    }
1611
1612    /*
1613     * Don't filter motion events if the user defaulting to true (1), which
1614     * could be set to false (0) when the user wishes to receive all the
1615     * motion data)
1616     */
1617
1618    if (!(dispPtr->flags & TK_DISPLAY_COLLAPSE_MOTION_EVENTS)) {
1619	wevPtr = (TkWindowEvent *) ckalloc(sizeof(TkWindowEvent));
1620	wevPtr->header.proc = WindowEventProc;
1621	wevPtr->event = *eventPtr;
1622	Tcl_QueueEvent(&wevPtr->header, position);
1623	return;
1624    }
1625
1626    if ((dispPtr->delayedMotionPtr != NULL) && (position == TCL_QUEUE_TAIL)) {
1627	if ((eventPtr->type == MotionNotify) && (eventPtr->xmotion.window
1628		== dispPtr->delayedMotionPtr->event.xmotion.window)) {
1629	    /*
1630	     * The new event is a motion event in the same window as the saved
1631	     * motion event. Just replace the saved event with the new one.
1632	     */
1633
1634	    dispPtr->delayedMotionPtr->event = *eventPtr;
1635	    return;
1636	} else if ((eventPtr->type != GraphicsExpose)
1637		&& (eventPtr->type != NoExpose)
1638		&& (eventPtr->type != Expose)) {
1639	    /*
1640	     * The new event may conflict with the saved motion event. Queue
1641	     * the saved motion event now so that it will be processed before
1642	     * the new event.
1643	     */
1644
1645	    Tcl_QueueEvent(&dispPtr->delayedMotionPtr->header, position);
1646	    dispPtr->delayedMotionPtr = NULL;
1647	    Tcl_CancelIdleCall(DelayedMotionProc, (ClientData) dispPtr);
1648	}
1649    }
1650
1651    wevPtr = (TkWindowEvent *) ckalloc(sizeof(TkWindowEvent));
1652    wevPtr->header.proc = WindowEventProc;
1653    wevPtr->event = *eventPtr;
1654    if ((eventPtr->type == MotionNotify) && (position == TCL_QUEUE_TAIL)) {
1655	/*
1656	 * The new event is a motion event so don't queue it immediately; save
1657	 * it around in case another motion event arrives that it can be
1658	 * collapsed with.
1659	 */
1660
1661	if (dispPtr->delayedMotionPtr != NULL) {
1662	    Tcl_Panic("Tk_QueueWindowEvent found unexpected delayed motion event");
1663	}
1664	dispPtr->delayedMotionPtr = wevPtr;
1665	Tcl_DoWhenIdle(DelayedMotionProc, (ClientData) dispPtr);
1666    } else {
1667	Tcl_QueueEvent(&wevPtr->header, position);
1668    }
1669}
1670
1671/*
1672 *----------------------------------------------------------------------
1673 *
1674 * TkQueueEventForAllChildren --
1675 *
1676 *	Given an XEvent, recursively queue the event for this window and all
1677 *	non-toplevel children of the given window.
1678 *
1679 * Results:
1680 *	None.
1681 *
1682 * Side effects:
1683 *	Events queued.
1684 *
1685 *----------------------------------------------------------------------
1686 */
1687
1688void
1689TkQueueEventForAllChildren(
1690    TkWindow *winPtr,	    /* Window to which event is sent. */
1691    XEvent *eventPtr)	    /* The event to be sent. */
1692{
1693    TkWindow *childPtr;
1694
1695    if (!Tk_IsMapped(winPtr)) {
1696	return;
1697    }
1698
1699    eventPtr->xany.window = winPtr->window;
1700    Tk_QueueWindowEvent(eventPtr, TCL_QUEUE_TAIL);
1701
1702    childPtr = winPtr->childList;
1703    while (childPtr != NULL) {
1704	if (!Tk_TopWinHierarchy(childPtr)) {
1705	    TkQueueEventForAllChildren(childPtr, eventPtr);
1706	}
1707	childPtr = childPtr->nextPtr;
1708    }
1709}
1710
1711/*
1712 *----------------------------------------------------------------------
1713 *
1714 * WindowEventProc --
1715 *
1716 *	This function is called by Tcl_DoOneEvent when a window event reaches
1717 *	the front of the event queue. This function is responsible for
1718 *	actually handling the event.
1719 *
1720 * Results:
1721 *	Returns 1 if the event was handled, meaning it should be removed from
1722 *	the queue. Returns 0 if the event was not handled, meaning it should
1723 *	stay on the queue. The event isn't handled if the TCL_WINDOW_EVENTS
1724 *	bit isn't set in flags, if a restrict proc prevents the event from
1725 *	being handled.
1726 *
1727 * Side effects:
1728 *	Whatever the event handlers for the event do.
1729 *
1730 *----------------------------------------------------------------------
1731 */
1732
1733static int
1734WindowEventProc(
1735    Tcl_Event *evPtr,		/* Event to service. */
1736    int flags)			/* Flags that indicate what events to handle,
1737				 * such as TCL_WINDOW_EVENTS. */
1738{
1739    TkWindowEvent *wevPtr = (TkWindowEvent *) evPtr;
1740    Tk_RestrictAction result;
1741    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
1742	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1743
1744    if (!(flags & TCL_WINDOW_EVENTS)) {
1745	return 0;
1746    }
1747    if (tsdPtr->restrictProc != NULL) {
1748	result = (*tsdPtr->restrictProc)(tsdPtr->restrictArg, &wevPtr->event);
1749	if (result != TK_PROCESS_EVENT) {
1750	    if (result == TK_DEFER_EVENT) {
1751		return 0;
1752	    } else {
1753		/*
1754		 * TK_DELETE_EVENT: return and say we processed the event,
1755		 * even though we didn't do anything at all.
1756		 */
1757
1758		CleanUpTkEvent(&wevPtr->event);
1759		return 1;
1760	    }
1761	}
1762    }
1763    Tk_HandleEvent(&wevPtr->event);
1764    CleanUpTkEvent(&wevPtr->event);
1765    return 1;
1766}
1767
1768/*
1769 *----------------------------------------------------------------------
1770 *
1771 * CleanUpTkEvent --
1772 *
1773 *	This function is called to remove and deallocate any information in
1774 *	the event which is not directly in the event structure itself. It may
1775 *	be called multiple times per event, so it takes care to set the
1776 *	cleared pointer fields to NULL afterwards.
1777 *
1778 * Results:
1779 *	None.
1780 *
1781 * Side effects:
1782 *	Makes the event no longer have any external resources.
1783 *
1784 *----------------------------------------------------------------------
1785 */
1786
1787static void
1788CleanUpTkEvent(
1789    XEvent *eventPtr)
1790{
1791    switch (eventPtr->type) {
1792    case KeyPress:
1793    case KeyRelease: {
1794	TkKeyEvent *kePtr = (TkKeyEvent *) eventPtr;
1795
1796	if (kePtr->charValuePtr != NULL) {
1797	    ckfree(kePtr->charValuePtr);
1798	    kePtr->charValuePtr = NULL;
1799	    kePtr->charValueLen = 0;
1800	}
1801	break;
1802    }
1803
1804    case VirtualEvent: {
1805	XVirtualEvent *vePtr = (XVirtualEvent *) eventPtr;
1806
1807	if (vePtr->user_data != NULL) {
1808	    Tcl_DecrRefCount(vePtr->user_data);
1809	    vePtr->user_data = NULL;
1810	}
1811	break;
1812    }
1813    }
1814}
1815
1816/*
1817 *----------------------------------------------------------------------
1818 *
1819 * DelayedMotionProc --
1820 *
1821 *	This function is invoked as an idle handler when a mouse motion event
1822 *	has been delayed. It queues the delayed event so that it will finally
1823 *	be serviced.
1824 *
1825 * Results:
1826 *	None.
1827 *
1828 * Side effects:
1829 *	The delayed mouse motion event gets added to the Tcl event queue for
1830 *	servicing.
1831 *
1832 *----------------------------------------------------------------------
1833 */
1834
1835static void
1836DelayedMotionProc(
1837    ClientData clientData)	/* Pointer to display containing a delayed
1838				 * motion event to be serviced. */
1839{
1840    TkDisplay *dispPtr = (TkDisplay *) clientData;
1841
1842    if (dispPtr->delayedMotionPtr == NULL) {
1843	Tcl_Panic("DelayedMotionProc found no delayed mouse motion event");
1844    }
1845    Tcl_QueueEvent(&dispPtr->delayedMotionPtr->header, TCL_QUEUE_TAIL);
1846    dispPtr->delayedMotionPtr = NULL;
1847}
1848
1849/*
1850 *----------------------------------------------------------------------
1851 *
1852 * TkCreateExitHandler --
1853 *
1854 *	Same as Tcl_CreateExitHandler, but private to Tk.
1855 *
1856 * Results:
1857 *	None.
1858 *
1859 * Side effects.
1860 *	Sets a handler with Tcl_CreateExitHandler if this is the first call.
1861 *
1862 *----------------------------------------------------------------------
1863 */
1864
1865void
1866TkCreateExitHandler(
1867    Tcl_ExitProc *proc,		/* Function to invoke. */
1868    ClientData clientData)	/* Arbitrary value to pass to proc. */
1869{
1870    ExitHandler *exitPtr;
1871
1872    exitPtr = (ExitHandler *) ckalloc(sizeof(ExitHandler));
1873    exitPtr->proc = proc;
1874    exitPtr->clientData = clientData;
1875    Tcl_MutexLock(&exitMutex);
1876
1877    /*
1878     * The call to TclInExit() is disabled here. That's a private Tcl routine,
1879     * and calling it is causing some trouble with portability of building Tk.
1880     * We should avoid private Tcl routines generally.
1881     *
1882     * In this case, the TclInExit() call is being used only to prevent a
1883     * Tcl_CreateExitHandler() call when Tcl finalization is in progress.
1884     * That's a situation that shouldn't happen anyway. Recent changes within
1885     * Tcl_Finalize now cause a Tcl_Panic() to happen if exit handlers get
1886     * added after exit handling is complete. By disabling the guard here,
1887     * that panic will serve to help us find the buggy conditions and correct
1888     * them.
1889     *
1890     * We can restore this guard if we find we must (hopefully getting public
1891     * access to TclInExit() if we discover extensions really do need this),
1892     * but during alpha development, this is a good time to dig in and find
1893     * the root causes of finalization bugs.
1894     */
1895
1896    if (firstExitPtr == NULL/* && !TclInExit()*/) {
1897	Tcl_CreateExitHandler(TkFinalize, NULL);
1898    }
1899    exitPtr->nextPtr = firstExitPtr;
1900    firstExitPtr = exitPtr;
1901    Tcl_MutexUnlock(&exitMutex);
1902}
1903
1904/*
1905 *----------------------------------------------------------------------
1906 *
1907 * TkDeleteExitHandler --
1908 *
1909 *	Same as Tcl_DeleteExitHandler, but private to Tk.
1910 *
1911 * Results:
1912 *	None.
1913 *
1914 * Side effects.
1915 *	None.
1916 *
1917 *----------------------------------------------------------------------
1918 */
1919
1920void
1921TkDeleteExitHandler(
1922    Tcl_ExitProc *proc,		/* Function that was previously registered. */
1923    ClientData clientData)	/* Arbitrary value to pass to proc. */
1924{
1925    ExitHandler *exitPtr, *prevPtr;
1926
1927    Tcl_MutexLock(&exitMutex);
1928    for (prevPtr = NULL, exitPtr = firstExitPtr; exitPtr != NULL;
1929	    prevPtr = exitPtr, exitPtr = exitPtr->nextPtr) {
1930	if ((exitPtr->proc == proc)
1931		&& (exitPtr->clientData == clientData)) {
1932	    if (prevPtr == NULL) {
1933		firstExitPtr = exitPtr->nextPtr;
1934	    } else {
1935		prevPtr->nextPtr = exitPtr->nextPtr;
1936	    }
1937	    ckfree((char *) exitPtr);
1938	    break;
1939	}
1940    }
1941    Tcl_MutexUnlock(&exitMutex);
1942    return;
1943}
1944
1945/*
1946 *----------------------------------------------------------------------
1947 *
1948 * TkCreateThreadExitHandler --
1949 *
1950 *	Same as Tcl_CreateThreadExitHandler, but private to Tk.
1951 *
1952 * Results:
1953 *	None.
1954 *
1955 * Side effects:
1956 *	Proc will be invoked with clientData as argument when the application
1957 *	exits.
1958 *
1959 *----------------------------------------------------------------------
1960 */
1961
1962void
1963TkCreateThreadExitHandler(
1964    Tcl_ExitProc *proc,		/* Function to invoke. */
1965    ClientData clientData)	/* Arbitrary value to pass to proc. */
1966{
1967    ExitHandler *exitPtr;
1968    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
1969	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1970
1971    exitPtr = (ExitHandler *) ckalloc(sizeof(ExitHandler));
1972    exitPtr->proc = proc;
1973    exitPtr->clientData = clientData;
1974
1975    /*
1976     * See comments in TkCreateExitHandler().
1977     */
1978
1979    if (tsdPtr->firstExitPtr == NULL/* && !TclInExit()*/) {
1980	Tcl_CreateThreadExitHandler(TkFinalizeThread, NULL);
1981    }
1982    exitPtr->nextPtr = tsdPtr->firstExitPtr;
1983    tsdPtr->firstExitPtr = exitPtr;
1984}
1985
1986/*
1987 *----------------------------------------------------------------------
1988 *
1989 * TkDeleteThreadExitHandler --
1990 *
1991 *	Same as Tcl_DeleteThreadExitHandler, but private to Tk.
1992 *
1993 * Results:
1994 *	None.
1995 *
1996 * Side effects:
1997 *	If there is an exit handler corresponding to proc and clientData then
1998 *	it is cancelled; if no such handler exists then nothing happens.
1999 *
2000 *----------------------------------------------------------------------
2001 */
2002
2003void
2004TkDeleteThreadExitHandler(
2005    Tcl_ExitProc *proc,		/* Function that was previously registered. */
2006    ClientData clientData)	/* Arbitrary value to pass to proc. */
2007{
2008    ExitHandler *exitPtr, *prevPtr;
2009    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
2010	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
2011
2012    for (prevPtr = NULL, exitPtr = tsdPtr->firstExitPtr; exitPtr != NULL;
2013	    prevPtr = exitPtr, exitPtr = exitPtr->nextPtr) {
2014	if ((exitPtr->proc == proc)
2015		&& (exitPtr->clientData == clientData)) {
2016	    if (prevPtr == NULL) {
2017		tsdPtr->firstExitPtr = exitPtr->nextPtr;
2018	    } else {
2019		prevPtr->nextPtr = exitPtr->nextPtr;
2020	    }
2021	    ckfree((char *) exitPtr);
2022	    return;
2023	}
2024    }
2025}
2026
2027/*
2028 *----------------------------------------------------------------------
2029 *
2030 * TkFinalize --
2031 *
2032 *	Runs our private exit handlers and removes itself from Tcl. This is
2033 *	benificial should we want to protect from dangling pointers should the
2034 *	Tk shared library be unloaded prior to Tcl which can happen on windows
2035 *	should the process be forcefully exiting from an exception handler.
2036 *
2037 * Results:
2038 *	None.
2039 *
2040 * Side effects.
2041 *	None.
2042 *
2043 *----------------------------------------------------------------------
2044 */
2045
2046void
2047TkFinalize(
2048    ClientData clientData)	/* Arbitrary value to pass to proc. */
2049{
2050    ExitHandler *exitPtr;
2051
2052    Tcl_DeleteExitHandler(TkFinalize, NULL);
2053
2054    Tcl_MutexLock(&exitMutex);
2055    for (exitPtr = firstExitPtr; exitPtr != NULL; exitPtr = firstExitPtr) {
2056	/*
2057	 * Be careful to remove the handler from the list before invoking its
2058	 * callback. This protects us against double-freeing if the callback
2059	 * should call TkDeleteExitHandler on itself.
2060	 */
2061
2062	firstExitPtr = exitPtr->nextPtr;
2063	Tcl_MutexUnlock(&exitMutex);
2064	(*exitPtr->proc)(exitPtr->clientData);
2065	ckfree((char *) exitPtr);
2066	Tcl_MutexLock(&exitMutex);
2067    }
2068    firstExitPtr = NULL;
2069    Tcl_MutexUnlock(&exitMutex);
2070}
2071
2072/*
2073 *----------------------------------------------------------------------
2074 *
2075 * TkFinalizeThread --
2076 *
2077 *	Runs our private thread exit handlers and removes itself from Tcl.
2078 *	This is benificial should we want to protect from dangling pointers
2079 *	should the Tk shared library be unloaded prior to Tcl which can happen
2080 *	on Windows should the process be forcefully exiting from an exception
2081 *	handler.
2082 *
2083 * Results:
2084 *	None.
2085 *
2086 * Side effects.
2087 *	None.
2088 *
2089 *----------------------------------------------------------------------
2090 */
2091
2092void
2093TkFinalizeThread(
2094    ClientData clientData)	/* Arbitrary value to pass to proc. */
2095{
2096    ExitHandler *exitPtr;
2097    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
2098	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
2099
2100    Tcl_DeleteThreadExitHandler(TkFinalizeThread, NULL);
2101
2102    if (tsdPtr != NULL) {
2103	tsdPtr->inExit = 1;
2104
2105	for (exitPtr = tsdPtr->firstExitPtr; exitPtr != NULL;
2106		exitPtr = tsdPtr->firstExitPtr) {
2107	    /*
2108	     * Be careful to remove the handler from the list before invoking
2109	     * its callback. This protects us against double-freeing if the
2110	     * callback should call TkDeleteThreadExitHandler on itself.
2111	     */
2112
2113	    tsdPtr->firstExitPtr = exitPtr->nextPtr;
2114	    (*exitPtr->proc)(exitPtr->clientData);
2115	    ckfree((char *) exitPtr);
2116	}
2117    }
2118}
2119
2120/*
2121 *----------------------------------------------------------------------
2122 *
2123 * Tk_MainLoop --
2124 *
2125 *	Call Tcl_DoOneEvent over and over again in an infinite loop as long as
2126 *	there exist any main windows.
2127 *
2128 * Results:
2129 *	None.
2130 *
2131 * Side effects:
2132 *	Arbitrary; depends on handlers for events.
2133 *
2134 *----------------------------------------------------------------------
2135 */
2136
2137void
2138Tk_MainLoop(void)
2139{
2140    while (Tk_GetNumMainWindows() > 0) {
2141	Tcl_DoOneEvent(0);
2142    }
2143}
2144
2145/*
2146 * Local Variables:
2147 * mode: c
2148 * c-basic-offset: 4
2149 * fill-column: 78
2150 * End:
2151 */
2152