Structure of a Palm Application, Part 3
Pages: 1, 2
Examples
There are other communications between the Palm OS and your application that you might want to handle in your code. Particular events, or overall access might be important for you to control. In any case, here are events some applications want to handle:
- A particular pen-down event
- The input of a graffiti character
- How to take over the hard buttons for your own use within your application
- How to take over the entire device and not allow any other applications to run
Let's take a look at the code required to handle each of these instances.
Handling a Pen-Down Event
Normally, you will not handle pen-down events directly, but instead handle
higher-level events like ctlSelectEvent. However,
occasionally, applications will want to be on the lookout for a penDown event. An example is the Address Book: tapping
and releasing on the display of an address in the display view switches to the
edit view.
The source code to the Address Book is part of the Palm OS 3.5 SDK. The RecordViewHandleEvent in Address.c from that example contains the following case:
case penDownEvent:
handled = RecordViewHandlePen(event);
break;
RecordViewHandlePen handles penDown events in the display-only view of the record
(see Example 5-15).
Example 5-15: RecordViewHandlePen in the Address Book source
static Boolean RecordViewHandlePen (EventType * event) {
Boolean handled = false;
FormPtr frm;
RectangleType r;
Int16 x, y;
Boolean penDown;
// If the user taps in the RecordViewDisplay take her to
the Edit View.
frm = FrmGetActiveForm( );
FrmGetObjectBounds(frm, FrmGetObjectIndex(frm,
RecordViewDisplay), &r);
if (RctPtInRectangle (event->screenX,
event->screenY, &r))
{
do
{
PenGetPoint (&x, &y, &penDown);
} while (penDown);
if (RctPtInRectangle (x, y, &r))
FrmGotoForm (EditView);
handled = true;
}
return handled;
}
The calls to the Form Manager routines FrmGetActiveForm and FrmGetObjectBounds yield the rectangle containing the
address display area. RctPtInRectangle checks to see
whether the pen-tap location (event->screenX
and event->screenY) are within those bounds.
Note that it then enters a loop calling PenGetPoint
until the user releases the stylus. If the user lets go within those same
bounds, the code switches to the edit view.
Handling a Graffiti Character
To show you an example of handling a graffiti character, we turned to the Reptoids game (one of the samples in the Palm OS 3.5 SDK). While the game is running, entering a "t" character displays the amount of time spent playing on-screen.
The Rocks.c file has the following check in MainViewHandleEvent:
else if (event->eType == keyDownEvent)
{
// Time spent playing. (Quick code at this
point.)
if (event->data.keyDown.chr == 't')
{
// ... Code that displays game-time is here.
}
return true;
}
Note that the routine checks the incoming character by looking within the
event: event->data.keyDown.chr.
Overriding Hard-Button Behavior
Some applications want to redirect the hard button presses (the Date Book
key, for instance) for their own use. An obvious example would be games.
Pressing a hard button generates a keyDownEvent
and as such can be looked for by an application. Indeed, the keyDownEvent is sent for all of these:
- The four application buttons
- The Power button
- The scroll buttons
- The Find button
- The Calculator button
- The antenna being raised on a Palm VII
In all the instances, a special modifier bit (the commandKeyMask) is set in the modifiers associated with
that key. This distinguishes it from a normal Graffiti character.
However, for all but the scroll buttons, the system handles the keyDownEvent, and doesn't allow the form's event handler
to deal with it.
Now, let's see how we can use this information to modify our source code to our advantage. We will make an application where tapping on the Date Book key doesn't bring up the Date Book, but instead does something app-specific.
First off, we need to avoid calling SysHandleEvent when that key is pressed (see Example 5-16).
Example 5-16: AppEventLoop that doesn't call SysHandleEvent for taps on the Date Book key
static void AppEventLoop(void)
{
Err error;
EventType event;
do {
Boolean isDatebookKey;
EvtGetEvent(&event, evtWaitForever);
isDatebookKey = (event.eType == keyDownEvent)
&&
(TxtCharIsHardKey(event.data.keyDown.modifiers,
event.data.keyDown.chr))
&& (event.data.keyDown.chr == vchrHard1);
if (isDatebookKey || ! SysHandleEvent(&event))
if (! MenuHandleEvent(0, &event, &error))
if (! AppHandleEvent(&event))
FrmDispatchEvent(&event);
} while (event.eType != appStopEvent);
}
Note that we figure out whether it is a hard key, and then whether it is the
Date Book key (vchrHard1). If it is, we don't call
SysHandleEvent, and so the normal processing for that
character won't happen. However, the event will be passed to FrmDispatchEvent
(after being ignored by MenuHandleEvent and AppHandleEvent),
and from there to our event handler.
Here's code in MainFormHandleEvent that switches to
the second form if the Date Book key is pressed:
switch (event->eType)
{
case keyDownEvent:
if (TxtCharIsHardKey(event->data.keyDown.modifiers,
event->data.keyDown.chr)
&& (event->data.keyDown.chr == vchrHard1))
{
FrmGotoForm(SecondForm);
handled = true;
}
break;
Controlling the Exiting of an Application
Some turnkey applications take over the machine and don't allow any other applications to run. For example, a Palm OS device carried by delivery people might only run a delivery application; it's locked for any other purpose.
TIP: Admittedly, this is a very rare UI. A standard Palm application should always quit when the user requests another application (by pressing one of the hard buttons, for instance). Standard applications should not have an explicit UI for quit, however. Users implicitly quit an application by starting another.
How do you write an application that takes control of the Palm OS unit and
won't let go? It's simple. In order to keep other applications from running,
you rudely refuse to exit from your main event loop. As a result, the
application never quits (except on a reset). All the OS can do is post an
appStopEvent to the event queue, requesting (nay,
strongly urging!) your application to quit. It's up to the application itself
to actually quit, though.
In the simplest case, you might just code your event loop so that it never exits (see Example 5-17).
Example 5-17: AppEventLoop that never exits
static void AppEventLoop(void)
{
Err error;
EventType event;
do {
EvtGetEvent(&event, evtWaitForever);
if (! SysHandleEvent(&event))
if (! MenuHandleEvent(0, &event,&error))
if (! AppHandleEvent(&event))
FrmDispatchEvent(&event);
} while (true); // Don't ever quit.
}
This will ensure that your application, once running, will never exit. It'll
silently ignore an appStopEvent that is posted to
the event queue.
Another scenario is an application that won't quit unless given a specific
command. Some turnkey applications provide a mechanism (perhaps a
password-protected button or menu item) to quit the application and open up the
unit to the rest of the Palm UI. The easiest way to implement this is to have a
global variable specifying whether appStopEvents
should be ignored. When the button is pressed, the application can post an
appStopEvent, and set the variable. Here's how the
event loop would change:
static void AppEventLoop(void)
{
Err error;
EventType event;
do {
EvtGetEvent(&event, evtWaitForever);
if (! SysHandleEvent(&event))
if (! MenuHandleEvent(0, &event, &error))
if (! AppHandleEvent(&event))
FrmDispatchEvent(&event);
} while (!(event.eType == appStopEvent && AppShouldStop( )));
}
AppShouldStop just returns the value of the
global:
Boolean gShouldStop = false;
Boolean AppShouldStop( )
{
return gShouldStop;
}
Now, when the specific action occurs (like pressing a button or choosing a
menu item), a routine MakeAppStop would be called to
set the global, and post an appStopEvent to the
event queue (see Example 5-18).
Example 5-18: MakeAppStop that causes the application to quit
void MakeAppStop( )
{
UInt32 romVersion;
gShouldStop = true;
FtrGet(sysFtrCreator, sysFtrNumROMVersion,
&romVersion);
if (romVersion <
sysMakeROMVersion(2,0,0,sysROMStageRelease,0)) {
AppLaunchWithCommand(sysFileCDefaultApp,
sysAppLaunchCmdNormalLaunch, NULL);
} else
PostAppStopEvent( ); // Launch previous app.
}
WARNING: Palm OS 1.0 relaunches the last application, so the code must explicitly launch an application in this case. (The default application is the one that is shown after a reset.) Any post-1.0 OS launches the previous application, so the code just posts an
appStopEvent.
Here's the code that posts the appStopEvent.
Note that whenever you create an event yourself, you should zero out the entire
structure so that unused fields are zero:
static void PostAppStopEvent( )
{
EventType event;
// Set all unused fields to 0.
MemSet(&event, sizeof(event), 0);
event.eType = appStopEvent;
EvtAddEventToQueue(&event);
}
What to Remember
In this chapter, we have given you a description of important terminology, standards, and a description of how an application interacts with the Palm OS on a device. Most importantly, you should remember the following:
- A Palm application is an event-driven system. The system's event queue feeds a constant flow of events to your application and it is up to you to handle them.
- Events are fed to four different routines (
SysHandleEvent,MenuHandleEvent,AppHandleEvent,FrmDispatchEvent) in your event loop. Each routine has responsibilities for various events. - A standard Palm application has a main routine,
PilotMain, from which everything is called. We showed you a sample program that contains a typicalPilotMainroutine that you will use in your own applications. - There are times, other than when opened by the user, when your application may be called by the system. Launch codes and the various launch flags tell your application how it was called by the system and what is expected.
From all of this information, you should now be well on your way to understanding this application architecture. In the following chapters, you will be using this information to move beyond our simple OReilly Starter application to create a full-featured application.
Neil Rhodes and Julie McKeehan are experienced authors who, through their company, Calliope Enterprises, work closely with Palm Computing to develop new training materials, materials that are based on this book.
|
Related Reading Palm OS Programming |
Return to the Wireless DevCenter




