http://www.developer.com/

Back to article

Windows Programming for Palm OS


February 2, 2005

Why You Need It

Once you've decided to develop an amazing new game for the Palm OS, you need to discover how to implement your brilliant idea. In simple cases, you propably can end up on the standard Form Manager API. In more interesting cases, Form Manager does not provide sufficient functionality. You then can develop a new custom gadget that will fit perfectly with your needs. But, who knows? Maybe straightforward drawing on the screen will simplify your life much more effectively.

Window Manager also can help you in different situations when you want to display some waiting message on the screen during lengthy operations, a progress bar, and so forth. This article will discuss how to manage windows under Palm OS.

Palm OS Does Windows

Well, that's the truth; Palm OS has the concept of windows. As the SDK documentation states, each form is a window, but not each window is a form. Thus, a 'window' gives you lower-level access to screen resources. You're paying for it by taking responsibility for display contents for the selected area. From the other side, you get full control over the device's screen. So, for those of you who are familiar with MS Windows programming, Window Manager is pretty similar to drawing-related procedures in pure WinAPI calls. Offscreen windows, active drawing window, fonts, images, and so forth—these are topics you're going to face.

But, let's stop the common discussions and move to more practical stuff. You'll find, in Window.h, about a hundred functions covering different aspects of window management. The first thing you will look at is the notion of display window. The system creates a special window at startup. It has the same size as the Palm OS drawable area of the physical display. You can obtain it calling the following:

WinHandle WinGetDisplayWindow(void);

Usually, you won't use this window, but it's nice to know that you at least have such capability. Next, you have a bunch of functions for window management. Below, the most useful APIs are listed. You can gather some sense from their names of what they actually do:

//-----------------------------------------------
// Routines relating to windows management
//-----------------------------------------------

WinHandle WinCreateOffscreenWindow (Coord width, Coord height,
                                    WindowFormatType format,
                                    UInt16 *error)
WinHandle WinCreateBitmapWindow (BitmapType *bitmapP, UInt16 *error)
void WinSetActiveWindow (WinHandle winHandle)
WinHandle WinSetDrawWindow (WinHandle winHandle)
WinHandle WinGetDrawWindow (void)
WinHandle WinGetActiveWindow (void)
void WinGetWindowFrameRect (WinHandle winHandle, RectangleType *r)
void WinDrawWindowFrame (void)
void WinEraseWindow (void)
WinHandle WinSaveBits (const RectangleType *source, UInt16 *error)
void WinRestoreBits (WinHandle winHandle, Coord destX, Coord destY)
void WinCopyRectangle (WinHandle srcWin, WinHandle dstWin,
                       const RectangleType *srcRect, Coord destX,
                       Coord destY, WinDrawOperation mode)
void WinScrollRectangle (const RectangleType *rP,
                         WinDirectionType direction,
                         Coord distance, RectangleType *vacatedP)
void WinGetDisplayExtent (Coord *extentX, Coord *extentY)
void WinGetDrawWindowBounds (RectangleType *rP)
void WinGetBounds (WinHandle winH, RectangleType *rP)
void WinSetBounds (WinHandle winHandle, const RectangleType *rP)
void WinGetWindowExtent (Coord *extentX, Coord *extentY)
void WinDisplayToWindowPt (Coord *extentX, Coord *extentY)
void WinWindowToDisplayPt (Coord *extentX, Coord *extentY)
void WinGetClip (RectangleType *rP)
void WinSetClip (const RectangleType *rP)
void WinResetClip (void)
void WinClipRectangle (RectangleType *rP)

This is yet a shortened list of calls, but it gives you a general picture of your opportunities. The next sections describe how to work with Window Manager in more detail.

Working with Windows

The usual scenario, which you will implement in your application, can be as with the following:

  • Create an offscreen window, which will keep all of the drawing
  • Get and store the current Draw Window handle
  • Proceed with the required operations for display—draw, copy, or scroll
  • Restore the original Draw Window

You can start with offscreen window creation. The offscreen window is a logical structure that enables you to prepare all necessary blocks of the display contents and then actually show them on the physical screen. This window can be bigger or smaller than the full screen. Such a concept is tightly connected to the meaning of device context in MS Windows. The following code creates an offscreen window:

static WinHandle gOffscreenWinH = 0;
...
static Err AppStart(void)
{
   Err error;
   gOffscreenWinH =
      WinCreateOffscreenWindow(g_nWidth,g_nHeight, nativeFormat,
                               &error);
   return errNone;
}

I'd like to point to the third parameter of this function (of the WindowFormatType type). It defines a behavior of created windows in terms of screen features, such as screen depth, density, and pixel format. You can choose from the following:

  • screenFormat—bitmaps will be of low density, accept pen input
  • genericFormat—the same as screenFormat, but does not accept pen input
  • nativeFormat—uses actual hardware screen formats; apps must use graphic APIs to draw

Once you've created the offscreen window, you can draw on it. At any moment, there is only one window in the system that is active. Here, you're approaching the next cluster of functions:

WinHandle WinSetDrawWindow (WinHandle winHandle)
WinHandle WinGetDrawWindow (void)
WinHandle WinGetActiveWindow (void)

Window Manager lets you get either the active or draw window on demand. Besides, common and apt practice is to set the draw window before you do something, and restore original one at the end:

