.FLYINGHEAD PROGRAMMING POWER
.TITLE Hello World!
.DEPT
.SUMMARY Have you ever wondered how PalmPilot program really works? What magical incantations are required to get everything on-screen every time? Well, this is your lucky day! Contributing editor Alan Jay Weiner takes you through "hello world", the simplest of C programs. Even if you are not a programmer, you’ll find this article enlightening.
.AUTHOR Alan Jay Weiner
.BEGIN_SIDEBAR
.H1 Note on program listings
PalmPower is still a growing journal. And as such, it occasionally has growing pains. In this case, the growing pains relate to how it displays program code in your Web browser. PalmPower is created using a powerful and complex Journal Production System that performs all of the HTML code generation (including creating back issue lists, tables of contents, and even paginating articles). Unfortunately, raw C code apparently confuses the current version of the Journal Production System. Rather than leaving you without Alan’s excellent code examples, we will simply be including links to individual, separate HTML pages containing the code. It’s not as pretty as we would normally like, but it will get the job done until we can get the production software trained on the intricacies of C code. — DG
.END_SIDEBAR
In The C Programming Language by Brian Kernighan and Dennis Ritchie, their first example of a C program is the now-traditional "hello, world" program. This four-line program simply prints the words "hello, world" and exits.
K&R wrote it like this (see http://www.component-net.com/pp-extras/helloworld1.html).
Alas, life is not so simple any more – the classic "hello, world" program is quite a bit more complex when we code it for the PalmPilot.
PalmPilot applications generally don’t start and run to completion without yielding control to the Palm OS operating system. Applications that fail to yield control prevent other things from working. For example, the user can’t switch to other applications, power down, or do a "find." Most applications will start, display a screen, and then yield until they’re told to do something. Usually the user will press a button, select a menu option, or some outside event will cause the program to do something. Such programs are "event driven". They do a little work each time some particular event occurs.
For example, when the built-in Address Book starts, it does some initialization, reads the first few data records, and displays a screen. It then pauses, handing control back to Palm OS until the user does something – perhaps pressing the "new" button. The button press is an event. The program then scurries off to do a bit of work before returning to the OS to wait for the next event.
This month, we’ll look at an appallingly complex "hello, world" application for the PalmPilot. Step by step, we’ll examine how this "simple" application works, walking through application start, exit, and the various events it receives and processes during operation.
Before we look at the code, let’s take a look at what our application looks like on the PalmPilot. We’ll also learn some of the Palm OS terminology.
.H1 Screens are called "Forms"
Figure A shows the "hello" application running. There’s a menu bar, a single line saying hello, and a single button. This display is a single form: a bunch of user-interface things, called "controls", which are displayed together. This main form contains three controls: the menu bar, a text label (saying "hello world") and a button. Most of the user-interface pieces you’re already familiar with are controls (i.e., fields for text entry, checkboxes, buttons, drop-down menus, and so forth) even a list like the Memo Pad’s list of memos is a control.
.FIG A This is the "Hello World" application.
You define the form using these controls – saying how large each control is, where it’s placed on the form, and any other parameters that apply to that control. For buttons, you’d define the text on them, for text fields you’d define how many lines of text, whether it should auto-capitalize the first character, etc. Each control has an ID number. When the user presses a button, internally the program is told something like "button 22 was pressed."
.H1 Start – do stuff – stop
Typically, programs do a bit of start-up processing, and a bit of clean-up at exit. The rest of the time is a series of wait for event, process that event, wait for next event loops. This is the "event loop". Most applications should spend almost their entire lives inside the event loop.
Start-up processing tells Palm OS which form to use first, along with whatever particular setup the application itself needs. Exit processing closes any open forms and returns to Palm OS.
Many programs maintain some "state information" between times when they are used – for example, what they were last doing, and any preferences or options the user has set. This information would be loaded during start-up and saved during exit. By keeping state information and returning to where it was before, it appears as if each program is still running.
.H1 The application’s heartbeat: the event loop
The event loop asks Palm OS for the next event. Usually there are no events (at least at nano-second computer time), so Palm OS waits until the next one occurs. Almost everything causes events: touching a control, the clock ticking inside, asking the OS to do something, and so forth.
The OS queues events, giving them to the program one at a time when the event loop asks for the next event. While processing (also called "handling") events, programs often do more system calls to Palm OS which causes additional calls to be queued.
With each handled event, the program does a little more work. Finally, after marching its way through enough events, the program has done its job for now, displaying the address list or a memo, or in our case, displaying "hello world.".
Events, and the program’s work, progresses in this manner until an event tells the program it should exit. This "stop event" tells the event loop to stop; the program does its exit processing, and returns to Palm OS.
.H1 Peeking behind the curtain – the source code
Looking at Listing A (see http://www.component-net.com/pp-extras/helloworld2.html), we see HELLO.PRC consists of six functions. Let’s review each function. I’ll take them roughly in the order they run.
.H2 Function 1: PilotMain()
We begin at PilotMain(). In most applications, this is the first function where the program gains control; the function called by Palm OS. Ours simply checks the "launch code" (more on that in a moment), calls the start-up routine, and enters the event loop. When the event loop returns (after the "stop event") PilotMain() calls the exit routine and returns to Palm OS.
.H2 Function 2: StartApplication()
StartApplication() does the program’s setup and initialization. Many applications do more start-time processing than our application does, so I’ve written StartApplication() as a separate function. Given how little it does here, it could be merged into PilotMain().
Our StartApplication() simply tells Palm OS to use our main form. We do this by calling the system API FrmGotoForm(), giving it the ID number of the form we want. The header file HelloRsc.H defines all the form and control ID numbers. Think of HelloRsc.H as "Hello application Resources Header." We’ll see more about resources after reviewing the source code. Listing B shows HelloRsc.H (see http://www.component-net.com/pp-extras/helloworld3.html).
.H2 Function 3: StopApplication()
Similarly, our StopApplication() also does very little; it too could be merged into PilotMain(). Again, since there’s often more exit-time clean-up, I’ve written it as a separate function. Our StopApplication() simply tells the OS to close all open forms.
Applications which preserve information between uses would typically read the information in StartApplication() as they start and write it in StopApplication() as they exit.
.H2 Function 4: EventLoop()
As I wrote before, the real work is in the event loop; ours, predictably, is in the function named EventLoop().
EventLoop() gets the next event from Palm OS, and hands it off to event handlers until an event handler indicates it has handled the event. When the event loop calls EvtGetEvent(), Palm OS returns the event information as an EventType structure. This structure tells us the type of event and other pertinent information. We’ll see this work later as we walk through a few events.
Each event handler checks if it should do anything with that type of event, does so if it should, and returns, indicating it did or did not do anything. Some handlers are part of Palm OS, others are part of the application.
The first, SysHandleEvent() is a Palm OS API that handles system events; things like turning the PalmPilot off, pressing one of the hardware buttons, doing a "find," and so forth.
If SysHandleEvent() didn’t handle the event, it’s passed to MenuHandleEvent(). Again a system API, it handles such as tapping on the menu key or selecting a menu item.
If still not handled, the event loop passes the event to ApplicationHandleEvent(). This is the first user-defined event handler. Typically it checks for only "load form" events; setting a form event handler for the specified form. Usually each form has its own event handler.
Finally, if the event still hasn’t been handled, it is given to FrmDispatchEvent(). Another OS API, it sends the event to the appropriate event handler for the active form. That’s the one set when ApplicationHandleEvent() handles the "load form" event. The form-event-handler watches for any events where we should actually do work. For example, our main-form-specific handler handles the button-press event that causes us to display "hello again!"
It’s a bit convoluted. Just remember that the event loop gets an event, passes it to several event handlers, and one of them handles the event. The form-specific handler handles the events that make us do real work.
.H2 Function 5: ApplicationHandleEvent()
Our ApplicationHandleEvent() indeed does handle just one event: frmLoadEvent, a message from the OS indicating we’re loading a new form. Getting the form ID number from the event structure, we tell Palm OS to initialize and activate that form. Then, we tell the OS which event handler to use for that form’s events. Again, that’s the handler called when the event loop passes an event to FrmDispatchEvent().
.H2 Function 6: MainFormHandleEvent()
This is where we watch for events and do real work. Ours handles three types of events:
.BEGIN_LIST
.BULLET frmOpenEvent tells us the form is active – we can now draw it. So we do; we get a pointer to the form, and tell the OS to draw that form on the display. Palm OS draws the form and its controls.
.END_LIST
.BEGIN_LIST
.BULLET ctlSelectEvent tells us a control has been "selected" – in our case; the "hello again" button was pushed. We check the button ID number (given in the event structure); if it’s the "hello again" button, we draw "hello again" on the form. WinDrawChars() puts the text onto the display (onto the current form); most of the line is to calculate where to place it so it’s centered.
.END_LIST
.BEGIN_LIST
.BULLET menuEvent tells us that a menu item was selected. Usually what we do depends on the menu item’s ID number. We’re told that in the event structure. Since we know there’s only one menu option ("about") we take a shortcut. With only one choice, we just do the work. First, we tell the menu to go away, then switch to our AboutForm (by its form ID number). We treat it here as a special dialog; we’ll cover this in more detail in another article. In short, it displays the AboutForm and when the user presses the AboutForm’s "ok" button it closes that form. The key is that nothing can happen except pressing a button to close the form. That’s why I didn’t do the whole "hello world" application as a special dialog.
.END_LIST
.H1 Beginning at the beginning – or just a tad before
Now, let’s see how these routines fit together as a few events occur. We won’t go through all the events; there’s many events we don’t need to handle. The OS does their default handling. These events march through the event handlers and each handler returns "no, I didn’t handle it."
.H1 Program launch; display the main form
Something starts our program. There are various "launch codes" that indicate how or why a program has started, but for now we’ll assume a standard program start by tapping the icon in the application launcher.
We’ll ignore all the set-up stuff that happens before our code. Just accept that some magic happens and the application begins running. We can cover all the gritty details another time.
Palm OS passes PilotMain() several parameters. The first is the launch code. For now, we’ll ignore the other parameters; HELLO.PRC doesn’t use them.
.BEGIN_SIDEBAR
.H1 Gotcha! #1: Check the launch code before using static or global data!
Applications may run under special conditions when static and global data are not accessible. Attempting to use this data will crash the PalmPilot!
For example, let’s assume you (erroneously) initialize some data prior to checking the launch code. When the user does a "find", your program will be called with a sysAppLaunchCmdFind launch code. During this launch code, your static data is not available. Remember the magic happening before your app launches? Making your data available is part of it. And it doesn’t happen for the "find" launch code!
Your application starts, attempts to initialize the data, but the data isn’t accessible! Boom! Your application crashes, displaying "fatal error."
.END_SIDEBAR
If it is a sysAppLaunchCmdNormalLaunch, then PilotMain() calls StartApplication() to do initialization, then enters the event loop in EventLoop().
.H1 Inside the event loop
The event loop gets the next event: it’s a frmLoadEvent. This event is a result of the call to FrmGotoForm() in StartApplication().
The event loop passes the event to SysHandleEvent() then to MenuHandleEvent() then to ApplicationHandleEvent(). Here, we initialize and activate the form, and tell Palm OS the form’s event handler. When ApplicationHandleEvent() returns, the event loop gets the next event as this one’s now been handled.
The next event is frmOpenEvent. This marches through the event handlers (each returning "not handled") until it’s passed to FrmDispatchEvent(). FrmDispatchEvent() sends it to the active form’s event handler, which is our MainFormHandleEvent(). MainFormHandleEvent() handles it, displaying the form and controls as described before. It returns "handled" so the event loop asks for the next event.
This time there isn’t any, so the OS sits and waits. Eventually, the user presses the "hello again" button, so the OS puts a "button pressed" event (i.e., ctlSelectEvent) into our queue. As our application is waiting for an event, its immediately passed on to the event loop. Actually, we’ve gotten a whole slew of events as the user presses the button. These events went through each handler – each returning "not handled" – so Palm OS handled them. These are events like "pen touched the screen" (penDownEvent), "pen lifted off the screen" (penUpEvent) and so forth. Palm OS recognizes these relate to the button control on our form, so there are other events related to the button, the final one being the ctlSelectEvent which we use to trigger our work.
The ctlSelectEvent marches through the event handlers until it too is handed to MainFormHandleEvent(). MainFormHandleEvent() handles it by displaying "hello again" as shown in Figure B and returns indicating "event handled."
.FIG B This is what it looks like after pressing the "hello again" button.
Again, the event loop asks for the next event, and Palm OS waits for the next one to occur.
.H1 Billions and billions of little events
Event after event, our little PalmPilot does its work. You can see how much goes on just to display a simple form with a few simple controls. Imagine how much goes on to do real work!
Fortunately, it gets somewhat easier. If you look at the processing for the "hello again" button, it’s minimal compared to the basic program structure. Once the program skeleton is working, controls and forms are added relatively easily. For example, you could easily add the about screen shown in Figure C.
.FIG C This is the application’s "About" screen.
.H1 Resources: defining the forms and controls
Each program includes "resources" which define the forms and controls used by that program. The program’s icon is another resource; text strings may also be attached as resources.
We’ll cover resources more completely in future columns, but we need to touch on them a bit here.
CodeWarrior and GCC build resources in quite different ways. CodeWarrior uses a graphical "drag-and-drop" tool called Constructor. You build each form by dragging controls from the "catalog" and placing them on the form, then configure the control as necessary (size, text, etc.). When you save it, Constructor automatically creates the header file with the ID numbers.
GCC uses a text script and Wes Cherry’s PilRC utility. PilRC takes the text script and builds the resources.
Unfortunately, the methods are incompatible; there are no tools for creating CodeWarrior resources from a PilRC script, nor vice-versa. We’ll examine creating CodeWarrior and GCC resources in upcoming columns.
.H1 In Conclusion
We’ve covered a lot here, but once the event loop makes sense you’re well on your way to writing PalmPilot programs. Next month we’ll start looking at controls and resources in detail.
.BEGIN_SIDEBAR
.H1 Product availability and resources
I’ve placed the source code (for both CodeWarrior and GCC) on my web site. You can download them at:
CodeWarrior version: http://www.ajw.com/PalmPower/ProgrammingPower/May98/cw.zip
GCC version:
http://www.ajw.com/PalmPower/ProgrammingPower/May98/gcc.zip
.END_SIDEBAR
.BIO Alan Weiner works hundreds of hours each week writing software so he can retire early and spend the rest of his life in leisure – writing software. His email address is alan@ajw.com.
.DISCUSS http://www.component-net.com/webx?13@@.ee6bd4e


