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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 69 - (show annotations) (download)
Sat Nov 5 10:54:17 2016 UTC (6 years, 2 months ago) by dashley
File MIME type: text/plain
File size: 34615 byte(s)
License and property (keyword) changes.
1 /* $Header$ */
2
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 /* End of tkevent.c */

Properties

Name Value
svn:keywords Header

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25