.KEYWORD rockettwo
.FLYINGHEAD PROGRAMMING POWER
.TITLE Setting application preferences
.DEPT
.SUMMARY In "When Harry Met Sally", Meg Ryan ("Sally") got all fussy about how she ordered her food. Billy Crystal ("Harry") called her "high maintenance". We at PalmPower identify with "high maintenance" and try to live our lives in such a way that we live up to that label. Another way of thinking about a high maintenance individual is to understand that such a person has many preferences. Software running on Palm organizers also has preferences, but is probably nowhere near as high maintenance as your editors. In this latest of the Programming Power series, prgramming technology editor Alan Jay Weiner shows us how you can set Palm preferences in your programs. Now if only it were that easy in real life!
.AUTHOR Alan Jay Weiner
Last month I started writing a small game for my son. This month we’ll add a couple of small features and allow some configurability. Configurations should be "sticky" — they should remain set until we change them, even if we run other programs and then return to the original application.
Palm applications use "preferences databases" to store these kinds of user configurations. Applications may store a small amount of data as a preferences record. They retrieve that data when they start, they store it when they exit. Having everyone use the same database saves each application from creating a special database just for their user configurations and provides a uniform method for applications to preserve configuration data between runs.
.H1 Changes to rocketship
Before we get into how to use preferences, lets take a quick look at what I changed in Rocketship.
First, I added a few definitions in the beginning, including the Creator ID. I’ll speak about that in a moment.
Second, I added a menu to allow configuring the vertical speed. At the same time, I changed SetPrelaunch and LaunchRocket so they set vertspeed from the configured speed (cfg_vertspeed) at launch time rather than pre-launch. SetPrelaunch occurs after the rocket hits the top, at the end of the game (such as it is). If you play a game, and then change the speed, it wouldn’t take effect on the next game since that game’s speed was already set. Setting vertspeed at launch time fixes this problem.
I also fixed two bugs. The first allowed tapping the screen to make the rocket go faster. It decremented vertspeed for each tap, but it allowed it to go below zero. This should’ve caused problems, but didn’t because of the second bug. That one failed to use vertspeed as a counter at all! If you look at RedrawRocket from last month’s listing, I never updated lastmovetime. So after the first movement delay, the rocket was going full speed! Oops…RedrawRocket now updates the lastmovetime value.
This had an interesting effect. It turns out that the value I picked for the initial time delay was way too slow. I’ve changed these so they range from 0 (fast) to 10 (very slow).
.H1 Saving and restoring preferences
Using Palm OS preferences is simple: special APIs read and write them. These APIs simply save a user-defined structure. You put whatever data you want in that structure. You don’t need to open the database or know an index or record number; these APIs refer to the data by the application’s Creator ID.
Early Pilot 1000s and 5000s running Palm OS version 1 only used a single preferences database. When the PalmPilot came out with Palm OS version 2, it added an additional database and several more preferences APIs.
Initially the preferences database was backed up like any other database. Typically this is what you want. If the PalmPilot’s memory is wiped out and restored from the backups, all the application preferences are restored as well. This database is called the "saved preferences."
PalmOS version 2 added the "unsaved preferences" database. Just as you’d expect from its name, this database doesn’t get backed up. If the Palm device is hard-reset and reloaded from backup data, those unsaved preferences are gone. Personally, I don’t see any use for it. I always save preferences. I’d rather take a few extra moments when I HotSync and be sure that I can restore everything to exactly the way it is now. But perhaps you have data that needs to survive between runs, but needn’t (or shouldn’t) be backed up. Then you’d use the unsaved preferences.
You use the same APIs for saved and unsaved preferences. The last argument in the call determines which database you’re saving into.
.H1 Creator IDs
Each application is identified by a 32-bit value called the Creator ID, displayed as four characters. The Palm Creator Database web site says to use characters in the ASCII range from exclamation mark through tilde; 0x21 through 0x7E.
Palm maintains a database of creator IDs used by existing applications. This database may be read at http://www.palm.com/devzone/crid/cridsub.html. You can register new creator IDs at this same address.
In the case of Hello World and last month’s Rocketship, I used a creator ID of "XXXX". As Rocketship will evolve into a real application I registered the ID "ajwR" for it. The creator ID is arbitrary. I just used my initials and "R" for "Rocketship".
.H1 The preferences APIs
Palm OS version 2 (and later) changed the names of the preferences APIs used by OS version 1. This was done so that programs would default to the newer APIs. If you don’t change the function name to the new name, you’ll build using the newer API.
The problem with this is that if you use the newer APIs you’ll crash on a Palm 1000 and 5000 (unless they’ve been upgraded, of course).
The newer APIs provide some additional functionality, so there’s reason to use them, but you must be aware that the program is no longer compatible with the older Pilots.
In Rocketship, I use the the older APIs where I must, and the newer APIs if they’re available. I’ll explain that later.
.H2 Palm OS version 1
The original preferences APIs are available in all current PalmPilots from the Palm 1000 and 5000 through the Palm III.
These APIs are:
.BEGIN_LIST
.BULLET PrefGetAppPreferences
.BULLET PrefGetPreferences
.BULLET PrefOpenPreferencesDB
.BULLET PrefSetAppPreferences
.BULLET PrefSetPreferences
.END_LIST
The names changed when the PalmPilots came out with Palm OS version 2.
PrefGetPreferences and PrefSetPreferences read and write the system preferences structure all at one time. This structure contains things like the date and time display format, the auto-shut-off time, whether or not private records should be displayed and so forth. The structure is defined in preferences.h. If you’re using the Palm OS 2 or 3 SDK, the OS 1 structure is a typedef named SystemPreferencesTypeV10. This structure is shown at http://www.component-net.com/pp-extras/prefs1.html.
PrefGetAppPreferences and PrefSetAppPreferences allow you to read and write an arbitrary structure (you define whatever you want) to the preferences database. Essentially, as your program exits you copy any data you want to save to a structure, then tell Palm OS to save it as the preferences for this program. When you start up the next time, you read the preferences and use that as the starting configuration.
The Palm OS 1 APIs always use the saved preferences database.
.H2 Palm OS version 2
One of the big improvements when the PalmPilot Professional and PalmPilot Personal came out was the upgrade to Palm OS version 2.
Several of the OS 1 APIs were renamed by appending "V10" to them, and replaced by several new APIs with additional functionality. This structure is shown at http://www.component-net.com/pp-extras/prefs2.html.
The OS 2 preferences APIS are:
.BEGIN_LIST
.BULLET PrefGetAppPreferences
.BULLET PrefGetAppPreferencesV10
.BULLET PrefGetPreference
.BULLET PrefGetPreferences
.BULLET PrefOpenPreferenceDB
.BULLET PrefOpenPreferenceDBV10
.BULLET PrefSetAppPreferences
.BULLET PrefSetAppPreferencesV10
.BULLET PrefSetPreference
.BULLET PrefSetPreferences
.END_LIST
PrefOpenPreferenceDB isn’t listed in the OS 2 or OS 3 documentation, but it is in the preferences.h file.
The system preferences structure also changed, and in a rather ugly way. New data was inserted in the middle of the structure, in addition to new preferences appended to the end of the structure. This is unfortunate since it breaks older code. If an older program gets the system preferences structure to find the "hide secret records" boolean, it will look at the wrong place in the OS 2 structure because gameSoundLevel was inserted before it — moving the later data down.
Fortunately, when the PalmPilots came out, developers were quick to update their Pilot 1000 and Pilot 5000 applications. At this point virtually all apps work with OS 1 and OS 2, and almost all work with OS 3.
The xxxV10 APIs are the original APIs from Palm OS version 1. Only the name has changed. Old programs calling the old APIs call these V10 APIs automatically. Their internal system-trap numbers haven’t changed.
The newer functions PrefGetPreference and PrefSetPreference get and set the system preferences a single preference at a time. There’s no need to know the overall structure, just an identification number. These numbers are enumerated in preferences.h. For example, you can get the show-hidden-records setting by calling PrefGetPreference(prefHidePrivateRecords).
Another addition for OS 2 is that you can delete the preferences for your application by calling PrefSetAppPreferences with a length of zero.
.H2 Palm OS version 3
The Palm III came with even more improvements and changes. Fortunately, the only change to the system preferences structure were changing the names of the sound levels, and adding new preferences to the end of the structure.
Look at http://www.component-net.com/pp-extras/prefs3.html to see shows the system preferences structure for Palm OS 3.
.H1 Handling rocketship preferences
Ok, so how does all this work? Look at Rocketship at http://www.component-net.com/pp-extras/prefs4.html and you’ll see I’ve added two routines; ReadAppPreferences to load the preferences when Rocketship starts, and SaveAppPreferences to save them as the application exits.
To determine which APIs should be used, another routine (GetOSVersion) returns the Palm OS version number. The load and store routines check which OS is running and use the appropriate routines.
For this program, there’s not much being stored, and that which is being stored is placed in the saved preferences, so why bother checking which OS is running? Why not just use the OS 1 APIs or the OS 2 APIs?
If I use the OS 2 APIs, then the program won’t run on Pilot 1000s and 5000s. There’s no reason to needlessly exclude those machines. And if I just use the OS 2 APIs, there’s a risk that a future machine would support the newer APIs and not the older ones. If that happens, then Rocketship would crash on it. Of course, some future machine may not support either API, but the newer APIs are supported on the Palm III so it’s likely they’ll be supported longer.
Additionally, I wanted to show you how to determine what OS you’re running under. If you’re reading system preferences, you need to know what preferences are there, and you need to deal with the structure changes between OS 1 and OS 2.
.H1 Next month
Next month we’ll add a few new things to Rocketship, making it into a playable game. It’ll still be simplistic, but be more entertaining than it currently is.
.BEGIN_SIDEBAR
.H1 Product availability and resources
Source code and executable for this project is at http://www.ajw.com/PalmPower/ProgrammingPower/Oct98/Rocketship.zip.
3Com’s database of creator IDs is at
http://www.palm.com/devzone/crid/cridsub.html.
.END_SIDEBAR
.BIO Alan Weiner has many preferences – primarily chocolate. His email address is alan@ajw.com.
.DISCUSS http://www.component-net.com/webx?13@@.ee6c302


