Thursday, August 23, 2007

Improving Code Completion in V9

The CodeWarior tools are developed by several different groups. While I'm responsible for the Palm OS tools, I rely on technology from other teams, most notably the IDE team. Earlier in 2002, they shipped IDE 4.3, our first IDE with true code completion. This was implemented only for Java at the time, but they worked hard over the next few months to get the same thing working for C and C++. They mostly succeeded, but their implementation had some problems that caused it to fail for many cases. In their continuing work on IDE 5, they've been improving it, but there are still some quirks of which you need to be aware in order to use this feature well.

How Does Code Completion Work?
Code completion has two parts: symbol acquisition and context discovery. Symbol acquisition is the process by which entries are put into the IDE's symbol browser database. You can see most of this database using the View/Browser Contents command.


The "Build Extras" panel of your project controls how this database is built. There are two options: compiler or code parser. The compiler method is the same one used in previous versions of CodeWarrior. With this, the compiler reports back to the IDE about the functions it compiled and the the macros and typedefs it saw. This data isn't very detailed, since it doesn't include prototypes for funtions that weren't also compiled, and it also doesn't include argument information for functions or macros. This data also requires that your code compile to be created. The IDE supports merging data from several projects -- if you link your project to another project and setup a dependency relationship, then the compiled browser data from that project will be imported into your own. This is how we setup browse info for precompiled headers in the past. See my article
Palm OS Precompiled Headers for details.

The other option on the Build Extras panel is "Code Parser". This is usually the preferred option. When you pick this, the IDE uses its own C/C++ parser to read through all your source files, picking up information straight from your source and headers. This usually works, but there are some tweaks that have to be made for this step to succeed.

First, you need sane values for the Prefix File and Macro File settings. The prefix file setting should match your prefix setting in the C/C++ Compiler panel, but with one exception. If you're directly using a precompiled header as a prefix, you need to mention the file that generates that PCH here instead. Our default for Palm OS projects is "PalmOS.win.pch", the header that builds the PalmOS_Header precompiled header file.
The Macro File setting is very important for completion using the Palm OS headers. Normally, the code parser doesn't try to expand macros it sees in the source or header files. However, if you have macros that affect how the code is parsed, you need to specify them in a separate source file and mention it here. The Palm OS headers are full of these kind of macros, since all of the Palm OS API functions use them to define how they are called. We have provided a good default file, PalmOSMacros.h, which lives in the "CW for Palm OS Support" folder. You need a "\{Compiler\}CW for Palm OS Support" system access path in your project to see this file. Without this, the parser will get very confused with the Palm OS headers and just give up on them, which means you won't get completions for the Palm OS API calls.


OK, so if all this is working, then shortly after opening your project, you should see all the symbols turn pretty colors and a big database of items in the View/Browser Contents dialog. Now, we come to context discovery.
Even when you're using the compiler to gather symbols, you're also using the code parser to let the IDE know where you are in your source file. The IDE uses this information to provide itself with context about what symbols could be completed at the cursor location. If you look at the "Editor/Code Completion" settings in the IDE's preferences dialog, you'll see settings that control when it pops up a completion box. If the IDE isn't providing help on its own, you can manually bring up help using the alt-period key. This keystroke can be changed by altering the key binding of the "Edit/Complete Code" command. The completion window provides both symbol names, and also type information.


Why Doesn't This Work?
Here are two reasons:
1) The code parser has bugs that make it give up on some source files. One bug that made it into the IDE build that we shipped on V9 involved the binary and operator. The parser sometimes dies when it sees it, since its parsing it as a address-of operator and getting confused. This IDE also doesn't parse macros that have a space between the macro name and the argument list. Both of these bugs have been fixed for the 9.1 patch.
2) The PalmOSMacros.h file is incomplete. I built this file based on the Palm OS 4 SDK headers, and I missed some macros that are used in the Palm OS 5 SDK. A new version of this file is coming in the 9.1 patch.


Source :http://www.palmoswerks.com/stories/storyReader$124

Monday, August 20, 2007

How to programmatically open the find dialog

To programatically open the find dialog, you need to add a key down event to the eventqueue using the EvtAddEventToQueue function. Here is a code example for adding an eventto the queue:

/* Emulate a keydown event */
static void AddKeyDownEvent(WChar character)
{
EventType theEvent;
MemSet(&theEvent, sizeof(EventType), 0);

/* Create the key down event */
theEvent.eType = keyDownEvent;
theEvent.data.keyDown.chr = character;
theEvent.data.keyDown.keyCode = 0;
theEvent.data.keyDown.modifiers = commandKeyMask;

/* Add the event to the event queue */
EvtAddEventToQueue(&theEvent);
}
In this case, pass in a character code of vchrFind Some other possible values that youmay find useful for the character argument are:


vchrMenu - Shows the menu bar
VchrCommand - Simulate a command stroke
vchrLaunch - Opens the launcher
vchrCalc - Opens the calculator
VchrRonamatic - Simulates a stroke from the graffiti writing area to the top of the screenvchrGraffitiReference - Opens the graffiti reference
dialogvchrLock - Locks and powers off the unit
vchrBacklight - Toggles the state of the backlight

