summaryrefslogtreecommitdiff
path: root/contrib/tcl/generic/tclNotify.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/tcl/generic/tclNotify.c')
-rw-r--r--contrib/tcl/generic/tclNotify.c561
1 files changed, 420 insertions, 141 deletions
diff --git a/contrib/tcl/generic/tclNotify.c b/contrib/tcl/generic/tclNotify.c
index 0745591835fa..19f38f3282ed 100644
--- a/contrib/tcl/generic/tclNotify.c
+++ b/contrib/tcl/generic/tclNotify.c
@@ -1,71 +1,125 @@
/*
* tclNotify.c --
*
- * This file provides the parts of the Tcl event notifier that are
- * the same on all platforms, plus a few other parts that are used
- * on more than one platform but not all.
+ * This file implements the generic portion of the Tcl notifier.
+ * The notifier is lowest-level part of the event system. It
+ * manages an event queue that holds Tcl_Event structures. The
+ * platform specific portion of the notifier is defined in the
+ * tcl*Notify.c files in each platform directory.
*
- * The notifier is the lowest-level part of the event system. It
- * manages an event queue that holds Tcl_Event structures and a list
- * of event sources that can add events to the queue. It also
- * contains the procedure Tcl_DoOneEvent that invokes the event
- * sources and blocks to wait for new events, but Tcl_DoOneEvent
- * is in the platform-specific part of the notifier (in files like
- * tclUnixNotify.c).
- *
- * Copyright (c) 1995 Sun Microsystems, Inc.
+ * Copyright (c) 1995-1997 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * SCCS: @(#) tclNotify.c 1.6 96/02/29 09:20:10
+ * SCCS: @(#) tclNotify.c 1.15 97/06/18 17:14:04
*/
#include "tclInt.h"
#include "tclPort.h"
/*
- * The following variable records the address of the first event
- * source in the list of all event sources for the application.
- * This variable is accessed by the notifier to traverse the list
- * and invoke each event source.
+ * The following static indicates whether this module has been initialized.
+ */
+
+static int initialized = 0;
+
+/*
+ * For each event source (created with Tcl_CreateEventSource) there
+ * is a structure of the following type:
*/
-TclEventSource *tclFirstEventSourcePtr = NULL;
+typedef struct EventSource {
+ Tcl_EventSetupProc *setupProc;
+ Tcl_EventCheckProc *checkProc;
+ ClientData clientData;
+ struct EventSource *nextPtr;
+} EventSource;
/*
- * The following variables indicate how long to block in the event
- * notifier the next time it blocks (default: block forever).
+ * The following structure keeps track of the state of the notifier.
+ * The first three elements keep track of the event queue. In addition to
+ * the first (next to be serviced) and last events in the queue, we keep
+ * track of a "marker" event. This provides a simple priority mechanism
+ * whereby events can be inserted at the front of the queue but behind all
+ * other high-priority events already in the queue (this is used for things
+ * like a sequence of Enter and Leave events generated during a grab in
+ * Tk).
*/
-static int blockTimeSet = 0; /* 0 means there is no maximum block
+static struct {
+ Tcl_Event *firstEventPtr; /* First pending event, or NULL if none. */
+ Tcl_Event *lastEventPtr; /* Last pending event, or NULL if none. */
+ Tcl_Event *markerEventPtr; /* Last high-priority event in queue, or
+ * NULL if none. */
+ int serviceMode; /* One of TCL_SERVICE_NONE or
+ * TCL_SERVICE_ALL. */
+ int blockTimeSet; /* 0 means there is no maximum block
* time: block forever. */
-static Tcl_Time blockTime; /* If blockTimeSet is 1, gives the
+ Tcl_Time blockTime; /* If blockTimeSet is 1, gives the
* maximum elapsed time for the next block. */
+ int inTraversal; /* 1 if Tcl_SetMaxBlockTime is being
+ * called during an event source traversal. */
+ EventSource *firstEventSourcePtr;
+ /* Pointer to first event source in
+ * global list of event sources. */
+} notifier;
/*
- * The following variables keep track of the event queue. In addition
- * to the first (next to be serviced) and last events in the queue,
- * we keep track of a "marker" event. This provides a simple priority
- * mechanism whereby events can be inserted at the front of the queue
- * but behind all other high-priority events already in the queue (this
- * is used for things like a sequence of Enter and Leave events generated
- * during a grab in Tk).
+ * Declarations for functions used in this file.
*/
-static Tcl_Event *firstEventPtr = NULL;
- /* First pending event, or NULL if none. */
-static Tcl_Event *lastEventPtr = NULL;
- /* Last pending event, or NULL if none. */
-static Tcl_Event *markerEventPtr = NULL;
- /* Last high-priority event in queue, or
- * NULL if none. */
+static void InitNotifier _ANSI_ARGS_((void));
+static void NotifierExitHandler _ANSI_ARGS_((ClientData clientData));
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * InitNotifier --
+ *
+ * This routine is called to initialize the notifier module.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Creates an exit handler and initializes static data.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+InitNotifier()
+{
+ initialized = 1;
+ memset(&notifier, 0, sizeof(notifier));
+ notifier.serviceMode = TCL_SERVICE_NONE;
+ Tcl_CreateExitHandler(NotifierExitHandler, NULL);
+}
+
/*
- * Prototypes for procedures used only in this file:
+ *----------------------------------------------------------------------
+ *
+ * NotifierExitHandler --
+ *
+ * This routine is called during Tcl finalization.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Clears the notifier intialization flag.
+ *
+ *----------------------------------------------------------------------
*/
-static int ServiceEvent _ANSI_ARGS_((int flags));
+static void
+NotifierExitHandler(clientData)
+ ClientData clientData; /* Not used. */
+{
+ initialized = 0;
+}
/*
*----------------------------------------------------------------------
@@ -112,14 +166,18 @@ Tcl_CreateEventSource(setupProc, checkProc, clientData)
ClientData clientData; /* One-word argument to pass to
* setupProc and checkProc. */
{
- TclEventSource *sourcePtr;
+ EventSource *sourcePtr;
+
+ if (!initialized) {
+ InitNotifier();
+ }
- sourcePtr = (TclEventSource *) ckalloc(sizeof(TclEventSource));
+ sourcePtr = (EventSource *) ckalloc(sizeof(EventSource));
sourcePtr->setupProc = setupProc;
sourcePtr->checkProc = checkProc;
sourcePtr->clientData = clientData;
- sourcePtr->nextPtr = tclFirstEventSourcePtr;
- tclFirstEventSourcePtr = sourcePtr;
+ sourcePtr->nextPtr = notifier.firstEventSourcePtr;
+ notifier.firstEventSourcePtr = sourcePtr;
}
/*
@@ -150,9 +208,9 @@ Tcl_DeleteEventSource(setupProc, checkProc, clientData)
ClientData clientData; /* One-word argument to pass to
* setupProc and checkProc. */
{
- TclEventSource *sourcePtr, *prevPtr;
+ EventSource *sourcePtr, *prevPtr;
- for (sourcePtr = tclFirstEventSourcePtr, prevPtr = NULL;
+ for (sourcePtr = notifier.firstEventSourcePtr, prevPtr = NULL;
sourcePtr != NULL;
prevPtr = sourcePtr, sourcePtr = sourcePtr->nextPtr) {
if ((sourcePtr->setupProc != setupProc)
@@ -161,7 +219,7 @@ Tcl_DeleteEventSource(setupProc, checkProc, clientData)
continue;
}
if (prevPtr == NULL) {
- tclFirstEventSourcePtr = sourcePtr->nextPtr;
+ notifier.firstEventSourcePtr = sourcePtr->nextPtr;
} else {
prevPtr->nextPtr = sourcePtr->nextPtr;
}
@@ -202,44 +260,48 @@ Tcl_QueueEvent(evPtr, position)
Tcl_QueuePosition position; /* One of TCL_QUEUE_TAIL, TCL_QUEUE_HEAD,
* TCL_QUEUE_MARK. */
{
+ if (!initialized) {
+ InitNotifier();
+ }
+
if (position == TCL_QUEUE_TAIL) {
/*
* Append the event on the end of the queue.
*/
evPtr->nextPtr = NULL;
- if (firstEventPtr == NULL) {
- firstEventPtr = evPtr;
+ if (notifier.firstEventPtr == NULL) {
+ notifier.firstEventPtr = evPtr;
} else {
- lastEventPtr->nextPtr = evPtr;
+ notifier.lastEventPtr->nextPtr = evPtr;
}
- lastEventPtr = evPtr;
+ notifier.lastEventPtr = evPtr;
} else if (position == TCL_QUEUE_HEAD) {
/*
* Push the event on the head of the queue.
*/
- evPtr->nextPtr = firstEventPtr;
- if (firstEventPtr == NULL) {
- lastEventPtr = evPtr;
+ evPtr->nextPtr = notifier.firstEventPtr;
+ if (notifier.firstEventPtr == NULL) {
+ notifier.lastEventPtr = evPtr;
}
- firstEventPtr = evPtr;
+ notifier.firstEventPtr = evPtr;
} else if (position == TCL_QUEUE_MARK) {
/*
* Insert the event after the current marker event and advance
* the marker to the new event.
*/
- if (markerEventPtr == NULL) {
- evPtr->nextPtr = firstEventPtr;
- firstEventPtr = evPtr;
+ if (notifier.markerEventPtr == NULL) {
+ evPtr->nextPtr = notifier.firstEventPtr;
+ notifier.firstEventPtr = evPtr;
} else {
- evPtr->nextPtr = markerEventPtr->nextPtr;
- markerEventPtr->nextPtr = evPtr;
+ evPtr->nextPtr = notifier.markerEventPtr->nextPtr;
+ notifier.markerEventPtr->nextPtr = evPtr;
}
- markerEventPtr = evPtr;
+ notifier.markerEventPtr = evPtr;
if (evPtr->nextPtr == NULL) {
- lastEventPtr = evPtr;
+ notifier.lastEventPtr = evPtr;
}
}
}
@@ -269,14 +331,18 @@ Tcl_DeleteEvents(proc, clientData)
{
Tcl_Event *evPtr, *prevPtr, *hold;
- for (prevPtr = (Tcl_Event *) NULL, evPtr = firstEventPtr;
+ if (!initialized) {
+ InitNotifier();
+ }
+
+ for (prevPtr = (Tcl_Event *) NULL, evPtr = notifier.firstEventPtr;
evPtr != (Tcl_Event *) NULL;
) {
if ((*proc) (evPtr, clientData) == 1) {
- if (firstEventPtr == evPtr) {
- firstEventPtr = evPtr->nextPtr;
+ if (notifier.firstEventPtr == evPtr) {
+ notifier.firstEventPtr = evPtr->nextPtr;
if (evPtr->nextPtr == (Tcl_Event *) NULL) {
- lastEventPtr = (Tcl_Event *) NULL;
+ notifier.lastEventPtr = (Tcl_Event *) NULL;
}
} else {
prevPtr->nextPtr = evPtr->nextPtr;
@@ -294,10 +360,10 @@ Tcl_DeleteEvents(proc, clientData)
/*
*----------------------------------------------------------------------
*
- * ServiceEvent --
+ * Tcl_ServiceEvent --
*
- * Process one event from the event queue. This routine is called
- * by the notifier whenever it wants Tk to process an event.
+ * Process one event from the event queue, or invoke an
+ * asynchronous event handler.
*
* Results:
* The return value is 1 if the procedure actually found an event
@@ -311,8 +377,8 @@ Tcl_DeleteEvents(proc, clientData)
*----------------------------------------------------------------------
*/
-static int
-ServiceEvent(flags)
+int
+Tcl_ServiceEvent(flags)
int flags; /* Indicates what events should be processed.
* May be any combination of TCL_WINDOW_EVENTS
* TCL_FILE_EVENTS, TCL_TIMER_EVENTS, or other
@@ -323,6 +389,21 @@ ServiceEvent(flags)
Tcl_Event *evPtr, *prevPtr;
Tcl_EventProc *proc;
+ if (!initialized) {
+ InitNotifier();
+ }
+
+ /*
+ * Asynchronous event handlers are considered to be the highest
+ * priority events, and so must be invoked before we process events
+ * on the event queue.
+ */
+
+ if (Tcl_AsyncReady()) {
+ (void) Tcl_AsyncInvoke((Tcl_Interp *) NULL, 0);
+ return 1;
+ }
+
/*
* No event flags is equivalent to TCL_ALL_EVENTS.
*/
@@ -336,7 +417,8 @@ ServiceEvent(flags)
* that can actually be handled.
*/
- for (evPtr = firstEventPtr; evPtr != NULL; evPtr = evPtr->nextPtr) {
+ for (evPtr = notifier.firstEventPtr; evPtr != NULL;
+ evPtr = evPtr->nextPtr) {
/*
* Call the handler for the event. If it actually handles the
* event then free the storage for the event. There are two
@@ -356,23 +438,26 @@ ServiceEvent(flags)
proc = evPtr->proc;
evPtr->proc = NULL;
if ((proc != NULL) && (*proc)(evPtr, flags)) {
- if (firstEventPtr == evPtr) {
- firstEventPtr = evPtr->nextPtr;
+ if (notifier.firstEventPtr == evPtr) {
+ notifier.firstEventPtr = evPtr->nextPtr;
if (evPtr->nextPtr == NULL) {
- lastEventPtr = NULL;
+ notifier.lastEventPtr = NULL;
+ }
+ if (notifier.markerEventPtr == evPtr) {
+ notifier.markerEventPtr = NULL;
}
} else {
- for (prevPtr = firstEventPtr; prevPtr->nextPtr != evPtr;
- prevPtr = prevPtr->nextPtr) {
+ for (prevPtr = notifier.firstEventPtr;
+ prevPtr->nextPtr != evPtr; prevPtr = prevPtr->nextPtr) {
/* Empty loop body. */
}
prevPtr->nextPtr = evPtr->nextPtr;
if (evPtr->nextPtr == NULL) {
- lastEventPtr = prevPtr;
+ notifier.lastEventPtr = prevPtr;
+ }
+ if (notifier.markerEventPtr == evPtr) {
+ notifier.markerEventPtr = prevPtr;
}
- }
- if (markerEventPtr == evPtr) {
- markerEventPtr = NULL;
}
ckfree((char *) evPtr);
return 1;
@@ -398,6 +483,64 @@ ServiceEvent(flags)
/*
*----------------------------------------------------------------------
*
+ * Tcl_GetServiceMode --
+ *
+ * This routine returns the current service mode of the notifier.
+ *
+ * Results:
+ * Returns either TCL_SERVICE_ALL or TCL_SERVICE_NONE.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_GetServiceMode()
+{
+ if (!initialized) {
+ InitNotifier();
+ }
+
+ return notifier.serviceMode;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_SetServiceMode --
+ *
+ * This routine sets the current service mode of the notifier.
+ *
+ * Results:
+ * Returns the previous service mode.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_SetServiceMode(mode)
+ int mode; /* New service mode: TCL_SERVICE_ALL or
+ * TCL_SERVICE_NONE */
+{
+ int oldMode;
+
+ if (!initialized) {
+ InitNotifier();
+ }
+
+ oldMode = notifier.serviceMode;
+ notifier.serviceMode = mode;
+ return oldMode;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* Tcl_SetMaxBlockTime --
*
* This procedure is invoked by event sources to tell the notifier
@@ -420,11 +563,28 @@ Tcl_SetMaxBlockTime(timePtr)
* the next blocking operation in the
* event notifier. */
{
- if (!blockTimeSet || (timePtr->sec < blockTime.sec)
- || ((timePtr->sec == blockTime.sec)
- && (timePtr->usec < blockTime.usec))) {
- blockTime = *timePtr;
- blockTimeSet = 1;
+ if (!initialized) {
+ InitNotifier();
+ }
+
+ if (!notifier.blockTimeSet || (timePtr->sec < notifier.blockTime.sec)
+ || ((timePtr->sec == notifier.blockTime.sec)
+ && (timePtr->usec < notifier.blockTime.usec))) {
+ notifier.blockTime = *timePtr;
+ notifier.blockTimeSet = 1;
+ }
+
+ /*
+ * If we are called outside an event source traversal, set the
+ * timeout immediately.
+ */
+
+ if (!notifier.inTraversal) {
+ if (notifier.blockTimeSet) {
+ Tcl_SetTimer(&notifier.blockTime);
+ } else {
+ Tcl_SetTimer(NULL);
+ }
}
}
@@ -459,9 +619,24 @@ Tcl_DoOneEvent(flags)
* TCL_TIMER_EVENTS, TCL_IDLE_EVENTS, or
* others defined by event sources. */
{
- TclEventSource *sourcePtr;
+ int result = 0, oldMode;
+ EventSource *sourcePtr;
Tcl_Time *timePtr;
+ if (!initialized) {
+ InitNotifier();
+ }
+
+ /*
+ * The first thing we do is to service any asynchronous event
+ * handlers.
+ */
+
+ if (Tcl_AsyncReady()) {
+ (void) Tcl_AsyncInvoke((Tcl_Interp *) NULL, 0);
+ return 1;
+ }
+
/*
* No event flags is equivalent to TCL_ALL_EVENTS.
*/
@@ -471,108 +646,212 @@ Tcl_DoOneEvent(flags)
}
/*
+ * Set the service mode to none so notifier event routines won't
+ * try to service events recursively.
+ */
+
+ oldMode = notifier.serviceMode;
+ notifier.serviceMode = TCL_SERVICE_NONE;
+
+ /*
* The core of this procedure is an infinite loop, even though
* we only service one event. The reason for this is that we
- * might think we have an event ready (e.g. the connection to
- * the server becomes readable), but then we might discover that
- * there's nothing interesting on that connection, so no event
- * was serviced. Or, the select operation could return prematurely
- * due to a signal. The easiest thing in both these cases is
- * just to loop back and try again.
+ * may be processing events that don't do anything inside of Tcl.
*/
while (1) {
/*
- * The first thing we do is to service any asynchronous event
- * handlers.
- */
-
- if (Tcl_AsyncReady()) {
- (void) Tcl_AsyncInvoke((Tcl_Interp *) NULL, 0);
- return 1;
- }
-
- /*
* If idle events are the only things to service, skip the
* main part of the loop and go directly to handle idle
- * events (i.e. don't wait even if TCL_DONT_WAIT isn't set.
+ * events (i.e. don't wait even if TCL_DONT_WAIT isn't set).
*/
- if (flags == TCL_IDLE_EVENTS) {
+ if ((flags & TCL_ALL_EVENTS) == TCL_IDLE_EVENTS) {
flags = TCL_IDLE_EVENTS|TCL_DONT_WAIT;
goto idleEvents;
}
/*
- * Ask Tk to service a queued event, if there are any.
+ * Ask Tcl to service a queued event, if there are any.
*/
- if (ServiceEvent(flags)) {
- return 1;
+ if (Tcl_ServiceEvent(flags)) {
+ result = 1;
+ break;
}
/*
- * There are no events already queued. Invoke all of the
- * event sources to give them a chance to setup for the wait.
+ * If TCL_DONT_WAIT is set, be sure to poll rather than
+ * blocking, otherwise reset the block time to infinity.
*/
- blockTimeSet = 0;
- for (sourcePtr = tclFirstEventSourcePtr; sourcePtr != NULL;
- sourcePtr = sourcePtr->nextPtr) {
- (*sourcePtr->setupProc)(sourcePtr->clientData, flags);
+ if (flags & TCL_DONT_WAIT) {
+ notifier.blockTime.sec = 0;
+ notifier.blockTime.usec = 0;
+ notifier.blockTimeSet = 1;
+ } else {
+ notifier.blockTimeSet = 0;
}
- if ((flags & TCL_DONT_WAIT) ||
- ((flags & TCL_IDLE_EVENTS) && TclIdlePending())) {
- /*
- * Don't block: there are idle events waiting, or we don't
- * care about idle events anyway, or the caller asked us not
- * to block.
- */
- blockTime.sec = 0;
- blockTime.usec = 0;
- timePtr = &blockTime;
- } else if (blockTimeSet) {
- timePtr = &blockTime;
+ /*
+ * Set up all the event sources for new events. This will
+ * cause the block time to be updated if necessary.
+ */
+
+ notifier.inTraversal = 1;
+ for (sourcePtr = notifier.firstEventSourcePtr; sourcePtr != NULL;
+ sourcePtr = sourcePtr->nextPtr) {
+ if (sourcePtr->setupProc) {
+ (sourcePtr->setupProc)(sourcePtr->clientData, flags);
+ }
+ }
+ notifier.inTraversal = 0;
+
+ if ((flags & TCL_DONT_WAIT) || notifier.blockTimeSet) {
+ timePtr = &notifier.blockTime;
} else {
timePtr = NULL;
}
/*
- * Wait until an event occurs or the timer expires.
+ * Wait for a new event or a timeout. If Tcl_WaitForEvent
+ * returns -1, we should abort Tcl_DoOneEvent.
*/
- if (Tcl_WaitForEvent(timePtr) == TCL_ERROR) {
- return 0;
+ result = Tcl_WaitForEvent(timePtr);
+ if (result < 0) {
+ result = 0;
+ break;
}
/*
- * Give each of the event sources a chance to queue events,
- * then call ServiceEvent and give it another chance to
- * service events.
+ * Check all the event sources for new events.
*/
- for (sourcePtr = tclFirstEventSourcePtr; sourcePtr != NULL;
- sourcePtr = sourcePtr->nextPtr) {
- (*sourcePtr->checkProc)(sourcePtr->clientData, flags);
+ for (sourcePtr = notifier.firstEventSourcePtr; sourcePtr != NULL;
+ sourcePtr = sourcePtr->nextPtr) {
+ if (sourcePtr->checkProc) {
+ (sourcePtr->checkProc)(sourcePtr->clientData, flags);
+ }
}
- if (ServiceEvent(flags)) {
- return 1;
+
+ /*
+ * Check for events queued by the notifier or event sources.
+ */
+
+ if (Tcl_ServiceEvent(flags)) {
+ result = 1;
+ break;
}
/*
- * We've tried everything at this point, but nobody had anything
- * to do. Check for idle events. If none, either quit or go back
- * to the top and try again.
+ * We've tried everything at this point, but nobody we know
+ * about had anything to do. Check for idle events. If none,
+ * either quit or go back to the top and try again.
*/
idleEvents:
- if ((flags & TCL_IDLE_EVENTS) && TclServiceIdle()) {
- return 1;
+ if (flags & TCL_IDLE_EVENTS) {
+ if (TclServiceIdle()) {
+ result = 1;
+ break;
+ }
}
if (flags & TCL_DONT_WAIT) {
- return 0;
+ break;
}
}
+
+ notifier.serviceMode = oldMode;
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_ServiceAll --
+ *
+ * This routine checks all of the event sources, processes
+ * events that are on the Tcl event queue, and then calls the
+ * any idle handlers. Platform specific notifier callbacks that
+ * generate events should call this routine before returning to
+ * the system in order to ensure that Tcl gets a chance to
+ * process the new events.
+ *
+ * Results:
+ * Returns 1 if an event or idle handler was invoked, else 0.
+ *
+ * Side effects:
+ * Anything that an event or idle handler may do.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_ServiceAll()
+{
+ int result = 0;
+ EventSource *sourcePtr;
+
+ if (!initialized) {
+ InitNotifier();
+ }
+
+ if (notifier.serviceMode == TCL_SERVICE_NONE) {
+ return result;
+ }
+
+ /*
+ * We need to turn off event servicing like we to in Tcl_DoOneEvent,
+ * to avoid recursive calls.
+ */
+
+ notifier.serviceMode = TCL_SERVICE_NONE;
+
+ /*
+ * Check async handlers first.
+ */
+
+ if (Tcl_AsyncReady()) {
+ (void) Tcl_AsyncInvoke((Tcl_Interp *) NULL, 0);
+ }
+
+ /*
+ * Make a single pass through all event sources, queued events,
+ * and idle handlers. Note that we wait to update the notifier
+ * timer until the end so we can avoid multiple changes.
+ */
+
+ notifier.inTraversal = 1;
+ notifier.blockTimeSet = 0;
+
+ for (sourcePtr = notifier.firstEventSourcePtr; sourcePtr != NULL;
+ sourcePtr = sourcePtr->nextPtr) {
+ if (sourcePtr->setupProc) {
+ (sourcePtr->setupProc)(sourcePtr->clientData, TCL_ALL_EVENTS);
+ }
+ }
+ for (sourcePtr = notifier.firstEventSourcePtr; sourcePtr != NULL;
+ sourcePtr = sourcePtr->nextPtr) {
+ if (sourcePtr->checkProc) {
+ (sourcePtr->checkProc)(sourcePtr->clientData, TCL_ALL_EVENTS);
+ }
+ }
+
+ while (Tcl_ServiceEvent(0)) {
+ result = 1;
+ }
+ if (TclServiceIdle()) {
+ result = 1;
+ }
+
+ if (!notifier.blockTimeSet) {
+ Tcl_SetTimer(NULL);
+ } else {
+ Tcl_SetTimer(&notifier.blockTime);
+ }
+ notifier.inTraversal = 0;
+ notifier.serviceMode = TCL_SERVICE_ALL;
+ return result;
}