In most cases, using the RunApplicationEventLoop function to collect and dispatch events is the simplest and most practical way to handle events. However, sometimes you may want more control over the event collection and dispatching mechanism, or you may need to process events that don’t occur in the main application thread. In cases like these, you can call other Carbon Event Manager functions to manually collect and dispatch your events.
The RunApplicationEventLoop function itself calls several Carbon Event Manager functions to accomplish its task:
ReceiveNextEvent runs the low-level event loop, placing events as they occur into the event queue. The function returns when an event you specified occurs, or when the specified timeout is exceeded.
OSStatus ReceiveNextEvent( |
UInt32 inNumTypes, |
const EventTypeSpec *inList, |
EventTimeout inTimeout, |
Boolean inPullEvent, |
EventRef *outEvent); |
The inNumTypes parameter specifies the number of events for which ReceiveNextEvent should return. Passing 0 indicates you want to return on all events.
The inList parameter points to the EventTypeSpec structure or array containing the class and kind of events to return on. Passing NULL indicates that you want to return on all events.
The inTimeout parameter is the duration to wait before timing out.
The inPull parameter specifies if whether you want ReceiveNextEvent to pull the event off the queue when it returns. Passing true causes the event to be pulled. If you pass false, ReceiveNextEvent only peeks at the event to determine its type. You still can dispatch the event, but it remains on the queue.
On return, outEvent contains the event that caused ReceiveNextEvent to return.
GetEventDispatcherTarget gets the event target reference for the standard toolbox dispatcher, which is the default target for all events. The toolbox dispatcher determines the proper target for each event (window, control, and so on) and sends the event there. Note that because the toolbox dispatcher is itself a valid event target, you can actually attach a handler to it. Such a handler can intercept an event before it gets sent on to the actual event target.
SendEventToEventTarget dispatches the event to the appropriate event target.
ReleaseEvent releases the event (disposing of it if necessary).
Listing 2-10 shows how you can use these calls to implement the basic functionality of RunApplicationEventLoop.
Listing 2-10 Processing events manually
EventRef theEvent; |
EventTargetRef theTarget; |
theTarget = GetEventDispatcherTarget(); |
while (ReceiveNextEvent(0, NULL,kEventDurationForever,true, |
&theEvent)== noErr) |
{ |
SendEventToEventTarget (theEvent, theTarget); |
ReleaseEvent(theEvent); |
} |
The ReceiveNextEvent function is blocked forever (kEventDurationForever) until an event occurs. Specifying zero and null for the first two parameters indicates that ReceiveNextEvent should return on all events. (Alternatively, you could specify that the function wait only for particular events). Passing true in the third parameter indicates that the application should take ownership of the event (which means it is pulled off the event queue).
After an event occurs, we dispatch it to the event dispatcher target, which automatically sends it to the proper event target. Because the application owns the event, the application is then responsible for releasing it by calling ReleaseEvent. (There is also a complementary function RetainEvent, which you can use to increment the reference count of the event, thus ensuring that it will not get disposed before you are finished with it.)
The only drawback to making your own event loop dispatching calls in the main application thread is that you won’t get the standard application event handler installed. Specifically, the RunApplicationEventLoop function installs handlers to do the following:
Allow clicks in the menu bar to begin menu tracking
Respond to quit Apple events by quitting RunApplicationEventLoop.
One way to work around this limitation is by creating a dummy custom event handler. When you are ready to process events, create the dummy event yourself, post it to the queue. and then call RunApplicationEventLoop (to install the standard application event handler). The dummy event handler can then process the events manually. For an example of using this method, see Technical Q&A 1061 in Developer Documentation Technical Q&As.
Last updated: 2005-07-07