Fix an amazing number of typos & malformed sentences reported by Detlef
[python/dscho.git] / Modules / tclNotify.c
blob429416e66ed40446bfe3f3167bd68450c454042c
1 /*
2 * This is a modified version of tclNotify.c from Sun's Tcl 8.0
3 * distribution. The purpose of the modification is to provide an
4 * interface to the internals of the notifier that make it possible to
5 * write safe multi-threaded Python programs that use Tkinter.
7 * Original comments follow. The file license.terms from the Tcl 8.0
8 * distribution is contained in this directory, as required.
9 */
11 /*
12 * tclNotify.c --
14 * This file implements the generic portion of the Tcl notifier.
15 * The notifier is lowest-level part of the event system. It
16 * manages an event queue that holds Tcl_Event structures. The
17 * platform specific portion of the notifier is defined in the
18 * tcl*Notify.c files in each platform directory.
20 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
22 * See the file "license.terms" for information on usage and redistribution
23 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
25 * SCCS: @(#) tclNotify.c 1.15 97/06/18 17:14:04
28 #include "tclInt.h"
29 #include "tclPort.h"
32 * The following static indicates whether this module has been initialized.
35 static int initialized = 0;
38 * For each event source (created with Tcl_CreateEventSource) there
39 * is a structure of the following type:
42 typedef struct EventSource {
43 Tcl_EventSetupProc *setupProc;
44 Tcl_EventCheckProc *checkProc;
45 ClientData clientData;
46 struct EventSource *nextPtr;
47 } EventSource;
50 * The following structure keeps track of the state of the notifier.
51 * The first three elements keep track of the event queue. In addition to
52 * the first (next to be serviced) and last events in the queue, we keep
53 * track of a "marker" event. This provides a simple priority mechanism
54 * whereby events can be inserted at the front of the queue but behind all
55 * other high-priority events already in the queue (this is used for things
56 * like a sequence of Enter and Leave events generated during a grab in
57 * Tk).
60 static struct {
61 Tcl_Event *firstEventPtr; /* First pending event, or NULL if none. */
62 Tcl_Event *lastEventPtr; /* Last pending event, or NULL if none. */
63 Tcl_Event *markerEventPtr; /* Last high-priority event in queue, or
64 * NULL if none. */
65 int serviceMode; /* One of TCL_SERVICE_NONE or
66 * TCL_SERVICE_ALL. */
67 int blockTimeSet; /* 0 means there is no maximum block
68 * time: block forever. */
69 Tcl_Time blockTime; /* If blockTimeSet is 1, gives the
70 * maximum elapsed time for the next block. */
71 int inTraversal; /* 1 if Tcl_SetMaxBlockTime is being
72 * called during an event source traversal. */
73 EventSource *firstEventSourcePtr;
74 /* Pointer to first event source in
75 * global list of event sources. */
76 } notifier;
79 * Declarations for functions used in this file.
82 static void InitNotifier _ANSI_ARGS_((void));
83 static void NotifierExitHandler _ANSI_ARGS_((ClientData clientData));
87 *----------------------------------------------------------------------
89 * InitNotifier --
91 * This routine is called to initialize the notifier module.
93 * Results:
94 * None.
96 * Side effects:
97 * Creates an exit handler and initializes static data.
99 *----------------------------------------------------------------------
102 static void
103 InitNotifier()
105 initialized = 1;
106 memset(&notifier, 0, sizeof(notifier));
107 notifier.serviceMode = TCL_SERVICE_NONE;
108 Tcl_CreateExitHandler(NotifierExitHandler, NULL);
112 *----------------------------------------------------------------------
114 * NotifierExitHandler --
116 * This routine is called during Tcl finalization.
118 * Results:
119 * None.
121 * Side effects:
122 * Clears the notifier intialization flag.
124 *----------------------------------------------------------------------
127 static void
128 NotifierExitHandler(clientData)
129 ClientData clientData; /* Not used. */
131 initialized = 0;
135 *----------------------------------------------------------------------
137 * Tcl_CreateEventSource --
139 * This procedure is invoked to create a new source of events.
140 * The source is identified by a procedure that gets invoked
141 * during Tcl_DoOneEvent to check for events on that source
142 * and queue them.
145 * Results:
146 * None.
148 * Side effects:
149 * SetupProc and checkProc will be invoked each time that Tcl_DoOneEvent
150 * runs out of things to do. SetupProc will be invoked before
151 * Tcl_DoOneEvent calls select or whatever else it uses to wait
152 * for events. SetupProc typically calls functions like Tcl_WatchFile
153 * or Tcl_SetMaxBlockTime to indicate what to wait for.
155 * CheckProc is called after select or whatever operation was actually
156 * used to wait. It figures out whether anything interesting actually
157 * happened (e.g. by calling Tcl_FileReady), and then calls
158 * Tcl_QueueEvent to queue any events that are ready.
160 * Each of these procedures is passed two arguments, e.g.
161 * (*checkProc)(ClientData clientData, int flags));
162 * ClientData is the same as the clientData argument here, and flags
163 * is a combination of things like TCL_FILE_EVENTS that indicates
164 * what events are of interest: setupProc and checkProc use flags
165 * to figure out whether their events are relevant or not.
167 *----------------------------------------------------------------------
170 void
171 Tcl_CreateEventSource(setupProc, checkProc, clientData)
172 Tcl_EventSetupProc *setupProc; /* Procedure to invoke to figure out
173 * what to wait for. */
174 Tcl_EventCheckProc *checkProc; /* Procedure to call after waiting
175 * to see what happened. */
176 ClientData clientData; /* One-word argument to pass to
177 * setupProc and checkProc. */
179 EventSource *sourcePtr;
181 if (!initialized) {
182 InitNotifier();
185 sourcePtr = (EventSource *) ckalloc(sizeof(EventSource));
186 sourcePtr->setupProc = setupProc;
187 sourcePtr->checkProc = checkProc;
188 sourcePtr->clientData = clientData;
189 sourcePtr->nextPtr = notifier.firstEventSourcePtr;
190 notifier.firstEventSourcePtr = sourcePtr;
194 *----------------------------------------------------------------------
196 * Tcl_DeleteEventSource --
198 * This procedure is invoked to delete the source of events
199 * given by proc and clientData.
201 * Results:
202 * None.
204 * Side effects:
205 * The given event source is cancelled, so its procedure will
206 * never again be called. If no such source exists, nothing
207 * happens.
209 *----------------------------------------------------------------------
212 void
213 Tcl_DeleteEventSource(setupProc, checkProc, clientData)
214 Tcl_EventSetupProc *setupProc; /* Procedure to invoke to figure out
215 * what to wait for. */
216 Tcl_EventCheckProc *checkProc; /* Procedure to call after waiting
217 * to see what happened. */
218 ClientData clientData; /* One-word argument to pass to
219 * setupProc and checkProc. */
221 EventSource *sourcePtr, *prevPtr;
223 for (sourcePtr = notifier.firstEventSourcePtr, prevPtr = NULL;
224 sourcePtr != NULL;
225 prevPtr = sourcePtr, sourcePtr = sourcePtr->nextPtr) {
226 if ((sourcePtr->setupProc != setupProc)
227 || (sourcePtr->checkProc != checkProc)
228 || (sourcePtr->clientData != clientData)) {
229 continue;
231 if (prevPtr == NULL) {
232 notifier.firstEventSourcePtr = sourcePtr->nextPtr;
233 } else {
234 prevPtr->nextPtr = sourcePtr->nextPtr;
236 ckfree((char *) sourcePtr);
237 return;
242 *----------------------------------------------------------------------
244 * Tcl_QueueEvent --
246 * Insert an event into the Tk event queue at one of three
247 * positions: the head, the tail, or before a floating marker.
248 * Events inserted before the marker will be processed in
249 * first-in-first-out order, but before any events inserted at
250 * the tail of the queue. Events inserted at the head of the
251 * queue will be processed in last-in-first-out order.
253 * Results:
254 * None.
256 * Side effects:
257 * None.
259 *----------------------------------------------------------------------
262 void
263 Tcl_QueueEvent(evPtr, position)
264 Tcl_Event* evPtr; /* Event to add to queue. The storage
265 * space must have been allocated the caller
266 * with malloc (ckalloc), and it becomes
267 * the property of the event queue. It
268 * will be freed after the event has been
269 * handled. */
270 Tcl_QueuePosition position; /* One of TCL_QUEUE_TAIL, TCL_QUEUE_HEAD,
271 * TCL_QUEUE_MARK. */
273 if (!initialized) {
274 InitNotifier();
277 if (position == TCL_QUEUE_TAIL) {
279 * Append the event on the end of the queue.
282 evPtr->nextPtr = NULL;
283 if (notifier.firstEventPtr == NULL) {
284 notifier.firstEventPtr = evPtr;
285 } else {
286 notifier.lastEventPtr->nextPtr = evPtr;
288 notifier.lastEventPtr = evPtr;
289 } else if (position == TCL_QUEUE_HEAD) {
291 * Push the event on the head of the queue.
294 evPtr->nextPtr = notifier.firstEventPtr;
295 if (notifier.firstEventPtr == NULL) {
296 notifier.lastEventPtr = evPtr;
298 notifier.firstEventPtr = evPtr;
299 } else if (position == TCL_QUEUE_MARK) {
301 * Insert the event after the current marker event and advance
302 * the marker to the new event.
305 if (notifier.markerEventPtr == NULL) {
306 evPtr->nextPtr = notifier.firstEventPtr;
307 notifier.firstEventPtr = evPtr;
308 } else {
309 evPtr->nextPtr = notifier.markerEventPtr->nextPtr;
310 notifier.markerEventPtr->nextPtr = evPtr;
312 notifier.markerEventPtr = evPtr;
313 if (evPtr->nextPtr == NULL) {
314 notifier.lastEventPtr = evPtr;
320 *----------------------------------------------------------------------
322 * Tcl_DeleteEvents --
324 * Calls a procedure for each event in the queue and deletes those
325 * for which the procedure returns 1. Events for which the
326 * procedure returns 0 are left in the queue.
328 * Results:
329 * None.
331 * Side effects:
332 * Potentially removes one or more events from the event queue.
334 *----------------------------------------------------------------------
337 void
338 Tcl_DeleteEvents(proc, clientData)
339 Tcl_EventDeleteProc *proc; /* The procedure to call. */
340 ClientData clientData; /* type-specific data. */
342 Tcl_Event *evPtr, *prevPtr, *hold;
344 if (!initialized) {
345 InitNotifier();
348 for (prevPtr = (Tcl_Event *) NULL, evPtr = notifier.firstEventPtr;
349 evPtr != (Tcl_Event *) NULL;
351 if ((*proc) (evPtr, clientData) == 1) {
352 if (notifier.firstEventPtr == evPtr) {
353 notifier.firstEventPtr = evPtr->nextPtr;
354 if (evPtr->nextPtr == (Tcl_Event *) NULL) {
355 notifier.lastEventPtr = (Tcl_Event *) NULL;
357 } else {
358 prevPtr->nextPtr = evPtr->nextPtr;
360 hold = evPtr;
361 evPtr = evPtr->nextPtr;
362 ckfree((char *) hold);
363 } else {
364 prevPtr = evPtr;
365 evPtr = evPtr->nextPtr;
371 *----------------------------------------------------------------------
373 * Tcl_ServiceEvent --
375 * Process one event from the event queue, or invoke an
376 * asynchronous event handler.
378 * Results:
379 * The return value is 1 if the procedure actually found an event
380 * to process. If no processing occurred, then 0 is returned.
382 * Side effects:
383 * Invokes all of the event handlers for the highest priority
384 * event in the event queue. May collapse some events into a
385 * single event or discard stale events.
387 *----------------------------------------------------------------------
391 Tcl_ServiceEvent(flags)
392 int flags; /* Indicates what events should be processed.
393 * May be any combination of TCL_WINDOW_EVENTS
394 * TCL_FILE_EVENTS, TCL_TIMER_EVENTS, or other
395 * flags defined elsewhere. Events not
396 * matching this will be skipped for processing
397 * later. */
399 Tcl_Event *evPtr, *prevPtr;
400 Tcl_EventProc *proc;
402 if (!initialized) {
403 InitNotifier();
407 * Asynchronous event handlers are considered to be the highest
408 * priority events, and so must be invoked before we process events
409 * on the event queue.
412 if (Tcl_AsyncReady()) {
413 (void) Tcl_AsyncInvoke((Tcl_Interp *) NULL, 0);
414 return 1;
418 * No event flags is equivalent to TCL_ALL_EVENTS.
421 if ((flags & TCL_ALL_EVENTS) == 0) {
422 flags |= TCL_ALL_EVENTS;
426 * Loop through all the events in the queue until we find one
427 * that can actually be handled.
430 for (evPtr = notifier.firstEventPtr; evPtr != NULL;
431 evPtr = evPtr->nextPtr) {
433 * Call the handler for the event. If it actually handles the
434 * event then free the storage for the event. There are two
435 * tricky things here, but stemming from the fact that the event
436 * code may be re-entered while servicing the event:
438 * 1. Set the "proc" field to NULL. This is a signal to ourselves
439 * that we shouldn't reexecute the handler if the event loop
440 * is re-entered.
441 * 2. When freeing the event, must search the queue again from the
442 * front to find it. This is because the event queue could
443 * change almost arbitrarily while handling the event, so we
444 * can't depend on pointers found now still being valid when
445 * the handler returns.
448 proc = evPtr->proc;
449 evPtr->proc = NULL;
450 if ((proc != NULL) && (*proc)(evPtr, flags)) {
451 if (notifier.firstEventPtr == evPtr) {
452 notifier.firstEventPtr = evPtr->nextPtr;
453 if (evPtr->nextPtr == NULL) {
454 notifier.lastEventPtr = NULL;
456 if (notifier.markerEventPtr == evPtr) {
457 notifier.markerEventPtr = NULL;
459 } else {
460 for (prevPtr = notifier.firstEventPtr;
461 prevPtr->nextPtr != evPtr; prevPtr = prevPtr->nextPtr) {
462 /* Empty loop body. */
464 prevPtr->nextPtr = evPtr->nextPtr;
465 if (evPtr->nextPtr == NULL) {
466 notifier.lastEventPtr = prevPtr;
468 if (notifier.markerEventPtr == evPtr) {
469 notifier.markerEventPtr = prevPtr;
472 ckfree((char *) evPtr);
473 return 1;
474 } else {
476 * The event wasn't actually handled, so we have to restore
477 * the proc field to allow the event to be attempted again.
480 evPtr->proc = proc;
484 * The handler for this event asked to defer it. Just go on to
485 * the next event.
488 continue;
490 return 0;
494 *----------------------------------------------------------------------
496 * Tcl_GetServiceMode --
498 * This routine returns the current service mode of the notifier.
500 * Results:
501 * Returns either TCL_SERVICE_ALL or TCL_SERVICE_NONE.
503 * Side effects:
504 * None.
506 *----------------------------------------------------------------------
510 Tcl_GetServiceMode()
512 if (!initialized) {
513 InitNotifier();
516 return notifier.serviceMode;
520 *----------------------------------------------------------------------
522 * Tcl_SetServiceMode --
524 * This routine sets the current service mode of the notifier.
526 * Results:
527 * Returns the previous service mode.
529 * Side effects:
530 * None.
532 *----------------------------------------------------------------------
536 Tcl_SetServiceMode(mode)
537 int mode; /* New service mode: TCL_SERVICE_ALL or
538 * TCL_SERVICE_NONE */
540 int oldMode;
542 if (!initialized) {
543 InitNotifier();
546 oldMode = notifier.serviceMode;
547 notifier.serviceMode = mode;
548 return oldMode;
552 *----------------------------------------------------------------------
554 * Tcl_SetMaxBlockTime --
556 * This procedure is invoked by event sources to tell the notifier
557 * how long it may block the next time it blocks. The timePtr
558 * argument gives a maximum time; the actual time may be less if
559 * some other event source requested a smaller time.
561 * Results:
562 * None.
564 * Side effects:
565 * May reduce the length of the next sleep in the notifier.
567 *----------------------------------------------------------------------
570 void
571 Tcl_SetMaxBlockTime(timePtr)
572 Tcl_Time *timePtr; /* Specifies a maximum elapsed time for
573 * the next blocking operation in the
574 * event notifier. */
576 if (!initialized) {
577 InitNotifier();
580 if (!notifier.blockTimeSet || (timePtr->sec < notifier.blockTime.sec)
581 || ((timePtr->sec == notifier.blockTime.sec)
582 && (timePtr->usec < notifier.blockTime.usec))) {
583 notifier.blockTime = *timePtr;
584 notifier.blockTimeSet = 1;
588 * If we are called outside an event source traversal, set the
589 * timeout immediately.
592 if (!notifier.inTraversal) {
593 if (notifier.blockTimeSet) {
594 Tcl_SetTimer(&notifier.blockTime);
595 } else {
596 Tcl_SetTimer(NULL);
602 *----------------------------------------------------------------------
604 * Tcl_DoOneEvent --
606 * Process a single event of some sort. If there's no work to
607 * do, wait for an event to occur, then process it.
609 * Results:
610 * The return value is 1 if the procedure actually found an event
611 * to process. If no processing occurred, then 0 is returned (this
612 * can happen if the TCL_DONT_WAIT flag is set or if there are no
613 * event handlers to wait for in the set specified by flags).
615 * Side effects:
616 * May delay execution of process while waiting for an event,
617 * unless TCL_DONT_WAIT is set in the flags argument. Event
618 * sources are invoked to check for and queue events. Event
619 * handlers may produce arbitrary side effects.
621 *----------------------------------------------------------------------
625 Tcl_DoOneEvent(flags)
626 int flags; /* Miscellaneous flag values: may be any
627 * combination of TCL_DONT_WAIT,
628 * TCL_WINDOW_EVENTS, TCL_FILE_EVENTS,
629 * TCL_TIMER_EVENTS, TCL_IDLE_EVENTS, or
630 * others defined by event sources. */
632 int result = 0, oldMode;
633 EventSource *sourcePtr;
634 Tcl_Time *timePtr;
636 if (!initialized) {
637 InitNotifier();
641 * The first thing we do is to service any asynchronous event
642 * handlers.
645 if (Tcl_AsyncReady()) {
646 (void) Tcl_AsyncInvoke((Tcl_Interp *) NULL, 0);
647 return 1;
651 * No event flags is equivalent to TCL_ALL_EVENTS.
654 if ((flags & TCL_ALL_EVENTS) == 0) {
655 flags |= TCL_ALL_EVENTS;
659 * Set the service mode to none so notifier event routines won't
660 * try to service events recursively.
663 oldMode = notifier.serviceMode;
664 notifier.serviceMode = TCL_SERVICE_NONE;
667 * The core of this procedure is an infinite loop, even though
668 * we only service one event. The reason for this is that we
669 * may be processing events that don't do anything inside of Tcl.
672 while (1) {
675 * If idle events are the only things to service, skip the
676 * main part of the loop and go directly to handle idle
677 * events (i.e. don't wait even if TCL_DONT_WAIT isn't set).
680 if ((flags & TCL_ALL_EVENTS) == TCL_IDLE_EVENTS) {
681 flags = TCL_IDLE_EVENTS|TCL_DONT_WAIT;
682 goto idleEvents;
686 * Ask Tcl to service a queued event, if there are any.
689 if (Tcl_ServiceEvent(flags)) {
690 result = 1;
691 break;
695 * If TCL_DONT_WAIT is set, be sure to poll rather than
696 * blocking, otherwise reset the block time to infinity.
699 if (flags & TCL_DONT_WAIT) {
700 notifier.blockTime.sec = 0;
701 notifier.blockTime.usec = 0;
702 notifier.blockTimeSet = 1;
703 } else {
704 notifier.blockTimeSet = 0;
708 * Set up all the event sources for new events. This will
709 * cause the block time to be updated if necessary.
712 notifier.inTraversal = 1;
713 for (sourcePtr = notifier.firstEventSourcePtr; sourcePtr != NULL;
714 sourcePtr = sourcePtr->nextPtr) {
715 if (sourcePtr->setupProc) {
716 (sourcePtr->setupProc)(sourcePtr->clientData, flags);
719 notifier.inTraversal = 0;
721 if ((flags & TCL_DONT_WAIT) || notifier.blockTimeSet) {
722 timePtr = &notifier.blockTime;
723 } else {
724 timePtr = NULL;
728 * Wait for a new event or a timeout. If Tcl_WaitForEvent
729 * returns -1, we should abort Tcl_DoOneEvent.
732 result = Tcl_WaitForEvent(timePtr);
733 if (result < 0) {
734 result = 0;
735 break;
739 * Check all the event sources for new events.
742 for (sourcePtr = notifier.firstEventSourcePtr; sourcePtr != NULL;
743 sourcePtr = sourcePtr->nextPtr) {
744 if (sourcePtr->checkProc) {
745 (sourcePtr->checkProc)(sourcePtr->clientData, flags);
750 * Check for events queued by the notifier or event sources.
753 if (Tcl_ServiceEvent(flags)) {
754 result = 1;
755 break;
759 * We've tried everything at this point, but nobody we know
760 * about had anything to do. Check for idle events. If none,
761 * either quit or go back to the top and try again.
764 idleEvents:
765 if (flags & TCL_IDLE_EVENTS) {
766 if (TclServiceIdle()) {
767 result = 1;
768 break;
771 if (flags & TCL_DONT_WAIT) {
772 break;
776 notifier.serviceMode = oldMode;
777 return result;
781 *----------------------------------------------------------------------
783 * Tcl_ServiceAll --
785 * This routine checks all of the event sources, processes
786 * events that are on the Tcl event queue, and then calls the
787 * any idle handlers. Platform specific notifier callbacks that
788 * generate events should call this routine before returning to
789 * the system in order to ensure that Tcl gets a chance to
790 * process the new events.
792 * Results:
793 * Returns 1 if an event or idle handler was invoked, else 0.
795 * Side effects:
796 * Anything that an event or idle handler may do.
798 *----------------------------------------------------------------------
802 Tcl_ServiceAll()
804 int result = 0;
805 EventSource *sourcePtr;
807 if (!initialized) {
808 InitNotifier();
811 if (notifier.serviceMode == TCL_SERVICE_NONE) {
812 return result;
816 * We need to turn off event servicing like we to in Tcl_DoOneEvent,
817 * to avoid recursive calls.
820 notifier.serviceMode = TCL_SERVICE_NONE;
823 * Check async handlers first.
826 if (Tcl_AsyncReady()) {
827 (void) Tcl_AsyncInvoke((Tcl_Interp *) NULL, 0);
831 * Make a single pass through all event sources, queued events,
832 * and idle handlers. Note that we wait to update the notifier
833 * timer until the end so we can avoid multiple changes.
836 notifier.inTraversal = 1;
837 notifier.blockTimeSet = 0;
839 for (sourcePtr = notifier.firstEventSourcePtr; sourcePtr != NULL;
840 sourcePtr = sourcePtr->nextPtr) {
841 if (sourcePtr->setupProc) {
842 (sourcePtr->setupProc)(sourcePtr->clientData, TCL_ALL_EVENTS);
845 for (sourcePtr = notifier.firstEventSourcePtr; sourcePtr != NULL;
846 sourcePtr = sourcePtr->nextPtr) {
847 if (sourcePtr->checkProc) {
848 (sourcePtr->checkProc)(sourcePtr->clientData, TCL_ALL_EVENTS);
852 while (Tcl_ServiceEvent(0)) {
853 result = 1;
855 if (TclServiceIdle()) {
856 result = 1;
859 if (!notifier.blockTimeSet) {
860 Tcl_SetTimer(NULL);
861 } else {
862 Tcl_SetTimer(&notifier.blockTime);
864 notifier.inTraversal = 0;
865 notifier.serviceMode = TCL_SERVICE_ALL;
866 return result;
870 *----------------------------------------------------------------------
872 * PyTcl_WaitUntilEvent --
874 * New function to wait until a Tcl event is ready without
875 * actually handling the event. This is different than
876 * TclWaitForEvent(): that function doesn't call the event
877 * check routines, which is necessary for our purpose.
878 * We also can't use Tcl_DoOneEvent(TCL_DONT_WAIT), since that
879 * does too much: it handles the event. We want the *handling*
880 * of the event to be done with the Python lock held, but the
881 * *waiting* with the lock released.
883 * Since the event administration is not exported, our only
884 * choice is to use a modified copy of the file tclNotify.c,
885 * containing this additional function that makes the desired
886 * functionality available. It is mostly a stripped down version
887 * of the code in Tcl_DoOneEvent().
889 * This requires that you link with a static version of the Tcl
890 * library. On Windows/Mac, a custom compilation of Tcl may be
891 * required (I haven't tried this yet).
893 *----------------------------------------------------------------------
897 PyTcl_WaitUntilEvent()
899 int flags = TCL_ALL_EVENTS;
900 int result = 0, oldMode;
901 EventSource *sourcePtr;
902 Tcl_Time *timePtr;
904 if (!initialized) {
905 InitNotifier();
909 * The first thing we do is to service any asynchronous event
910 * handlers.
913 if (Tcl_AsyncReady())
914 return 1;
917 * Set the service mode to none so notifier event routines won't
918 * try to service events recursively.
921 oldMode = notifier.serviceMode;
922 notifier.serviceMode = TCL_SERVICE_NONE;
924 notifier.blockTimeSet = 0;
927 * Set up all the event sources for new events. This will
928 * cause the block time to be updated if necessary.
931 notifier.inTraversal = 1;
932 for (sourcePtr = notifier.firstEventSourcePtr; sourcePtr != NULL;
933 sourcePtr = sourcePtr->nextPtr) {
934 if (sourcePtr->setupProc) {
935 (sourcePtr->setupProc)(sourcePtr->clientData, flags);
938 notifier.inTraversal = 0;
940 timePtr = NULL;
943 * Wait for a new event or a timeout. If Tcl_WaitForEvent
944 * returns -1, we should abort Tcl_DoOneEvent.
947 result = Tcl_WaitForEvent(timePtr);
948 if (result < 0)
949 return 0;
952 * Check all the event sources for new events.
955 for (sourcePtr = notifier.firstEventSourcePtr; sourcePtr != NULL;
956 sourcePtr = sourcePtr->nextPtr) {
957 if (sourcePtr->checkProc) {
958 (sourcePtr->checkProc)(sourcePtr->clientData, flags);
962 notifier.serviceMode = oldMode;
963 return result;