static void DrawBitmap(WinHandle winHandle, Int16 resID, Int16 x,
                       Int16 y)
{
   MemHandle   resH;
   BitmapPtr   resP;
   WinHandle   currDrawWindow;

   if (winHandle)
      currDrawWindow = WinSetDrawWindow(winHandle);

   resH = DmGetResource(bitmapRsc, resID);
   ErrFatalDisplayIf(! resH, "no bitmap found");
   resP = (BitmapPtr)MemHandleLock(resH);
   WinDrawBitmap (resP, x, y);
   MemPtrUnlock(resP);
   DmReleaseResource(resH);

   if (winHandle)
      WinSetDrawWindow(currDrawWindow);
}

Now, consider a couple other helpful functions:

WinHandle WinSaveBits (const RectangleType *source, UInt16 *error)
void WinRestoreBits (WinHandle winHandle, Coord destX, Coord destY)

The first one creates an offscreen window and copies a given region into it. The second one puts the contents of the passed window into the current draw window and then removes the given window. When will it be required? Suppose you want to display a "Please wait" message while processing some lengthly operation. There is no need to use any resource for such a lightweight task. All you need to do is to draw an appropriate string and frame:

...
   Err error;
   FontID font = stdFont;
   FrameType frame = rectangleFrame;
   const Char* pszLine = "Please wait";
   RectangleType rcLocation;
   UInt32 nScreenX, nScreenY;
   Coord nMessageWidth = 0;
   Int16 wLineLength;

   error = WinScreenMode(winScreenModeGet,&nScreenX, &nScreenY,
                         NULL, NULL);

   rcLocation.topLeft.x = 0;
   rcLocation.topLeft.y = 0;
   rcLocation.extent.x  = (Coord)nScreenX;
   rcLocation.extent.y  = (Coord)nScreenY;

   wLineLength = (Int16)StrLen(pszLine);
   nMessageWidth = FntCharsWidth(pszLine, wLineLength);

     Coord nLineHeight = FntLineHeight();
   nMessageWidth += nLineHeight * 2;

   RectangleType rcMessageBounds;
   rcMessageBounds.topLeft.x = rcLocation.topLeft.x
                             + (rcLocation.extent.x - nMessageWidth) / 2;
   rcMessageBounds.topLeft.y = rcLocation.topLeft.y
                             + (rcLocation.extent.y - nLineHeight) / 2;
   rcMessageBounds.extent.x = nMessageWidth;
   rcMessageBounds.extent.y = nLineHeight;

   RectangleType rcSavedBounds;
   WinGetFramesRectangle(frame, &rcMessageBounds, &rcSavedBounds);

   // First, save the display area
      WinHandle hwndSavedBits = WinSaveBits(&rcSavedBounds, &error);
   if (hwndSavedBits != NULL)
   {
      FontID fntOld = FntSetFont(font);

      WinEraseRectangle(&rcMessageBounds, 0);
      WinDrawRectangleFrame(frame, &rcMessageBounds);

      Coord nTopPos = rcMessageBounds.topLeft.y + nLineHeight / 2;
      Coord nLeftPos = rcMessageBounds.topLeft.x
                     + (nMessageWidth - nLineWidth) / 2;
      WinDrawChars(pszLine, wLineLength, nLeftPos, nTopPos);

      FntSetFont(fntOld);
   ................................................

      // and finally, restore the screen
      WinRestoreBits(hwndSavedBits, rcSavedBounds.topLeft.x,
                     rcSavedBounds.topLeft.y);
   }

As a result, a framed "Please wait" message is displayed on the screen.

Let me mention several points in the above code snippet. First, take a look at how message bounds are calculated. The sample code takes the screen boundaries as default values. Then, after a call to FntCharsWidth, the snippet gets the actual string width in pixels, based on the currently selected font. And finally, the application requests a frame to be temporarily stored (WinGetFramesRectangle). A pair of WinSave/RestoreBits completes the game.

I'm leaving quite a lot of various functions to manage shapes, rectangles, bitmaps, and colors untouched. The Window.h header file will guide you through all the rich APIs that Palm OS offers.

Finally, I'd like to say a few words regarding font management. Palm OS has about two dozen functions to manage fonts. They all are declared in the Font.h file. You definitely won't use them all, but several helpful ones are listed below:

FontID FntGetFont (void)
FontID FntSetFont (FontID font)
Int16 FntCharHeight (void)
Int16 FntLineHeight (void)
Int16 FntCharsWidth (Char const *chars, Int16 len)
void FntCharsInWidth (Char const *string,
                      Int16 *stringWidthP, Int16 *stringLengthP,
                      Boolean *fitWithinWidth)
Int16 FntLineWidth (Char const *pChars, UInt16 length)
UInt16 FntWordWrap (Char const *chars, UInt16 maxWidth)
void FntWordWrapReverseNLines (Char const *const chars,
                               UInt16 maxWidth, UInt16 *linesToScrollP,
                               UInt16 *scrollPosP)

These functions allow you to get or set the current font, retrieve information about font height, determine boundaries of given text, and so forth. Some examples of their usage were presented above. Actually, there is nothing much to duscuss here; just refer to the SDK documentation.

Conclusion

I hope this article gave you an initial picture of Palm OS Window Management. It's not as complicated as it might seem, but does require some effort from you to develop all the functionality you want to be implemented. In other words, it is worth your verification.

About the Author

Alex Gusev started to play with mainframes at the end of the 1980s, using Pascal and REXX, but soon switched to C/C++ and Java on different platforms. When mobile PDAs seriously rose their heads in the IT market, Alex did it too. Now, he works at an international retail software company as a team leader of the Mobile R department, making programmers' lives in the mobile jungles a little bit simpler.

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date