Main Page   Class Hierarchy   Compound List   File List   Compound Members   File Members

Starter.cpp

Go to the documentation of this file.
00001 /*********************************************************************************
00002  *
00003  * Razor! Engine - A modular C++ presentation engine
00004  *
00005  * $Id$
00006  *
00007  * Copyright (c) 2000 Tilo Christ. All Rights Reserved.
00008  *
00009  * This library is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 2.1 of the License, or (at your option) any later version.
00013  *
00014  * This library is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Lesser General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU Lesser General Public
00020  * License along with this library; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022  *
00023  **********************************************************************************/
00024 
00025 
00026 #include <PalmOS.h>
00027 #include "../Rsc/StarterRsc.h"
00028 
00029 #include "Device.h"
00030 #include "Presentation.h"
00031 #include "Customization.h"
00032 
00033 /**
00034  * @file Starter.cpp
00035  * The main application. This is the bare skeleton of a functional
00036  * PalmOS application. It delegates most of the work to a Presentation
00037  * object.
00038  */
00039 
00040 
00041 
00042 // ***********************************************************************
00043 
00044 static Presentation *presentation;
00045 
00046 // ***********************************************************************
00047 
00048 
00049 
00050 /**
00051  * Perform the specified menu command
00052  *
00053  * @param command menu item id
00054  *
00055  * @return true if the command has been handled
00056  */
00057 static Boolean MainFormDoCommand(UInt16 command)
00058 {
00059     Boolean handled = false;
00060 
00061     switch (command)
00062     {
00063         case MainOptionsAboutRazor:
00064             presentation->pause();
00065 
00066             MenuEraseStatus(0);                 // Clear the menu status from the display.
00067             FormType* frmP = FrmInitForm(AboutForm);
00068             FrmDoDialog (frmP);                 // Display the About Box.
00069             FrmDeleteForm (frmP);
00070             handled = true;
00071             
00072             presentation->resume();
00073         break;
00074     }
00075     
00076     return handled;
00077 }
00078 
00079 
00080 /**
00081  * The event handler for the "MainForm" of this application.
00082  * 
00083  * @param eventP a pointer to an EventType structure
00084  *
00085  * @return true if the event has been handled and should not be passed to a higher level handler.
00086  */
00087 static Boolean MainFormHandleEvent(EventType* eventP)
00088 {
00089     Boolean handled = false;
00090 
00091     switch (eventP->eType) 
00092     {
00093         case menuEvent:
00094             return MainFormDoCommand(eventP->data.menu.itemID);
00095 
00096         case frmOpenEvent:
00097             {   // This scope is required for PRC-Tools 2.0
00098                 FormType* frmP = FrmGetActiveForm();
00099                 FrmDrawForm (frmP);
00100             }
00101             // Begin the presentation
00102             presentation->begin();
00103 
00104             handled = true;         
00105             break;
00106 
00107         default:
00108             break;      
00109     }
00110     
00111     return handled;
00112 }
00113 
00114 
00115 
00116 
00117 /**
00118  * Load form resources and set the event handler for the form loaded.
00119  *
00120  * @param eventP a pointer to an EventType structure
00121  *
00122  * @return true if the event has been handled and should not be passed to a higher level handler.
00123  */
00124 static Boolean AppHandleEvent(EventType* eventP)
00125 {
00126     if (eventP->eType == frmLoadEvent)
00127     {
00128         // Load the form resource.
00129         UInt16 formId = eventP->data.frmLoad.formID;
00130         FormType* frmP = FrmInitForm(formId);
00131         FrmSetActiveForm(frmP);
00132 
00133         // Set the event handler for the form.  The handler of the currently
00134         // active form is called by FrmHandleEvent each time is receives an
00135         // event.
00136         switch (formId)
00137         {
00138             case MainForm:
00139                 FrmSetEventHandler(frmP, MainFormHandleEvent);
00140                 break;
00141 
00142             default:
00143                 ErrNonFatalDisplay("Invalid Form Load Event");
00144                 break;
00145 
00146         }
00147         return true;
00148     }
00149     
00150     return false;
00151 }
00152 
00153 
00154 /**
00155  * The event loop for the application.  
00156  */
00157 static void AppEventLoop()
00158 {
00159     UInt16 error;
00160     EventType event;
00161     Boolean redrawWhenReturningToGameWindow;
00162 
00163 
00164     // The game has not yet begun. Let PalmOS handle all events until
00165     // frmOpenEvent has been received on the Main form.
00166     do
00167     {
00168         EvtGetEvent (&event, evtWaitForever);
00169         if (! SysHandleEvent (&event))
00170             if (! MenuHandleEvent (NULL, &event, &error))
00171                 if (! AppHandleEvent (&event))
00172                     FrmDispatchEvent (&event);
00173 
00174     } while ((event.eType != appStopEvent) && (!(presentation->hasBegun())));
00175 
00176 
00177     do
00178     {
00179         // Wait until the next game period.
00180         EvtGetEvent (&event, presentation->getTimeUntilNextPeriod());
00181         
00182         
00183         // Detect exiting the game's window.  This must be checked for.  At this
00184         // point there probably exists another window which may cover part of
00185         // the MainView window.  Suppress drawing.  Otherwise drawing may draw
00186         // to part of the window covered by the new window.
00187         if (event.eType == winExitEvent)
00188         {
00189             if (event.data.winExit.exitWindow == (WinHandle) FrmGetFormPtr(MainForm))
00190             {
00191                 presentation->pause();
00192             }
00193         }
00194 
00195         // Detect entering the game's window.  Resume drawing to our window.
00196         else if (event.eType == winEnterEvent)
00197         {
00198             // In the current code, the menu doesn't remove itself when it receives
00199             // a winExitEvent.
00200             if (event.data.winEnter.enterWindow == (WinHandle) FrmGetFormPtr(MainForm) &&
00201                 event.data.winEnter.enterWindow == (WinHandle) FrmGetFirstForm ())
00202             {
00203                 // Sometimes we can enter the game's window without knowing it was 
00204                 // ever left.  In that case the pause time will not have been recorded.
00205                 // Presentation is smart enough to handle that, and will set the current 
00206                 // period back to it's beginning.
00207                 presentation->resume();
00208                 
00209                 
00210                 // Redraw the game window.  This is normally triggered when the launcher
00211                 // is activated during a low heap memory condition to work around a launcher
00212                 // bug which causes it to fail to send a frmUpdateEvent when it doesn't
00213                 // restore the bits underneath it.
00214                 if (redrawWhenReturningToGameWindow)
00215                 {
00216                     presentation->redraw();
00217                     redrawWhenReturningToGameWindow = false;
00218                 }
00219             }
00220         }
00221         else
00222         {
00223             presentation->receiveEvent(&event);
00224 
00225             // If it's time, go to the next time period
00226             if (presentation->getTimeUntilNextPeriod() == 0)
00227             {       
00228                 presentation->nextPeriod();
00229             }
00230         }
00231 
00232 
00233         if (event.eType == nilEvent)
00234             continue; 
00235 
00236 
00237         // Intercept the hard keys to prevent them from switching apps
00238         if (event.eType == keyDownEvent)
00239         {
00240             // Swallow events notifying us of key presses.  We poll instead.
00241             if (event.data.keyDown.chr >= hard1Chr &&
00242                 event.data.keyDown.chr <= hard4Chr &&
00243                 !(event.data.keyDown.modifiers & poweredOnKeyMask))
00244             {
00245                 continue;
00246             }
00247             
00248             // Handle a launcher bug.  It can fail to send a frmUpdateEvent.
00249             else if (event.data.keyDown.chr >= launchChr)
00250             {
00251                 UInt32 freeBytes;
00252                 UInt32 maxChunk;
00253                 const UInt32 saveBitsThreshold = 4000;
00254                                 
00255                 MemHeapFreeBytes (0, &freeBytes, &maxChunk);
00256                 if (freeBytes <= saveBitsThreshold)
00257                 {
00258                     redrawWhenReturningToGameWindow = true;
00259                 }
00260             }
00261 
00262         }
00263 
00264 
00265 
00266         if (! SysHandleEvent(&event))
00267             if (! MenuHandleEvent(0, &event, &error))
00268                 if (! AppHandleEvent(&event))
00269                     FrmDispatchEvent(&event);
00270 
00271     } while (event.eType != appStopEvent);
00272 }
00273 
00274 
00275 /**
00276  * Prepare the App for running
00277  */
00278 static Err AppStart(UInt16 launchFlags)
00279 {
00280     Device::init();
00281 
00282     Err error = Device::romVersionCompatible(appMinRomVersion, launchFlags);
00283     if (error != errNone) 
00284         return error;
00285 
00286     // Establish the presentation
00287     presentation = new Presentation();
00288 
00289     return errNone;
00290 }
00291 
00292 
00293 /**
00294  * Shutdown the App (save prefs, restore display to normal)
00295  */
00296 static void AppStop()
00297 {
00298     // Close all the open forms.
00299     FrmCloseAllForms ();
00300 
00301     delete presentation;
00302 }
00303 
00304 
00305 /**
00306  * This is the main entry point for the application.
00307  *
00308  * @param cmd word value specifying the launch code. 
00309  * @param cmdPB pointer to a structure that is associated with the launch code. 
00310  * @param launchFlags word value providing extra information about the launch.
00311  *
00312  * @return Result of launch
00313  */
00314 static UInt32 StarterPalmMain(UInt16 cmd, void* /*cmdPBP*/, UInt16 launchFlags)
00315 {
00316     if (cmd == sysAppLaunchCmdNormalLaunch)
00317     {
00318         Err error = AppStart(launchFlags);
00319         if (error != errNone)
00320             return error;
00321                 
00322         FrmGotoForm(MainForm);
00323         AppEventLoop();
00324         AppStop();
00325 
00326         return errNone;
00327     }
00328     else
00329     {
00330         return errNone;
00331     }
00332 }
00333 
00334 
00335 /**
00336  * This is the public main entry point for the application.
00337  *
00338  * @param cmd word value specifying the launch code. 
00339  * @param cmdPB pointer to a structure that is associated with the launch code. 
00340  * @param launchFlags word value providing extra information about the launch.
00341  *
00342  * @return Result of launch
00343  */
00344 UInt32 PilotMain( UInt16 cmd, void* cmdPBP, UInt16 launchFlags)
00345 {
00346     return StarterPalmMain(cmd, cmdPBP, launchFlags);
00347 }
00348 

Razor! Engine Developer's Guide. Copyright © by Tilo Christ. All Rights Reserved. Last updated: 4 Nov 2000