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

Annotation of /projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkevent.c

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:keywords Header

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25