For a complete listing see Chars.h.

Overriding the silk screen buttons

In the main event loop, scan for the keyDown event before SysHandleEventgets to process it. If the character is vchrFind, you skip the rest of the event loop, effectively ignoring the find button.
For example:

static void EventLoop()
{ Err error; EventType event;
do

{
EvtGetEvent(&event, evtWaitForever);
// Eat all find key events

if (event.eType == keyDownEvent && event.data.keyDown.chr == vchrFind)
{
continue;
}
if (!SysHandleEvent(&event))

{
if (!MenuHandleEvent(0, &event, &error))
{
if (!ApplicationHandleEvent(&event))
{
FrmDispatchEvent(&event);
}
}
}
}while (event.eType != appStopEvent);
}

/***************************************OR*****************************************************/

PenBtnInfoPtr btnInfo;
UInt16 numButtons;

btnInfo = (const PenBtnInfoPtr)EvtGetPenBtnList(&numButtons); //Get the list of silk screen buttons.

for(int i =0; i
{
if((pEvent->data.keyDown.chr)==btnInfo[i].asciiCode)
{
FrmCustomAlert(GenericErrorAlert,"Silk Screen button selected","","");
return true;
}
}

Launching Application From SD Card

err=VFSImportDatabaseFromFile (VolRef, lapp, &card, &locid);

DmDatabaseInfo (card, locid, NULL, &attr, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
attr=dmHdrAttrRecyclable;
DmSetDatabaseInfo (card, locid, NULL, &attr, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);

SysUIAppSwitch (card, locid, sysAppLaunchCmdNormalLaunch, cmdPBP);

This code copies database from memory card to main memory, sets it's attribute to 'delete it automatically after closing' and then runs it in main memory.
This works fine with one exception: if reset occurs during running this app, it remains in main memory. But I think that it happens even in case of standard launcher running app from card.

How to power off programmatically

Add the vchrPowerOff keyDownEvent to the queue
/***********************************************************************************/
static void Uti_PowerOff(void)
{
EventType event;
MemSet(&event,sizeof(event),0);
event.eType = keyDownEvent;
event.data.keyDown.chr = vchrPowerOff; event.data.keyDown.keyCode = 0;
event.data.keyDown.modifiers = commandKeyMask;
EvtAddEventToQueue(&event);
}

How to know if the palm is powering on or is going to sleep

Register for some notification and handle them as followsUnregister with SysNotifyUnregister() when no more neededYou can use a Feature (see How to store a permanent value... ) to store the program start time

/*********************************************************************************************/
static void RegisterForNotifications()
{
UInt16 cardNo=0;
UInt32 romVersion=0;
LocalID dbID=0;
FtrGet(sysFtrCreator, sysFtrNumROMVersion, &romVersion);
if(romVersion <>
return;
if(SysCurAppDatabase(&cardNo, &dbID)!=0)
return;
// Register the Notification you need
SysNotifyRegister(cardNo, dbID, sysNotifyEarlyWakeupEvent, NULL, sysNotifyNormalPriority, 0);
SysNotifyRegister(cardNo, dbID, sysNotifyLateWakeupEvent, NULL, sysNotifyNormalPriority, 0);
SysNotifyRegister(cardNo, dbID, sysNotifySleepRequestEvent, NULL, sysNotifyNormalPriority, 0);
}
/****************************************************************************************/

static void HandleNotifications(SysNotifyParamType *np)
{
if(np->notifyType==sysNotifyEarlyWakeupEvent)
{
// Do something
}
else if(np->notifyType==sysNotifyLateWakeupEvent)
{
// Do something
}
else if(np->notifyType==sysNotifySleepRequestEvent)
{
// Do something
}
}

/***************************************************************************************/

UInt32 PilotMain(UInt16 cmd,void *cmdPBP,UInt16 launchFlags)
{
switch(cmd)
{
case sysAppLaunchCmdSystemReset:
case sysAppLaunchCmdSyncNotify:
RegisterForNotifications();
break;
case sysAppLaunchCmdNotify:

case sysNotifySleepRequestEvent:
HandleNotifications((SysNotifyParamType *)cmdPBP);
break;
case sysAppLaunchCmdNormalLaunch:

... Normal code ...

}

Friday, August 17, 2007

How to exit from the application

/*Returns to launcher*/

static void Uti_Exit(void)
{
EventType event;
MemSet(&event,sizeof(event),0);
event.eType = keyDownEvent;
event.data.keyDown.chr = vchrLaunch;event.data.keyDown.modifiers = commandKeyMask;
EvtAddEventToQueue(&event);
}

/* Returns to the previous application*/

static void Uti_Exit(void)
{
EventType event;
MemSet(&event,sizeof(event),0);
event.eType = appStopEvent;
EvtAddEventToQueue(&event);
}