-->

Programando para Palm OS usando Linux

Tutoriais ruins, dificuldade em se configurar um ambiente de desenvolvimento decente, códigos não compatíveis entre ferramentas diferentes… enfim, se você usa Linux e quer começar a criar aplicações para Palm OS, saiba que, até onde eu sei, o caminho não é muito fácil.

Por isso mesmo resolvi criar esse artigo. Espero que ele se torne um bom ponto de partida para você.

O que vamos desenvolver

Se você não sabe, antigamente, lá pelas alturas da era Mesozóica, a Palm produzia aparelhos equipados com processador Motorola68k (m68k, DragonBall, etc). Atualmente ela faz aparelhos equipados com processadores ARM. Se você é programador (e se não é: você está fazendo o que aqui? Vá aprender a programar “normalmente” antes de ler esse artigo!), deve estar com as palavras “incompatibilidade binária” na cabeça.

Bom, pra encurtar a história, a Palm botou no Palm OS um emulador/simulador/máquina virtual/enganador/interpretador de binários m68k. Sacou? Por isso as aplicações jurássicas ainda conseguem rodar em Palms novos.

E o que isso tem a ver conosco? Bom, tem a ver que eu vou mostrar, nesse artigo, como programar para m68k. Isso não é nenhum grande problema. Isso ainda é bem rápido, não se preocupe, e roda em qualquer Palm, desde os antigões até os mais novos.

Parte ruim: seria muito mais legal compilar direto para ARM.

Parte boa: você pode usar o POSE ou o xcopilot para emular o Palm. Isso facilita muito nossa vida!

Como se constrói um programa para Palm OS

Papel e caneta

Já de cara, você pega uma folha de papel e vai desenhando e escrevendo. Teu programa vai servir pra quê? Já não existe algum que faça o mesmo? Se existe, o dito cujo é GPL? Você vai distribuir? Se vai, sob que licença fará isso? Será necessário suporte a outras línguas?

Assim que responder essas perguntas, você já pode começar a desenhar as telas. Acredite, se você pular esse passo, terá o triplo de trabalho na hora de botar a mão na massa pra valer! Então, desenhe!

Resources

O primeiro passo, assim que você já sabe a cara do programa é desenhar a interface. “Desenhar” é modo de dizer. Não conheço nenhuma ferramenta gráfica que faça isso (não para Linux). Você escreverá a interface num editor de texto.

A relação entre interface e programação, nesse caso, é bem como a relação entre HTML e JavaScript, sabe? Primeiro você faz a “cara” da página, e depois bota funcionalidade.

Os arquivos com a interface, em geral, ganham o sufixo .rcp. Olha um exemplo, pra você ter uma idéia:

#include "interface.h"

FORM ID id_MainForm AT (2 2 156 156)
USABLE
FRAME
MODAL
HELPID id_Help
MENUID id_MainMenu
BEGIN
TITLE "Hello-World do Cléber"
END

MENU ID id_MainMenu
BEGIN
PULLDOWN "Opções"
BEGIN
MENUITEM "Sobre..." ID id_MenuItem_About "a"
END
END

STRING ID id_Help  "Hello world"

ALERT ID id_About
INFORMATION
BEGIN
TITLE "Sobre o Hello world"
MESSAGE  " Hello To the World "
BUTTONS "Done"
END

Olhando assim dá pra ver que é bem simples. É um arquivo cheio de BEGINs e ENDs e tal. Bem susse de sacar como é que se faz. No fim do artigo tem uns links com exemplos e explicações de cada tipo de resource (botões, caixas de texto, listas, etc).

pilrc

Esse é o cara que compila os arquivo de resources. Basicamente:

pilrc interface.rcp

Aí ele gera um monte de arquivinhos intermediários. Existe uma ferramenta chamada pilrcui, que mostra como ficou a interface.

Programação

Volte pro arquivo de resources e preste atenção em duas coisas: no include do início e nos nomes que começam com “id_”.

A programação para Palm OS é do tipo baseada em eventos. Aquele include é um arquivo cheio de defines, tipo:

#define id_About     1000
#define id_Help      1001
#define id_MainMenu  1002
#define id_MainForm  1003
#define AboutForm    1004
#define MainForm     1005
#define id_MenuItem_About 1006

Daí, lá no arquivo C, você fica tratando eventos e outras coisas pelo ID do resource. Os defines são, óbviamente, para facilitar tua vida, mas não são obrigatórios.

Bom, já que meu “hello world” é o exemplo, vou mandar o código para você ver:

