http://www.developer.com/ws/brew/article.php/3661341/Extending-Event-Handling-with-the-BREW-UI-Toolkit.htm
One of the challenges of writing a large BREW application is keeping your event handling code organized. Although breaking up your event handler by application state and/or event type can help, the result becomes a proliferation of conditionals and function dispatches in your application's main event handler. With the advent of the BREW uiOne Toolkit (BUIT), however, there's a better approach: the HandlerDesc and the IHandler interface. The purpose of the HandlerDesc is simple: It lets you chain functions by storing function pointers and associated context data at run time. By creating a list of event handlers, and having each event handler chain to the next, as long as the first event handler invokes the first event handler in the chain and checks its return value before continuing to process the event, user-level functions can hook the behavior of a component's provided event handler. HandlerDescs work with any BREW interface that implement the IHandler interface. This includes the BUIT widgets and forms, making it an important part of building BUIT-based applications. Using a HandlerDesc to do this is easy: You also can use a HandlerDesc to hook a component's destruction. This is important if you want to destroy component-related context data at the same time that the component is freed. Under the hood, a HandlerDesc structure is just the information that encapsulates your event handler: Of course, as with most BREW structures, you shouldn't access these slots directly. Instead, BREW provides a macro, HANDLERDESC_Init, to do so: The context data (in this case, pMe), is passed to both the event handler (MyEventHandler) and the destruction-time handler (MyFreeFunction) when the component invokes either of these functions. You still need to register the HandlerDesc with the event-handling component for it to do anything. This is done by using the component's SetHandler call: This causes the Handler to register your HandlerDesc within its context, ensuring that it gets called at an appropriate time during the event handling process instead of its native event handler. Once your event handler handles incoming events, it must chain to the existing event handler. That's because the IHANDLER_SetHandler interface replaces the existing event handler with your event handler; if you still want the default event-handling behavior of the original component, you must invoke its event handler as well: Precisely when you do this depends on the behavior you seek. In most cases, you want to patch an existing event handler, either handling unhandled events or changing how an event is handled. In that case, your event handler should handle incoming events first, performing whatever custom actions you desire, and then invoke HANDLERDESC_Call, returning its result so that previous event handlers know whether or not the event was handled. A common reason to trap an event is to know when a particular form has become active—say, to play a sound when a screen is drawn or ensure that the screen has the latest contents available from a persistent store. Because IForm implements IHandler (as does IWidget), a HandlerDesc is the idea way to solve this problem. (Note that in the following example I've omitted error checking from common routines such as CreateInstance for brevity.) First, I need a custom event handler. This might be as simple as this one: I also need a cleanup function, say, to clean up the IMedia player used to play my custom sound, or to close the persistent data store: Next, I create the data container that will hold the form and HanderDesc, as well as the form. In the process, I'll register my event handler and cleanup function with the form as well: I now can push the new form on the form stack; as a consequence, MyHandleEvent will be invoked with a FID_ACTIVE event, and I can process the event however I please. Once it's processed, I can pass the event on to the form's event handler, and it operates as it should. That's all there is to it! The HandlerDesc mechanism is a powerful way to adapt and extend a fixed component's event handler. Not only is it a crucial part of building an application using the BUIT, but you also can use the same interface in your applications with custom components for greater extensibility, too! Qualcomm BREW (incluing the uiOne Toolkit): http://www.qualcomm.com/brew Ray Rischpater is the chief architect at Rocket Mobile, Inc., specializing in the design and development of messaging and information access applications for today's wireless devices. He is the author of several books on software development, including eBay Application Development and Software Development for the QUALCOMM BREW Platform, both available from Apress, and is an active Amateur Radio operator. Contact Ray at kf6gpe@lothlorien.com.
Extending Event Handling with the BREW UI Toolkit
February 22, 2007
Enter the HandlerDesc
Under the Hood
typedef struct {
PFNHANDLER pfn;
void * pCxt;
PFNFREEHANDLER pfnFree;
} HandlerDesc;
HANDLERDESC_Init( &pMe->handler, MyEventHandler, pMe,
MyFreeFunction );
IHANDLER_SetHandler( (IHandler*)pMe->p, &pMe->handler );
result = HANDLERDESC_Call( &pMe->selectHandler, evt, wParam,
dwParam );
Examining a HandlerDesc in Action
static boolean MyHandleEvent( SMyForm *pMe, AEEEvent evt,
uint16 wParam, uint32 dwParam )
{
if ( evt == FID_ACTIVE )
{
// Use the data in pMe to play a sound, update the model for
// the widgets in this form, or whatever.
}
return HANDLERDESC_Call( pMe->selectHandler, evt, param,
wParam, dwParam );
}
static void MyCleanup( SMyForm *pMe )
{
// Free up anything in pMe that is on the heap.
IFORM_Release( pMe->pIForm );
// Then release my context
FREE( pMe );
}
IForm * MyForm_Create( CApp *pMe )
{
SMyForm *pForm = MALLOCREC( SMyForm );
// Do any other necessary setup here.
ISHELL_CreateInstance( pMe->a.m_pIShell, AEECLSID_FORM,
(void **)&pForm->pIForm );
HANDLERDESC_Init( &pMe->handler, MyHandleEvent, pMe,
MyCleanup );
IHANDLER_SetHandler( (IHandler*)pMe->pIForm, &pMe->handler );
return pForm->pIForm;
}
Conclusion
Related Resource
About the Author