A Walk through the Plug-in Development Kit, Part 2

5 BY unwiredben

This is going to be a pretty long post, so I’m hiding most of it from the main page.  However, I want to get people to click on the article, so here’s the pretty picture that we’re using for our fake game studio logo, created using my elite Inkscape skills.

What’s our goal with part 2?  By the end of this post, you’ll have a PDK application that shows a picture then waits for the user to quit.  In theory, this will give the user something to look at while we process all the data needed for our super hot game.

Oh, and one last thing “before the cut”.  I apologize to our PDK developers using Mac OS X or Linux.  I’m doing my development using Windows and haven’t been able to test on the other platforms.  It should be simple to follow along, and I encourage you to post corrections and tips in the comments.

Setting Up the Project

To get started, you need to install the PDK from our developer site.  This may take a while; the PalmPDK.exe installer is about 20MB large and it pulls down a separate 128MB CodeSourcery G++ Lite installer when it starts up.  Try to find a fast network connection and take this time to post some funny stories to the Off-Topic Developer Lounge.

We’ll start by stealing the current “simple” project sample so we can reuse some of the pieces that are there. The PDK installer puts it in “C:\Program Files\Palm\PDK\share\samplecode\simple”, so I’ll copy that whole directory to C:\badfont, then start editing the files to customize them.

Building The Code

In a large project with many source files, you’d want to use make or some other build utility, but for this one-file sample, the simple buildit script will work OK.  Here’s what it looks like after some edits to make it work for this code:

@echo off
@rem Set the device you want to build for to 1
set PRE=0
set PIXI=1
set DEBUG=0

@rem List your source files here
set SRC=badfont.cpp

@rem List the libraries needed
set LIBS=-lSDL -lpdl

@rem Name your output executable
set OUTFILE=badfont

if %PRE% equ 0 if %PIXI% equ 0 goto :END

if %DEBUG% equ 1 (
 set DEVICEOPTS=-g
) else (
 set DEVICEOPTS=
)

if %PRE% equ 1 (
 set DEVICEOPTS=%DEVICEOPTS% -mcpu=cortex-a8 -mfpu=neon -mfloat-abi=softfp
)

if %PIXI% equ 1 (
 set DEVICEOPTS=%DEVICEOPTS% -mcpu=arm1136jf-s -mfpu=vfp -mfloat-abi=softfp
)

echo %DEVICEOPTS%

arm-none-linux-gnueabi-gcc %DEVICEOPTS% -o %OUTFILE% %SRC% ^
  "-I%PALMPDK%\include" "-I%PALMPDK%\include\SDL" "-L%PALMPDK%\device\lib" ^
  -Wl,--allow-shlib-undefined %LIBS%

goto :EOF

:END
echo Please select the target device by editing the PRE/PIXI variable in this file.
exit /b 1

We made a few edits here: first, we changed PRE to 0 and PIXI to 1 to make sure the code works on all devices. We edited LIBS to remove the -lGLESv2 and add -lpdl as we’re not using OpenGL but we do call some PDL functions.  We changed SRC=simple.cpp to instead say SRC=badfont.cpp, and similarly edited OUTFILE to say “badfont”.

While we’re editing buildit.cmd, we also should edit the other scripts.  uploadit.cmd needs to have “simple” replaced with “badfont” in both the plink and pscp lines, and we need to add logo.png to the pscp line to make sure we copy over our graphics file.  runit.cmd and debugit.cmd also need “simple” changed to “badfont” too.

Application Initialization

Now we get to some code.  We can remove the old simple.cpp file and just start a new file called badfont.cpp that will have the source for our application.  Borrowing some inspiration from the Arduino world, our main() function will just do two things:

int main()
{
    setup();
    display();
    while (1)
        loop();
}

The setup() code will deal with everything we need to do to get the app running.  Here’s the code

static void setup()
{
    SDL_Init(SDL_INIT_VIDEO);
    atexit(SDL_Quit);

    PDL_Init(0);
    atexit(PDL_Quit);

    PDL_Err err;
    char appPath[256];
    err = PDL_GetCallingPath(appPath, sizeof(appPath));
    if (err) exit(1);
    chdir(appPath);

    gScreen = SDL_SetVideoMode(0, 0, 0, 0);

    SDL_Surface *logoImage = IMG_Load("logo.png");
    if (!logoImage) exit(1);
    gLogo = SDL_DisplayFormat(logoImage);
    if (!gLogo) exit(1);
    SDL_FreeSurface(logoImage);
    atexit(freeLogo);
}

This code initializes the SDL library using a call to SDL_Init() noting that we want to use the video subsystem to show graphics on the screen.  This SDL_INIT_VIDEO flag is also needed to get the connection to WebKit going for plug-ins to allow JavaScript code to call into the PDK, so you always want to specify it.  We use the C library call atexit() here to register a shutdown handler so the app will call SDL_Quit() at exit.  You also could just have that in your own exit code, but this is a nice way to make sure it will get called no matter where we call exit().