#include <PalmOS.h>
#include "interface.h"

/***********************************************************************
*
* Internal Constants
*
***********************************************************************/
#define appFileCreator "HELO" // register your own at http://www.palmos.com/dev/creatorid/
#define appVersionNum 0x01
#define appPrefID 0x00
#define appPrefVersionNum 0x01

/***********************************************************************
*
* Internal Functions
*
***********************************************************************/

/***********************************************************************
* FUNCTION: MainFormDoCommand
* DESCRIPTION: This routine performs the menu command specified.
* PARAMETERS: command - menu item id
* RETURNED: nothing
***********************************************************************/
static Boolean MainFormDoCommand(UInt16 command)
{
Boolean handled = false;
FormType * pForm;

switch (command)
{
case id_MenuItem_About:
//		pForm = FrmInitForm(id_About);
//		FrmDoDialog(pForm); // Display the About Box.
//		FrmDeleteForm(pForm);

FrmCustomAlert(id_About, NULL, NULL, NULL);
handled = true;
break;
}

return handled;
}

/***********************************************************************
*
* FUNCTION: MainFormHandleEvent
* DESCRIPTION: This routine is the event handler for the
* "MainForm" of this application.
* PARAMETERS: pEvent - a pointer to an EventType structure
* RETURNED: true if the event has handle and should not be passed
* to a higher level handler.
*
***********************************************************************/
static Boolean MainFormHandleEvent(EventType* pEvent)
{
FormType* pForm;

switch (pEvent->eType)
{
case menuEvent:
return MainFormDoCommand(pEvent->data.menu.itemID);

case frmOpenEvent:
pForm = FrmGetActiveForm();
FrmDrawForm(pForm);
return true;
}

return false;
}

/***********************************************************************
*
* FUNCTION: AppHandleEvent
* DESCRIPTION: This routine loads form resources and set the event
* handler for the form loaded.
* PARAMETERS: event - a pointer to an EventType structure
* RETURNED: true if the event has handle and should not be passed
* to a higher level handler.
*
***********************************************************************/
static Boolean AppHandleEvent(EventType* pEvent)
{
UInt16 formId;
FormType* pForm;
Boolean handled = false;

if (pEvent->eType == frmLoadEvent)
{
// Load the form resource.
formId = pEvent->data.frmLoad.formID;

pForm = FrmInitForm(formId);
FrmSetActiveForm(pForm);

// Set the event handler for the form. The handler of the currently
// active form is called by FrmHandleEvent each time is receives an
// event.
switch (formId)
{
case id_MainForm:
FrmSetEventHandler(pForm, MainFormHandleEvent);
break;

default:
break;
}
handled = true;
}

return handled;
}

/***********************************************************************
*
* FUNCTION: AppStart
* DESCRIPTION: Get the current application"s preferences.
* PARAMETERS: nothing
* RETURNED: Err value errNone if nothing went wrong
*
***********************************************************************/
static Err AppStart(void)
{
FrmGotoForm(id_MainForm);
return errNone;
}

/***********************************************************************
*
* FUNCTION: AppStop
* DESCRIPTION: Save the current state of the application.
* PARAMETERS: nothing
* RETURNED: nothing
*
***********************************************************************/
static void AppStop(void)
{
// Close all the open forms.
FrmCloseAllForms();
}

/***********************************************************************
*
* FUNCTION: AppEventLoop
* DESCRIPTION: This routine is the event loop for the application.
* PARAMETERS: nothing
* RETURNED: nothing
*
***********************************************************************/
static void AppEventLoop(void)
{
Err error;
EventType event;

do
{
EvtGetEvent(&event, evtWaitForever);

if (SysHandleEvent(&event))
continue;

if (MenuHandleEvent(0, &event, &error))
continue;

if (AppHandleEvent(&event))
continue;

FrmDispatchEvent(&event);

}
while (event.eType != appStopEvent);
}

/***********************************************************************
*
* FUNCTION: PilotMain
* DESCRIPTION: This is the main entry point for the application.
* PARAMETERS: cmd - word value specifying the launch code.
* cmdPB - pointer to a structure that is associated with the launch code.
* launchFlags - word value providing extra information about the launch.
* RETURNED: Result of launch
*
***********************************************************************/
UInt32 PilotMain(UInt16 cmd, MemPtr cmdPBP, UInt16 launchFlags)
{
Err error = errNone;

switch (cmd)
{
case sysAppLaunchCmdNormalLaunch:
if ((error = AppStart()) == 0)
{
AppEventLoop();
AppStop();
}
break;

default:
break;
}

return error;
}

