MAN page from Old RedHat 6.X tcl-8.0.5-35.i386.rpm
Notifier
Section: Tcl Library Procedures (3)
Updated: 8.0
Index
NAME
Tcl_CreateEventSource, Tcl_DeleteEventSource, Tcl_SetMaxBlockTime, Tcl_QueueEvent, Tcl_DeleteEvents, Tcl_WaitForEvent, Tcl_SetTimer, Tcl_ServiceAll, Tcl_ServiceEvent, Tcl_GetServiceMode, Tcl_SetServiceMode - the event queue and notifier interfaces
SYNOPSIS
#include <tcl.h>Tcl_CreateEventSource(setupProc, checkProc, clientData)Tcl_DeleteEventSource(setupProc, checkProc, clientData)Tcl_SetMaxBlockTime(timePtr)Tcl_QueueEvent(evPtr, position)Tcl_DeleteEvents(deleteProc, clientData)intTcl_WaitForEvent(timePtr)Tcl_SetTimer(timePtr)intTcl_ServiceAll()intTcl_ServiceEvent(flags)intTcl_GetServiceMode()int Tcl_SetServiceMode(mode)
ARGUMENTS
- Tcl_EventSetupProc *setupProc (in)
Procedure to invoke to prepare for event wait in Tcl_DoOneEvent. - Tcl_EventCheckProc *checkProc (in)
Procedure for Tcl_DoOneEvent to invoke after waiting forevents. Checks to see if any events have occurred and, if so,queues them. - ClientData clientData (in)
Arbitrary one-word value to pass to setupProc, checkProc, ordeleteProc. - Tcl_Time *timePtr (in)
Indicates the maximum amount of time to wait for an event. Thisis specified as an interval (how long to wait), not an absolutetime (when to wakeup). If the pointer passed to Tcl_WaitForEventis NULL, it means there is no maximum wait time: wait forever ifnecessary. - Tcl_Event *evPtr (in)
An event to add to the event queue. The storage for the event musthave been allocated by the caller using Tcl_Alloc or ckalloc. - Tcl_QueuePosition position (in)
Where to add the new event in the queue: TCL_QUEUE_TAIL,TCL_QUEUE_HEAD, or TCL_QUEUE_MARK. - int flags (in)
What types of events to service. These flags are the same as thosepassed to Tcl_DoOneEvent. - Tcl_EventDeleteProc *deleteProc (in)
Procedure to invoke for each queued event in Tcl_DeleteEvents. - int mode (in)
Inidicates whether events should be serviced by Tcl_ServiceAll.Must be one of TCL_SERVICE_NONE or TCL_SERVICE_ALL.
INTRODUCTION
The interfaces described here are used to customize the Tcl eventloop. The two most common customizations are to add new sources ofevents and to merge Tcl's event loop with some other event loop, suchas one provided by an application in which Tcl is embedded. Each ofthese tasks is described in a separate section below.
The procedures in this manual entry are the building blocks out of whichthe Tcl event notifier is constructed. The event notifier is the lowestlayer in the Tcl event mechanism. It consists of three things:
- [1]
- Event sources: these represent the ways in which events can begenerated. For example, there is a timer event source that implementsthe Tcl_CreateTimerHandler procedure and the aftercommand, and there is a file event source that implements theTcl_CreateFileHandler procedure on Unix systems. An eventsource must work with the notifier to detect events at the righttimes, record them on the event queue, and eventually notifyhigher-level software that they have occurred. The proceduresTcl_CreateEventSource, Tcl_DeleteEventSource,and Tcl_SetMaxBlockTime, Tcl_QueueEvent, andTcl_DeleteEvents are used primarily by event sources.
- [2]
- The event queue: there is a single queue for the whole application,containing events that have been detected but not yet serviced. Eventsources place events onto the queue so that they may be processed inorder at appropriate times during the event loop. The event queueguarantees a fair discipline of event handling, so that no eventsource can starve the others. It also allows events to be saved forservicing at a future time.Tcl_QueueEvent is used (primarilyby event sources) to add events to the event queue and Tcl_DeleteEvents is used to remove events from the queue withoutprocessing them.
- [3]
- The event loop: in order to detect and process events, the applicationenters a loop that waits for events to occur, places them on the eventqueue, and then processes them. Most applications will do this bycalling the procedure Tcl_DoOneEvent, which is described in aseparate manual entry.
Most Tcl applications need not worry about any of the internals ofthe Tcl notifier. However, the notifier now has enough flexibilityto be retargeted either for a new platform or to use an external eventloop (such as the Motif event loop, when Tcl is embedded in a Motifapplication). The procedures Tcl_WaitForEvent andTcl_SetTimer are normally implemented by Tcl, but may bereplaced with new versions to retarget the notifier (the Tcl_Sleep,Tcl_CreateFileHandler, and Tcl_DeleteFileHandler mustalso be replaced; see CREATING A NEW NOTIFIER below for details).The procedures Tcl_ServiceAll, Tcl_ServiceEvent,Tcl_GetServiceMode, and Tcl_SetServiceMode are providedto help connect Tcl's event loop to an external event loop such asMotif's.
NOTIFIER BASICS
The easiest way to understand how the notifier works is to considerwhat happens when Tcl_DoOneEvent is called.Tcl_DoOneEvent is passed a flags argument that indicateswhat sort of events it is OK to process and also whether or not toblock if no events are ready. Tcl_DoOneEvent does the followingthings:
- [1]
- Check the event queue to see if it contains any events that canbe serviced. If so, service the first possible event, remove itfrom the queue, and return. It does this by callingTcl_ServiceEvent and passing in the flags argument.
- [2]
- Prepare to block for an event. To do this, Tcl_DoOneEventinvokes a setup procedure in each event source.The event source will perform event-source specific initialization andpossibly call Tcl_SetMaxBlockTime to limit how longTcl_WaitForEvent will block if no new events occur.
- [3]
- Call Tcl_WaitForEvent. This procedure is implemented differentlyon different platforms; it waits for an event to occur, based on theinformation provided by the event sources.It may cause the application to block if timePtr specifiesan interval other than 0.Tcl_WaitForEvent returns when something has happened,such as a file becoming readable or the interval given by timePtrexpiring. If there are no events for Tcl_WaitForEvent towait for, so that it would block forever, then it returns immediatelyand Tcl_DoOneEvent returns 0.
- [4]
- Call a check procedure in each event source. The checkprocedure determines whether any events of interest to this sourceoccurred. If so, the events are added to the event queue.
- [5]
- Check the event queue to see if it contains any events that canbe serviced. If so, service the first possible event, remove itfrom the queue, and return.
- [6]
- See if there are idle callbacks pending. If so, invoke all of them andreturn.
- [7]
- Either return 0 to indicate that no events were ready, or go back tostep [2] if blocking was requested by the caller.
CREATING A NEW EVENT SOURCE
An event source consists of three procedures invoked by the notifier,plus additional C procedures that are invoked by higher-level codeto arrange for event-driven callbacks. The three procedures calledby the notifier consist of the setup and check procedures describedabove, plus an additional procedure that is invoked when an eventis removed from the event queue for servicing.
The procedure Tcl_CreateEventSource creates a new event source.Its arguments specify the setup procedure and check procedure forthe event source.SetupProc should match the following prototype:
typedef void Tcl_EventSetupProc( ClientData clientData, int flags);
The
clientData argument will be the same as the
clientDataargument to
Tcl_CreateEventSource; it is typically used topoint to private information managed by the event source.The
flags argument will be the same as the
flagsargument passed to
Tcl_DoOneEvent except that it will neverbe 0 (
Tcl_DoOneEvent replaces 0 with
TCL_ALL_EVENTS).
Flags indicates what kinds of events should be considered;if the bit corresponding to this event source isn't set, the eventsource should return immediately without doing anything. Forexample, the file event source checks for the
TCL_FILE_EVENTSbit.
SetupProc's job is to make sure that the application wakes upwhen events of the desired type occur. This is typically done in aplatform-dependent fashion. For example, under Unix an event sourcemight call Tcl_CreateFileHandler; under Windows it mightrequest notification with a Windows event. For timer-driven eventsources such as timer events or any polled event, the event sourcecan call Tcl_SetMaxBlockTime to force the application to wakeup after a specified time even if no events have occurred.If no event source calls Tcl_SetMaxBlockTimethen Tcl_WaitForEvent will wait as long as necessary for anevent to occur; otherwise, it will only wait as long as the shortestinterval passed to Tcl_SetMaxBlockTime by one of the eventsources. If an event source knows that it already has events ready toreport, it can request a zero maximum block time. For example, thesetup procedure for the X event source looks to see if there areevents already queued. If there are, it callsTcl_SetMaxBlockTime with a 0 block time so thatTcl_WaitForEvent does not block if there is no new data on the Xconnection.The timePtr argument to Tcl_WaitForEvent points toa structure that describes a time interval in seconds andmicroseconds:
typedef struct Tcl_Time { long sec; long usec;} Tcl_Time;
The
usec field should be less than 1000000.
Information provided to Tcl_SetMaxBlockTimeis only used for the next call to Tcl_WaitForEvent; it isdiscarded after Tcl_WaitForEvent returns.The next time an event wait is done each of the event sources'setup procedures will be called again, and they can specify newinformation for that event wait.
If the application uses an external event loop rather thanTcl_DoOneEvent, the event sources may need to callTcl_SetMaxBlockTime at other times. For example, if a new eventhandler is registered that needs to poll for events, the event sourcemay call Tcl_SetMaxBlockTime to set the block time to zero toforce the external event loop to call Tcl. In this case,Tcl_SetMaxBlockTime invokes Tcl_SetTimer with the shortestinterval seen since the last call to Tcl_DoOneEvent orTcl_ServiceAll.
In addition to the generic procedure Tcl_SetMaxBlockTime, otherplatform-specific procedures may also be available forsetupProc, if there is additional information needed byTcl_WaitForEvent on that platform. For example, on Unix systemsthe Tcl_CreateFileHandler interface can be used to wait for file events.
The second procedure provided by each event source is its checkprocedure, indicated by the checkProc argument toTcl_CreateEventSource. CheckProc must match thefollowing prototype:
typedef void Tcl_EventCheckProc( ClientData clientData, int flags);
The arguments to this procedure are the same as those for
setupProc.
CheckProc is invoked by
Tcl_DoOneEvent after it has waitedfor events. Presumably at least one event source is now prepared toqueue an event.
Tcl_DoOneEvent calls each of the event sourcesin turn, so they all have a chance to queue any events that are ready.The check procedure does two things. First, it must see if any eventshave triggered. Different event sources do this in different ways.
If an event source's check procedure detects an interesting event, itmust add the event to Tcl's event queue. To do this, the event sourcecalls Tcl_QueueEvent. The evPtr argument is a pointer toa dynamically allocated structure containing the event (see below formore information on memory management issues). Each event source candefine its own event structure with whatever information is relevantto that event source. However, the first element of the structuremust be a structure of type Tcl_Event, and the address of thisstructure is used when communicating between the event source and therest of the notifier. A Tcl_Event has the following definition:
typedef struct Tcl_Event { Tcl_EventProc *proc; struct Tcl_Event *nextPtr;};
The event source must fill in the
proc field ofthe event before calling
Tcl_QueueEvent.The
nextPtr is used to link together the events in the queueand should not be modified by the event source.
An event may be added to the queue at any of three positions, dependingon the position argument to Tcl_QueueEvent:
- TCL_QUEUE_TAIL
- Add the event at the back of the queue, so that all other pendingevents will be serviced first. This is almost always the rightplace for new events.
- TCL_QUEUE_HEAD
- Add the event at the front of the queue, so that it will be servicedbefore all other queued events.
- TCL_QUEUE_MARK
- Add the event at the front of the queue, unless there are otherevents at the front whose position is TCL_QUEUE_MARK; if so,add the new event just after all other TCL_QUEUE_MARK events.This value of position is used to insert an ordered sequence ofevents at the front of the queue, such as a series ofEnter and Leave events synthesized during a grab or ungrab operationin Tk.
When it is time to handle an event from the queue (steps 1 and 4above) Tcl_ServiceEvent will invoke the proc specifiedin the first queued Tcl_Event structure.Proc must match the following prototype:
typedef int Tcl_EventProc( Tcl_Event *evPtr, int flags);
The first argument to
proc is a pointer to the event, which willbe the same as the first argument to the
Tcl_QueueEvent call thatadded the event to the queue.The second argument to
proc is the
flags argument for thecurrent call to
Tcl_ServiceEvent; this is used by the event sourceto return immediately if its events are not relevant.
It is up to proc to handle the event, typically by invokingone or more Tcl commands or C-level callbacks.Once the event source has finished handling the event it returns 1to indicate that the event can be removed from the queue.If for some reason the event source decides that the event cannotbe handled at this time, it may return 0 to indicate that the eventshould be deferred for processing later; in this case Tcl_ServiceEventwill go on to the next event in the queue and attempt to service it.There are several reasons why an event source might defer an event.One possibility is that events of this type are excluded by theflags argument.For example, the file event source will always return 0 if theTCL_FILE_EVENTS bit isn't set in flags.Another example of deferring events happens in Tk ifTk_RestrictEvents has been invoked to defer certain kindsof window events.
When proc returns 1, Tcl_ServiceEvent will remove theevent from the event queue and free its storage.Note that the storage for an event must be allocated bythe event source (using Tcl_Alloc or the Tcl macro ckalloc)before calling Tcl_QueueEvent, but itwill be freed by Tcl_ServiceEvent, not by the event source.
Tcl_DeleteEvents can be used to explicitly remove one or moreevents from the event queue. Tcl_DeleteEvents calls procfor each event in the queue, deleting those for with the procedurereturns 1. Events for which the procedure returns 0 are left in thequeue. Proc should match the following prototype:
typedef int Tcl_EventDeleteProc( Tcl_Event *evPtr, ClientData clientData);
The
clientData argument will be the same as the
clientDataargument to
Tcl_DeleteEvents; it is typically used to point toprivate information managed by the event source. The
evPtr willpoint to the next event in the queue.
CREATING A NEW NOTIFIER
The notifier consists of all the procedures described in this manualentry, plus Tcl_DoOneEvent and Tcl_Sleep, which areavailable on all platforms, and Tcl_CreateFileHandler andTcl_DeleteFileHandler, which are Unix-specific. Most of theseprocedures are generic, in that they are the same for all notifiers.However, five of the procedures are notifier-dependent:Tcl_SetTimer, Tcl_Sleep, Tcl_WaitForEvent,Tcl_CreateFileHandler and Tcl_DeleteFileHandler. Tosupport a new platform or to integrate Tcl with anapplication-specific event loop, you must write new versions of theseprocedures.
Tcl_WaitForEvent is the lowest-level procedure in the notifier;it is responsible for waiting for an ``interesting'' event to occur orfor a given time to elapse. Before Tcl_WaitForEvent is invoked,each of the event sources' setup procedure will have been invoked.The timePtr argument toTcl_WaitForEvent gives the maximum time to block for an event,based on calls to Tcl_SetMaxBlockTime made by setup proceduresand on other information (such as the TCL_DONT_WAIT bit inflags).
Ideally, Tcl_WaitForEvent should only wait for an eventto occur; it should not actually process the event in any way.Later on, theevent sources will process the raw events and create Tcl_Events onthe event queue in their checkProc procedures.However, on some platforms (such as Windows) this isn't possible;events may be processed in Tcl_WaitForEvent, including queuingTcl_Events and more (for example, callbacks for native widgets may beinvoked). The return value from Tcl_WaitForEvent must be either0, 1, or -1. On platforms such as Windows where events get processed inTcl_WaitForEvent, a return value of 1 means that there may be moreevents still pending that haven't been processed. This is a sign to thecaller that it must call Tcl_WaitForEvent again if it wants allpending events to be processed. A 0 return value means that callingTcl_WaitForEvent again will not have any effect: either this is aplatform where Tcl_WaitForEvent only waits without doing any eventprocessing, or Tcl_WaitForEvent knows for sure that there are noadditional events to process (e.g. it returned because the timeelapsed). Finally, a return value of -1 means that the event loop isno longer operational and the application should probably unwind andterminate. Under Windows this happens when a WM_QUIT message is received;under Unix it happens when Tcl_WaitForEvent would have waitedforever because there were no active event sources and the timeout wasinfinite.
If the notifier will be used with an external event loop, then it mustalso support the Tcl_SetTimer interface. Tcl_SetTimer isinvoked by Tcl_SetMaxBlockTime whenever the maximum blockingtime has been reduced. Tcl_SetTimer should arrange for theexternal event loop to invoke Tcl_ServiceAll after the specifiedinterval even if no events have occurred. This interface is neededbecause Tcl_WaitForEvent isn't invoked when there is an externalevent loop. If thenotifier will only be used from Tcl_DoOneEvent, thenTcl_SetTimer need not do anything.
On Unix systems, the file event source also needs support from thenotifier. The file event source consists of theTcl_CreateFileHandler and Tcl_DeleteFileHandlerprocedures, which are described elsewhere.
The Tcl_Sleep and Tcl_DoOneEvent interfaces are describedelsewhere.
The easiest way to create a new notifier is to look at the codefor an existing notifier, such as the files unix/tclUnixNotfy.cor win/tclWinNotify.c in the Tcl source distribution.
EXTERNAL EVENT LOOPS
The notifier interfaces are designed so that Tcl can be embedded intoapplications that have their own private event loops. In this case,the application does not call Tcl_DoOneEvent except in the caseof recursive event loops such as calls to the Tcl commands updateor vwait. Most of the time is spent in the external event loopof the application. In this case the notifier must arrange for theexternal event loop to call back into Tcl when somethinghappens on the various Tcl event sources. These callbacks shouldarrange for appropriate Tcl events to be placed on the Tcl event queue.
Because the external event loop is not calling Tcl_DoOneEvent ona regular basis, it is up to the notifier to arrange forTcl_ServiceEvent to be called whenever events are pending on theTcl event queue. The easiest way to do this is to invokeTcl_ServiceAll at the end of each callback from the externalevent loop. This will ensure that all of the event sources arepolled, any queued events are serviced, and any pending idle handlersare processed before returning control to the application. Inaddition, event sources that need to poll for events can callTcl_SetMaxBlockTime to force the external event loop to callTcl even if no events are available on the system event queue.
As a side effect of processing events detected in the main externalevent loop, Tcl may invoke Tcl_DoOneEvent to start a recursive eventloop in commands like vwait. Tcl_DoOneEvent will invokethe external event loop, which will result in callbacks as describedin the preceding paragraph, which will result in calls toTcl_ServiceAll. However, in these cases it is undesirable toservice events in Tcl_ServiceAll. Servicing events there isunnecessary because control will immediately return to theexternal event loop and hence to Tcl_DoOneEvent, which canservice the events itself. Furthermore, Tcl_DoOneEvent issupposed to service only a single event, whereas Tcl_ServiceAllnormally services all pending events. To handle this situation,Tcl_DoOneEvent sets a flag for Tcl_ServiceAllthat causes it to return without servicing any events.This flag is called the service mode;Tcl_DoOneEvent restores it to its previous value before it returns.
In some cases, however, it may be necessary for Tcl_ServiceAllto service eventseven when it has been invoked from Tcl_DoOneEvent. This happenswhen there is yet another recursive event loop invoked via anevent handler called by Tcl_DoOneEvent (such as one that ispart of a native widget). In this case, Tcl_DoOneEvent may nothave a chance to service events so Tcl_ServiceAll must servicethem all. Any recursive event loop that calls an external eventloop rather than Tcl_DoOneEvent must reset the service mode sothat all events get processed in Tcl_ServiceAll. This is doneby invoking the Tcl_SetServiceMode procedure. IfTcl_SetServiceMode is passed TCL_SERVICE_NONE, then callsto Tcl_ServiceAll will return immediately without processing anyevents. If Tcl_SetServiceMode is passed TCL_SERVICE_ALL,then calls to Tcl_ServiceAll will behave normally.Tcl_SetServiceMode returns the previous value of the servicemode, which should be restored when the recursive loop exits.Tcl_GetServiceMode returns the current value of the servicemode.
KEYWORDS
event, notifier, event queue, event sources, file events, timer, idle, service mode
Index
- NAME
- SYNOPSIS
- ARGUMENTS
- INTRODUCTION
- NOTIFIER BASICS
- CREATING A NEW EVENT SOURCE
- CREATING A NEW NOTIFIER
- EXTERNAL EVENT LOOPS
- KEYWORDS
This document was created byman2html,using the manual pages.