We then setup the PDL library.  We’re not actually using any PDL calls in this example, but it’s a good idea to always have it around.  You have to call PDL_Init() after calling SDL_Init() on startup, and the reverse it true on shutdown; you call PDL_Quit() before calling SDL_Quit().  We do that by another call to atexit(); all the handlers are called in the last in-first out policy.

We now make our sole call into the PDK library with PDL_GetCallingPath().  When the launcher starts our application, it’s not guaranteed that we’ll start with the application folder as the current directory.  Since it’s nice to use relative paths to access our resources, we’ll adjust the current directory using chdir() before we try to access any files.

The next call to SDL_SetVideoMode() is needed to actually give us a surface on which to draw.  Since we want to run on both the Pre and the Pixi, we use all zeros.  That’s a hint to SDL that we want a full screen surface with the color properties of the screen.  We’ll pull the size out of this structure later when we display the bitmap

The final thing we do in setup is load our logo bitmap.  In a real app, we could load that while we’re showing the logo screen then release it later.  We’re using the SDL_image library because it supports loading PNG and JPEG files; the core SDL library only supports loading BMP files.  In order to speed up bitmap blitting, we do an immediate conversion to screen format using SDL_DisplayFormat() after loading so we don’t pay for conversion every time we draw the bitmap.

Drawing the Screen

Our display() routine is called in two places, first after setup to do the initial drawing of the screen, and then again when we get a SDL_VIDEOEXPOSE event to redraw the screen when asked by the OS.

static void display()
{
    int black = SDL_MapRGB(gScreen->format, 0, 0, 0);
    SDL_Rect screenRect = { 0, 0, gScreen->w, gScreen->h };
    SDL_FillRect(gScreen, &screenRect, black);

    SDL_Rect logoDestRect;
    logoDestRect.x = (gScreen->w - gLogo->w) / 2;
    logoDestRect.y = (gScreen->h - gLogo->h) / 2;
    logoDestRect.w = gLogo->w;
    logoDestRect.h = gLogo->h;
    SDL_BlitSurface(gLogo, NULL, gScreen, &logoDestRect);

    SDL_Flip(gScreen);
}

We do three things here.  First, we fill the whole surface with black using SDL_FillRect().  This gives us a blank page to draw on.  Then, we figure out the center position for the logo bitmap and draw it to the surface using SDL_BlitSurface().  Finally, we call SDL_Flip() to tell the system that our drawing is done and that it can update the screen.

Handling Events

Finally, we come to the code that gets called over-and-over in loop().  Since we’re not doing any real processing, we’ll use SDL_WaitEvent() to pause until some event arrives.  We really only care about two events: I’ve already mentioned SDL_VIDEOEXPOSE, but the big one is SDL_QUIT.  This is sent when the user flicks away the application’s card, and it means we only have a brief moment to shut everything down before our process is killed.

static void loop()
{
    SDL_Event event;
    if (SDL_WaitEvent(&event)) {
        if (event.type == SDL_QUIT)
            exit(0);
        else if (event.type == SDL_VIDEOEXPOSE)
            display();
   }
}

Downloading and Running the Code

You can download all the source files for part 2 from this link.  After unpacking the ZIP file, you should be able to open a command prompt, change to the BadFont directory, and type “runit” to build the app, upload it to your device, and test it out.  If all goes well, you’ll have a screen that looks like this (when the app is minimized):

(Unfortunately, we don’t support screen capture for full-screen PDK applications right now, so I had to use the minimize trick to get something to show.)

Next Time on the Blog

These scripts build and run the app on the device using SSH to copy files into /media/internal and run them.  This isn’t the usual way people get webOS apps, so next time, we’ll be covering packaging of your application into an IPK file using the pdk-package tool.  Plus, we’ll look at reading input via touches on the screen.

Comments (5)

  1. Tames McTigue says:

    This seems to build correctly, however I am unable to actually execute the app. It gives me “Permission denied” no matter what when it tries to execute. I even SSHed into it to check the permissions. Did I miss a step somewhere?

    • unwiredben says:

      Is this “Permission Denied” coming from the “runit.cmd” script or is it being generated on the device? The scripts upload to /media/internal which is a FAT partition, so everything there should have execute permission by default. However, if you’re trying to use the emulator, you might get that message as /media/internal is just part of it’s EXT3 filesystem. The bad news is that the emulator uses x86 instructions, so PDK-build code won’t run there at all as the PDK tools build for ARM.

  2. Harshapaul Pinto says:

    I got the following error when compiling this work in Visual Studio 2005.
    error LNK2019: unresolved external symbol _PDL_Init referenced in function “void __cdecl setup(void)” (?setup@@YAXXZ)

    I have set the directories in the tools options as also the dependencies in the input option of Linker.

    • unwiredben says:

      PDL_Init is defined in the libpdl.lib that comes with the PDK in “c:\Program Files\Palm\PDK/host\lib” Under the project properties in Linker/Input, make sure you’ve got “libpdl.lib” listed in “Additional Dependencies”

  3. Ryan Edwards says:

    This is great, thanks.

    In a future blog you think you could include how to render text on the screen (not an image with text, text, presumably using SDL_ttf) with other openGL ES artifacts, such as a triangle with the word “Hello” under it? That would be extremely helpful, as this was.