Leia todo o exemplo com atenção, só pra sacar como os eventos são tratados.

GCC

 m68k-palmos-gcc hello.c

Isso gerará, simplesmente, o a.out. Atenção: esse não é o executável. Pare para pensar: o GCC gera um binário, mas não é tão esperto pra deixá-lo prontinho para rodar num sistema tão bizarro quanto o Palm OS. Vou mostrar o Makefile pra você ver:

All:
pilrc interface.rcp
m68k-palmos-gcc hello.c
m68k-palmos-obj-res a.out
build-prc hello.prc hello-world *.grc *.bin

clean:
rm *.bin
rm *.grc
rm a.out

POSE

Palm OS Emulator. Cara, não vou escrever aqui, agora, como fazer pra deixar ele redondo. Você é programador! Tenho certeza que vai se virar…

O POSE serve pra você testar tua aplicação. É muito bom, pois evita ter que ficar gravando/testanto/[reiniciando]/apagando/alterando/gravando/testando…

.

.

.

.

Puxa, ninguém nunca tinha dito isso assim, tão claro pra mim. Os tutoriais ensinam como configurar o ambiente para você programar, mas não dão esses macetes assim, em ordem e de forma concisa.

Macetes

Bibliotecas

Veja o hello.c novamente. Viu que eu só inclui uma biblioteca do Palm, mesmo (PalmOS.h)? Quando você correr atrás de exemplos, essa será uma das diferenças. Em geral, os arquivos C incluem um monte de coisas. Talvez funcione com os outros, mas comigo nunca dava certo… todos os programas que eu escrevi até agora (não foram muitos) eu escrevi desse jeito, sem incluir mais nada.

Se você vir alguém incluindo, por exemplo, o Pilot.h e mais coisas, e isso der pau, experimente trocar toda essa tralha pelo bom e velho “<PalmOS.h>”.

Tipos

Tem gente que usa coisas como Word, DWord, Ptr, etc. Pra mim nunca funcionou. Eu uso UInt32 (DWord/double word), UInt16 (Word) e MemPtr (no lugar de Ptr).

Links

Ambiente

Esses caras ensinam você a configurar tua máquina para começar a programar. Em breve vou criar meu próprio tutorial, ensinando a fazer isso no Slackware (do jeito que funcionou para mim).

http://www.shallowsky.com/linux/palmlinuxdev.html - Bem velho, meio estranho, mas bem escrito. Isso pode te ajudar.

http://www.elf.org/pilot/develop.html - não gostei muito.

http://www.isaac.cs.berkeley.edu/palmdevel/ - esse aqui é pra quem gosta de compilar coisas (cara, eu sou programador, mas compilar o GCC é um saco!).

Tutoriais como esse aqui

http://www.linuxjournal.com/article/3782

http://www.wirelessdevnet.com/channels/pda/training/palmdevelopment.html - não é voltado especialmente para Linux, mas pode ser útil.

http://www.ericgiguere.com/books/palm/palm-database-programming/chapter-3-gcc.html;jsessionid=A002A03E65C9497617F1C0EAE7D3370A - bom!

http://tangentsoft.net/palmfaq/articles/tutorial/ - bem legal pra uma segunda aplicação (depois do “hello world”)

Resources

http://www.mit.jyu.fi/mweber/teaching/docs/palmos/pilrc/doc/pilrc.htm - Manual do pilrc, com a definição e exemplos dos resources - ótimo.

http://64.233.169.104/search?q=cache:poz4aINtyPcJ:stuff.mit.edu/afs/sipb/project/pilot/doc/TutorialWin.pdf+palm+resource+%22gadget+id%22&hl=pt-PT&ct=clnk&cd=2&client=firefox-a#221 - é do CodeWarrior, solução proprietária para Windows e MacOS, mas tem a documentação de vários resources.

Programação

http://www.netmeister.org/palm/Example/PalmExample.html - Um programinha mais complexo. Bem bom.

http://www.access-company.com/developers/documents/docs/palmos/PalmOSReference/ReferenceTOC.html - referência oficial da API - obrigatório.

http://mobile.eric-poncet.com/palm/tutorial/ - excelente. Tem coisas para iniciantes, médios e avançados.

Bom, espero que isso tenha sido útil. Fique de olho, pois um dia eu vou escrever mais. Se você ler os links, tiver dúvidas, fuçar no Google e depois de um mês continuar com dúvidas, não exite em perguntar (só, por favor, tente se virar sozinho antes, ok? Esse é um bom hábito).

Leave a Reply