This document is a single-page version of a a multi-page document, suitable for easy printing.

Tutorial

This chapter shows how you might get started writing a simple GEOS program, and it explains several fundamental GEOS programming concepts as it goes along. Although this tutorial explicitly refers to the Nokia 9000 SDK version 1.1, it is also applies to the Nokia 9000i SDK version 2.0.


Getting Started with GEOS Programming

Before jumping into writing your own application, it might be useful to compile and run an existing sample application. This chapter will take you through the generic steps of checking out a source file, compiling it, then running the compiled application on the emulator with the Swat debugger attached. The next two chapters explore GEOS development in greater detail by stepping through every step in creating the application "Tutorial". We recommend that you step through this chapter to acquaint yourself with the generic process of compiling an application, then carefully follow the tutorial to get a flavor for GOC, Swat debugging, and Geode Parameter files.

Typically, your development sequence will follow these steps:

  1. Check out a file by copying it to your Working Branch. This is your private development area. By doing your work here, the Branch files remain untouched (see "Developing In Your Working Branch" for more information);
  2. Create a Makefile using the mkmf utility;
  3. Compile your application using the pmake utility;
  4. Run the application on the error-checking version of the target emulator;
  5. Debug your application using the Swat debugger; and
  6. Edit your source code and go back to Step 3.

The next section follows this sequence using the Dialogs sample application, though of course the same steps apply for any sample application. (Refer to the release notes in the README.TXT file or the Troubleshooting guide in the "Installing the SDK" chapter if you encounter problems.)

In the directory paths below, prepend your correct drive letter or path to PCGEOS and replace "workingdir" as appropriate. Also note that if you are using the Nokia 9000i SDK version 2.0, the directory labled here as N9000v11 will be N9000v20 in your development branch.

  1. Install the SDK by following the instructions in the "Installing the SDK" chapter;
  2. Start a command window.
  3. Go to the \APPL\ subdirectory of your Working Directory:
  4. CD PCGEOS\workingdir\APPL
  5. Create and go to the subdirectory \SDK_9000\DIALOGS\:
  6. MD SDK_9000\DIALOGS
    CD SDK_9000\DIALOGS
  7. Copy the file DIALOGS.GOC from the N9000v11 Branch to this directory:
  8. COPY \PCGEOS\N9000V11\APPL\SDK_9000\DIALOGS\DIALOGS.GOC
  9. Type mkmf to create the makefile.
  10. Type pmake to compile and link the executable. This will create an error-checking version called DIALOGSEC.GEO .
  11. Launch a wait-for-swat EC demo. You can do this from the GEOS SDK program menu if the shortcuts were installed; otherwise, CD to \PCGEOS\workingdir\TARGET\N9000.EC, then type start ss .
  12. Launch Swat. You can also do this from the GEOS SDK program menu; otherwise, type start pcgeos\bin\swat . (The full path is only necessary if there is also a Swat stub in your current directory, which you do not want to run.)
  13. When the emulator has finished loading (usually after "serial" exits), press Ctrl-C in the Swat window to bring command control back to Swat.
  14. Copy your geode (your compiled executable) to the target emulator by typing send dialogs .
  15. Type c to continue Swat.
  16. Click inside the emulator window to regain focus in that window. Press Ctrl-F12 to launch the Extras folder.
  17. Use the arrow keys to highlight the EC Dialogs application. Press F1 to launch it. (The keys F1 - F4 correspond to the menu list on the right of the emulator window.)
  18. Play with the application.
  19. Select the Swat window, press Ctrl-C to bring command control back to Swat, then type quit to exit the emulator.

In this section, you learned how to check out a source code file by copying it from the Branch directory to your Working Directory, and then compile and run it on the emulator. Notice that it was not necessary to copy all the files from the \DIALOGS\ subdirectory in the N9000v11 Branch. When compiling and linking, the tools are smart enough to look for files in your Working Directory first and then look for whatever other files it needs in the Branch directory. This allows you to copy only the file or files you need to work on; shared files can remain in the Branch directory.

Now that you've gone through the basic steps of compiling and running a GEOS application, you can go on to the next chapter to create your own application from scratch.


Tutorial

In this tutorial, you will create a simple GEOS application that draws text and demonstrates the basic components of a GEOS application. You'll learn how to compile and link the application and explore its source code using the Swat debugger.


1: Creating "Tutorial"

The application that you'll be working on throughout this tutorial is called, appropriately enough, "Tutorial." In this section you'll create two files: TUTORIAL.GP and TUTORIAL.GOC. The .GP (or "geode parameters") file tells the linker how the application is organized; the .GOC file contains the actual source code. All GEOS applications require these two files.

1.1: Creating "Tutorial": Setting Up Your Working Directory

The first step in creating your application is to set up your Working Directory where you will do all your private development. Because your application is called "Tutorial," you need to create a \TUTORIAL\ subdirectory in your Working Directory to hold the source files (see "Developing In Your Working Branch" for more information).

  1. Create the \TUTORIAL\ subdirectory under \APPL\ in your Working Directory; for example: C:\PCGEOS\workingdir\APPL\TUTORIAL\ where "workingdir" refers to your personal working directory (usually the same as your login name).
  2. Type in the contents of TUTORIAL.GPand TUTORIAL.GOC. Put these files into the ...\TUTORIAL\ directory you just created.Typing source code by hand is often a good way to learn the feel for a language's grammar. If you don't want to type the source code by hand, follow the above links and copy the text into the files TUTORIAL.GOC and TUTORIAL.GP, as indicated.
1.2: Creating "Tutorial": Compiling Your Source Code

Now that you've created some source code, it's time to compile your application. First, you will need to create a Makefile and then run the "make" or compilation utility.

  1. Start up a command window and make sure you are in your Working Directory for this application; i.e., C:\PCGEOS\workingdir\APPL\TUTORIAL\.
  2. Type mkmf at the prompt; this utility creates a "makefile" which tells the pmake utility the steps with which to construct the application. It also creates a dependencies file, which tells pmake which files need to be remade whenever a source file has been modified.
  3. Type pmake to invoke the preprocessor, compiler, and linker to create the GEOS executable.

When you have completed these steps, your directory should contain some new files, including TUTORIALEC.GEO and your newly created GEOS executable or "geode." The "EC" in the name indicates that you've compiled the error-checking version of your application. The GEOS SDK tools have been set up with some optional compilation features to allow for error-checking code which is useful during development.

1.3: Creating "Tutorial": Starting the Emulator and Swat

Once you've successfully compiled your code, it's time to start up the GEOS emulator and attach Swat, the debugger.

  1. From the GEOS SDK program group, start the error-checking version of the emulator with Swat-wait.
  2. From the GEOS SDK program group, launch Swat (or type "swat" from a command prompt). The following should appear in the Swat window:
  3. Swat version 2.1 (Feb 14 1997 19:05:55).
    Using the N9000V11 version of GEOS.
    SDK version: ntsdk30
    Looking for "loader"...c:/pcgeos/N9000V11/Installed/Loader/Text/loaderec.sym
    Sourcing swat.tcl...done
    GEOS Attached
    Stopped in LoadGeos, address 0a06h:0007h
    LoadGeos:            CLD                        ;DF=0
    (loader:0) 1 => 

    At this point, Swat is telling you that it has successfully established communications with the target emulator, has started the process of loading the GEOS kernel, and is now waiting for you to type in a command. Type c and press the <Enter> key to continue loading the GEOS emulator. The following will appear:

    Swat version 2.1 (Feb 14 1997 19:05:55).
    pcgeosGEOS Attached
    Stopped in LoadGeos, address 0a06h:0007h
    LoadGeos:            CLD                        ;DF=0
    (loader:0) 1 => save screen1.txt
    Saving to c:/pcgeos/nfiedler/screen1.txt: 1000 lines
    (loader:0) 2 => c
    Looking for "geos    Eker"...c:/pcgeos/N9000V11/Installed/Library/Kernel/N9000DE
    MO/geosec.sym
    Looking for "os2     Eifs"...c:/pcgeos/N9000V11/Installed/Driver/IFS/DOS/OS2/os2
    ec.sym
    Looking for "netware Eifs"...c:/pcgeos/N9000V11/Installed/Driver/IFS/DOS/NetWare
    /netwareec.sym
    netware exited.
    Looking for "respondrElib"...c:/pcgeos/N9000V11/Installed/Library/Respondr/N9000
    DEMO/respondrec.sym
    Looking for "rspwr   Edrv"...c:/pcgeos/N9000V11/Installed/Driver/Power/Rspwr/N90
    00DEMO/rspwrec.sym
    Thread 1 created for patient geos
    Thread 2 created for patient geos
    Looking for "vidmem  Edrv"...c:/pcgeos/N9000V11/Installed/Driver/Video/Dumb/VidM
    em/vidmemec.sym
    Looking for "swap    Elib"...c:/pcgeos/N9000V11/Installed/Library/Swap/swapec.sy
    m
    Looking for "disk    Edrv"...c:/pcgeos/N9000V11/Installed/Driver/Swap/Disk/diske
    c.sym
    Looking for "xms     Edrv"...c:/pcgeos/N9000V11/Installed/Driver/Swap/XMS/xmsec.
    sym
    Looking for "gdi     Elib"...c:/pcgeos/N9000V11/Installed/Library/GDI/GenPC/WIN3
    2/gdiec.sym
    Looking for "gdiKbd  Edrv"...c:/pcgeos/N9000V11/Installed/Driver/Keyboard/GDI/gd
    iKbdec.sym
    Looking for "nimbus  Edrv"...c:/pcgeos/N9000V11/Installed/Driver/Font/Nimbus/nim
    busec.sym
    Looking for "stream  Edrv"...c:/pcgeos/N9000V11/Installed/Driver/Stream/streamec
    .sym
    Looking for "sound   Elib"...c:/pcgeos/N9000V11/Installed/Library/Sound/N9000/so
    undec.sym
    Looking for "standarddrvr"...c:/pcgeos/N9000V11/Installed/Driver/Sound/Standard/
    N9000DEMO/standard.sym
    Looking for "ui      Elib"...c:/pcgeos/N9000V11/Installed/Library/User/N9000/uie
    c.sym
    Thread 0 created for patient ui
    Looking for "styles  Elib"...c:/pcgeos/N9000V11/Installed/Library/Styles/N9000/s
    tylesec.sym
    Looking for "color   Elib"...c:/pcgeos/N9000V11/Installed/Library/Color/N9000/co
    lorec.sym
    Looking for "ruler   Elib"...c:/pcgeos/N9000V11/Installed/Library/Ruler/N9000/ru
    lerec.sym
    Looking for "text    Elib"...c:/pcgeos/N9000V11/Installed/Library/Text/N9000/tex
    tec.sym
    Looking for "rtcm    Elib"...c:/pcgeos/N9000V11/Installed/Library/RTCM/rtcmec.sy
    m
    Looking for "ansic   Elib"...c:/pcgeos/N9000V11/Installed/Library/AnsiC/ansicec.
    sym
    Looking for "vp      Elib"...c:/pcgeos/N9000V11/Installed/Library/Foam/OEM/vp_st
    b/vpec.sym
    Looking for "foam    Elib"...c:/pcgeos/N9000V11/Installed/Library/Foam/Foam/foam
    ec.sym
    Looking for "foamdb  Elib"...c:/pcgeos/N9000V11/Installed/Library/Foam/DB/foamdb
    ec.sym
    Looking for "contdb  Elib"...c:/pcgeos/N9000V11/Installed/Library/Foam/Contdb/co
    ntdbec.sym
    WARNING(foamdb::FoamDBVisibleRecordEnumWithRange): DB_ENUM_START_ELEMENT_TOO_LAR
    GE
    Looking for "securitylib "...c:/pcgeos/N9000V11/Installed/Library/Foam/Security/
    security.sym
    Looking for "rudy    Espu"...c:/pcgeos/N9000V11/Installed/Library/SpecUI/Rudy/ru
    dyec.sym
    Looking for "simp4bitEdrv"...c:/pcgeos/N9000V11/Installed/Driver/Video/Dumb/Simp
    4Bit/WIN32/simp4bitec.sym
    WARNING(rudy::OLAppEnsureIndicatorCorrect): RUDY_INDICATOR_NOT_FOUND_IS_GEOS_BOO
    TING_OR_SHUTTING_DOWN
    Looking for "spool   Elib"...c:/pcgeos/N9000V11/Installed/Library/Spool/N9000/sp
    oolec.sym
    Thread 0 created for patient spool
    Looking for "mailbox Elib"...c:/pcgeos/N9000V11/Installed/Library/Mailbox/N9000/
    mailboxec.sym
    Thread 0 created for patient mailbox
    Looking for "nonts   Edrv"...c:/pcgeos/N9000V11/Installed/Driver/Task/NonTS/nont
    sec.sym
    Looking for "contlog Elib"...c:/pcgeos/N9000V11/Installed/Library/Foam/ContLog/c
    ontlogec.sym
    Looking for "indicatoEapp"...c:/pcgeos/N9000V11/Installed/Appl/FApps/OEM/indicat
    o/indicate.sym
    Thread 0 created for patient indicato
    Looking for "faxfile Elib"...c:/pcgeos/N9000V11/Installed/Library/Fax/File/N9000
    /faxfileec.sym
    Looking for "viewer  Elib"...c:/pcgeos/N9000V11/Installed/Library/Foam/Viewer/vi
    ewerec.sym
    Looking for "clrfax  Egeo"...c:/pcgeos/N9000V11/Installed/Appl/FApps/ClrFax/clrf
    axec.sym
    Thread 0 created for patient clrfax
    Looking for "math    Elib"...c:/pcgeos/N9000V11/Installed/Library/Math/mathec.sy
    m
    Looking for "ssset   Elib"...c:/pcgeos/N9000V11/Installed/Library/Foam/OEM/ssset
    /sssetec.sym
    Looking for "scm     Elib"...c:/pcgeos/N9000V11/Installed/Library/Foam/OEM/scm/s
    cmec.sym
    Thread 0 created for patient scm
    Looking for "compose Elib"...c:/pcgeos/N9000V11/Installed/Library/Foam/OEM/compo
    se/composee.sym
    Looking for "borlandcElib"...c:/pcgeos/N9000V11/Installed/Library/Math/Compiler/
    BorlandC/borlandcec.sym
    Looking for "phone   Eapp"...c:/pcgeos/N9000V11/Installed/Appl/FApps/OEM/phone/p
    honeec.sym
    Thread 0 created for patient phone
    Thread 1 created for patient indicato
    Thread 1 of indicato exited 0
    viewer exited.
    faxfile exited.
    clrfax exited.
    Thread 0 of clrfax exited 0
    Looking for "serial  Edrv"...c:/pcgeos/N9000V11/Installed/Driver/Stream/Serial/s
    erialec.sym
    serial exited.
    GEOS Halted
    Stopped in DOSIdleHook, address 2796h:1136h
    DOSIdleHook+17:      MOV     AX, 5760 (1680h)
    (geos:0) 3 => 

    Each line that begins "Looking for..." indicates that the system is loading a geode (a GEOS executable) and that Swat is looking for its symbol information. Swat also tells you whenever it creates (or exits) a thread for any geode.

    Now that the emulator is running with Swat attached, you need to send your source code to the emulator to run it.

  4. Type Ctrl-C in the Swat window. At this point, the Swat prompt should appear.
  5. Type send tutorial to copy the application to the emulator.
  6. Type run tutorial to run the application.
  7. Type c to allow execution to continue on the emulator.

After you've followed these steps, your emulator should look like the screen pictured below.


Figure 1: The "Tutorial" application screen.

This is how your application will look after you type in the first pieces of code. Notice that it consists only of a blank viewing window and a "Close" button; later you will add code that displays text in this window.

As you can see, your application consists of an empty window. In the next chapter, you will add procedural code that draws a text string in this window.


2: Learning GOC

By typing in the contents of the source files (both the .GOC and .GP files), you've probably become a little familiar with GOC syntax. GOC is a proprietary superset of standard ANSI C. It supports C routines and functionality and adds its own set of keywords and special syntax. This section will cover basic GOC syntax, including the usage and meaning of various GOC keywords, by giving a line-by-line explanation of the code you entered.

2.1: Learning GOC: TUTORIAL.GP: Geode Parameters File

The .GP file tells the Glue linker about an application's general organization. (You can get complete information about all of the possible fields in a .GP file by reading the GP File Keywords reference.) Let's take a look at the code in TUTORIAL.GP to find out what each line means.

name tutorial.app

The name field specifies the "patient" name by which Swat will identify the application. Swat thinks of each geode as a patient, so you'll see phrases in Swat like "patient died".

longname "Tutorial Sample Application"

The longname field is the name the system displays for this application. For example, if you press Ctrl-F12 on the emulator (to list the applications in the "Extras" folder), you will see the longname for this application displayed. GEOS supports names up to 32 characters in length.

tokenchars "TUTO"
tokenid 8

Each application has its own unique identifier to the system. This identifier is a special GEOS data type called a GeodeToken. A GeodeToken is a data structure comprised of two fields:

tokenchars
A string of four characters (normally taken from the name of the application); and
tokenid
The Manufacturer ID for your company; this value is unique to your company and ensures that your applications' GeodeTokens do not conflict with those of other manufacturers. All sample applications, including this tutorial application, use a tokenid of 8; for your "real" applications, you should use your company's assigned Manufacturer ID. (Send email to orders@geoworks.com to receive a Manufacturer ID.)
type appl, process, single

The type line tells Glue whether your geode is an application, a driver or a library. Tutorial, like most GEOS applications, uses the following keywords:

Because GEOS is a multi-tasking or multi-threaded operating system, it allows more than one thread of execution to run at a time. This enables programs to run in the background. By specifying that your application has a process, you are requesting that it have its own thread of execution. If you were writing a library, you probably wouldn't want to give it a process, figuring that other geodes would be executing the library's code.

class TutorialProcessClass

The class line specifies which class will run the process thread. In this case, the TutorialProcessClass will be in charge of the process thread. (You will declare TutorialProcessClass in the TUTORIAL.GOC file.)

appobj TutorialApp

The appobj line specifies the "application object" for this application. The application object is the interface between your geode and the rest of the system. (You will declare this object in your source file as well.)

platform n9000v20

Glue will use the platform line to make sure that your application doesn't rely on any geodes that aren't present on the GEOS device.

heapspace 3K

The heapspace line specifies the maximum amount of memory the application requires on the global memory heap. Note that the value 3K is a wild guess. Once your application is closer to completion, you can use Swat's heapspace command to find out how much heap space the application really needs.

library geos
library ui

The library lines tell Glue which libraries to load for your application. All GEOS libraries are dynamically linked and loaded.

resource APPRESOURCE ui-object
resource INTERFACE ui-object

The resource lines specify the blocks of memory that your application uses for objects. Breaking up an application into resources allows it to run more efficiently because the system will only load those resources it needs.

The ui-object keyword signals that the UI thread should run the specified resource. Specifying a UI thread ensures that your application will have a UI thread and thus be dual-threaded: the process will run in one thread and UI objects will run in the UI thread. If you don't want the application to have two threads, use the keyword object instead of ui-object .

2.2: Learning GOC: TUTORIAL.GOC: Source Code

Now let's take a look at the source code in TUTORIAL.GOC. (For more information about GOC syntax, see the GEOS Programming chapter.)

@include <stdapp.goh>
@include <foam.goh>

The first lines of code contain the @include directive. Note the '@' symbol. This symbol is used to denote GOC keywords and distinguish them from regular C syntax. @include behaves the same way as #include, except that the inclusion will take place when the GOC preprocessor is processing the source code. Generally, you @include .GOH files and #include regular .H files.

@class TutorialProcessClass, GenProcessClass;
@endc;

The @class and @endc keywords mark the beginning and end of a new class definition. Here, you're defining TutorialProcessClass as a subclass of GenProcessClass , which means that TutorialProcessClass will inherit all the behavior of its parent, GenProcessClass .

@classdecl TutorialProcessClass, neverSaved;

Once you define the class, you need to declare it so that the system will know how to build objects of that class. To declare the class, you use the @classdecl keyword and because this is the process object, (a special object with no instance data), you also use the neverSaved flag. This flag tells the system that no instance data need be saved when the system shuts down.

 @start AppResource; 

The @start keyword defines a resource or block of memory. In this case, you're defining the APPRESOURCE resource. In the . GP file, you may recall that this resource holds objects, and that those objects will be run by the UI thread.

@object FoamSubApplicationClass TutorialApp = {

The first object to be declared in the APPRESOURCE resource is the application object, TutorialApp . In the .GP file, you specified TutorialApp as the application object in the appobj line. The application object is responsible for receiving and handling all sorts of system messages and notifications. This is a nontrivial task so the object will be of a class specifically set up to handle this task: FoamSubApplicationClass . (Note, on GEOS systems other than the Nokia 9000i Communicator, you would use a GenApplicationClass; FoamSubApplicationClass is a specialized subclass of GenApplicationClass.)

Because the application object provides important information to the system, it needs to live in its own resource; that way, the system can query the application object by loading only that resource which contains it.

The next set of fields contains the application object's instance data. Instance data are characteristics of an object, as defined by the object's class. (This should make more sense as you read on.)

	 GI_visMoniker = list{ @TutorialTextMoniker };

The GI_visMoniker field specifies the object's label or name that appears to the user (not to be confused with TutorialApp, the name of the object). The "visMoniker" part of the field name is short for "visual moniker." In GEOS parlance, a "visual moniker" is a text string or graphic used to identify an object to the user. This field is commonly set to a "list" of monikers; the system uses the moniker list to determine which text or graphic to display for your application.

 	 GI_comp = @TutorialPrimary;

The GI_comp field specifies the children of a generic UI object. In this case, the only child of the TutorialApp object is the TutorialPrimary object (which you declare later). (For a detailed description of how objects keep track of their children, see the GEOS Programming chapter.)

Notice that both instance data field names begin with "GI_." The "GI_" stands for "Gen Instance." Because GenApplicationClass is a subclass of GenClass , it inherits the GI_visMoniker field from its parent. By Geoworks' naming conventions, instance data field names begin with the initials of their associated class followed by an "I" for "instance." Thus, any GenApplicationClass instance field names would begin "GAI_."

You may be wondering about the syntax for @TutorialPrimary. @TutorialPrimary is actually a reference to the TutorialPrimary object. Object references have their own GEOS-specified type called an optr.

	gcnList( MANUFACTURER_ID_GEOWORKS, GAGCNLT_WINDOWS ) =@TutorialPrimary; 
}

This line puts the TutorialPrimary object,which is the primary window of your application, on a General Change Notification (GCN) list so that it will receive notification when a system-level change has occurred. (For more information about GCN lists, see the gcnList entry in the GEOS Programming chapter.)

This completes the declaration of the TutorialApp object.

@visMoniker TutorialTextMoniker = "My Tutorial";

This line contains the string to which the TutorialApp 's GI_visMoniker field refers. The @visMoniker keyword stores the string in a GEOS data structure set up strictly for monikers.

@localize "Program Title";

This @localize statement doesn't actually affect the program; it simply acts as a hint for someone translating the program to a foreign language. The ResEdit program displays the information in @localize statements when it prompts the translator to translate a moniker or string chunk. In this case, for example, when ResEdit prompts the translator to translate the string, "My Tutorial," it will display the string "Program Title" to assist with the translation.

@end AppResource

This line signals the end of the APPRESOURCE declaration.

@start Interface; 

Here begins the next resource definition. This resource is called INTERFACE and will hold the basic UI gadgetry for your application.

@object GenPrimaryClass TutorialPrimary = { 

The first object to be declared in this resource is TutorialPrimary , your application's primary window and an object of GenPrimaryClass .

	GI_comp = @TutorialView, @TutorialCloseTrigger;
}

The first instance data field is GI_comp , which specifies the children of TutorialPrimary .

@object GenViewClass TutorialView = {

The next object is a GenViewClass object called TutorialView ; this object provides space on the screen for objects to draw themselves.

    GVI_horizAttrs = @default |
        GVDA_NO_LARGER_THAN_CONTENT;
    GVI_vertAttrs  = @default |
        GVDA_NO_LARGER_THAN_CONTENT;
    GVI_content = process;
}

The GVI_content field specifies the top-level object which will appear in the view's drawing space. The GVI_horizAttrs and GVI_vertAttrs fields specify how the view should size itself in relation to the content object's size. Setting the flag GVDA_NO_LARGER_THAN_CONTENT ensures that the view will be the same size as its content object.

Notice that the GVI_...Attrs fields also use the @default keyword. @default tells the system to expand to the default values for this field (as defined by GenViewClass ); additional flags are ORed in with the single pipe ("|").

@object GenTriggerClass TutorialCloseTrigger = {
    GI_visMoniker = "Close";

The last object declared in the INTERFACE resource is TutorialCloseTrigger, an object of GenTriggerClass. TutorialCloseTrigger provides the "Close" button for your application.

    GTI_destination = @TutorialApp;
    GTI_actionMsg = MSG_FSA_RETURN_TO_LAUNCHER;

The GTI_destination and GTI_actionMsg fields are GenTrigger instance data fields. GTI_actionMsg specifies the message that gets sent when the user presses the "Close" button; GTI_destination specifies the object who will handle the message. (We will discuss messages in more detail in the next chapter; suffice it to say that a message is a signal which may be handled by a set of procedural code defined for a class.)

    HINT_SEEK_MENU_BAR;
    HINT_SEEK_REPLY_BAR;
    HINT_SEEK_SLOT = 3;
}

These hints ensure that the button is placed on the right side of the screen so that it aligns with the buttons on the Nokia 9000i Communicator.

@end Interface;

This line signals the end of the INTERFACE resource definition.


3: Exploring With Swat

Now that you've successfully compiled your application, you can use Swat to "debug" it. In the Swat window, press Ctrl-C to halt the emulator and gain control back in the Swat window. Something similar to the following should appear in your Swat window:

GEOS Halted
Stopped in DOSIdleHook, address 277eh:1136h
DosIdleHook+17		MOVE	AX, 5760 (1680h)
(geos:0) 5 =>

"GEOS Halted" indicates that Swat has frozen the emulator. The next two lines of Swat output indicate the address of the current internal routine that is executing. If Swat stopped in a public routine, the address would have been given in relation to the routine name and would have been more readable.

The last line indicates the thread that was executing (on the emulator) when you hit Ctrl-C . In this example, the zeroth thread associated with the GEOS geode (the kernel) was executing. To examine the thread associated with your application, type "tutorial." (Recall that this is the value you set in the name field of your TUTORIAL.GP file [without the suffix].) This tells Swat which thread to switch to.

(geos:0) 5 => tutorial
[tutorial:0] 6 => 

The prompt indicates that you are now in the process thread of the tutorial geode. If you were in the UI thread, your prompt would read "[tutorial:1]." To change threads within a geode, simply type :0 or :1 .

Now try the where command to find out what this thread was doing when you stopped the system.

[tutorial:0] 6 => where
* 1: near BlockOnLongQueue(), 153dh:c22ah
2:  far QueueGetMessage(), 153dh:133ch
------------------------------------------------------------------------------
The event queue for "tutorial:0" is empty
==============================================================================
[tutorial:0] 7 =>

These lines tells you that the tutorial thread is idling; it's waiting for a message or something to happen.

Next, use the gentree command to examine your application's generic UI object tree.

[tutorial:0] 7 => gentree *TutorialPrimary
*TutorialPrimary::GenPrimary (@1, ^l5230h:001eh) "My Tutorial"
    *TutorialView::GenViewClass (@2, ^l5230h:0020h)
	^143b0h:002ah(GenValueClass) (@3, ^15230h:002ah)
    *TutorialCloseTrigger(GenTriggerClass) (@4, ^15230h:0024h) "Close"
[tutorial:0] 8=>

The gentree command prints out a list of all the objects in the tree, along with their class, object references, and monikers. For an example, let's look at the information for the TutorialView object:

You can refer to an object by a shortcut that Swat provides, namely, the "@number." To look at an object's instance data, use the Swat command pobj followed by the "@number" designation for the particular object. Try the pobj command with the TutorialView object.

[tutorial:0] 8 => pobj @2
*TutorialView{GenViewClass} (@5, ^l5230h:0020h)
master part: Gen_offset(131) -- ui::GenViewInstance
@6: {ui::GenViewInstance (^h21040:502)+131} = {
    GenInstance GenView_metaInstance = {
        MetaBase Gen_metaInstance = {
            ClassStruct _far *MB_class = 3916h:1816h (rudy::CommonUIClassStructu
res::OLPaneClass)
        }
         LinkPart GI_link = {
            void _optr LP_next = *TutorialCloseTrigger{GenTriggerClass} (@7, ^l5
230h:0024h)
        }
        CompPart GI_comp = {
            void _optr CP_firstChild = ^l5230h:002ah{GenValueClass} (@8, ^l5230h :002ah)
        }
        void _lptr GI_visMoniker = null
        KeyboardShortcut GI_kbdAccelerator = {
            KS_PHYSICAL = 0h
            KS_ALT = 0h
            KS_CTRL = 0h
            KS_SHIFT = 0h
            KS_CHAR_SET = 0h
            KS_CHAR = C_NULL
        }
        GenAttrs GI_attrs = {GA_TARGETABLE}
        GenStates GI_states = {GS_USABLE, GS_ENABLED}
    }
    PointDWFixed GVI_origin = {
        DWFixed PDF_x = {0.000000}
        DWFixed PDF_y = {0.000000}
    }
    RectDWord GVI_docBounds = {
        long RD_left = 0
        long RD_top = 0
        long RD_right = 0
        long RD_bottom = 0
    }
    PointDWord GVI_increment = {
        long PD_x = +20
        long PD_y = +15
    }
    PointWWFixed GVI_scaleFactor = {
        WWFixed PF_x = {1.000000}
        WWFixed PF_y = {1.000000}
    }
    ColorQuad GVI_color = {
        byte CQ_redOrIndex = fh
        ColorFlag CQ_info = CF_INDEX
        byte CQ_green = 0h
        byte CQ_blue = 0h
    }
    GenViewAttrs GVI_attrs = {GVA_NO_WIN_FRAME, GVA_FOCUSABLE}
    GenViewDimensionAttrs GVI_horizAttrs = {GVDA_DONT_DISPLAY_SCROLLBAR, GVDA_NO_LARGER_THAN_CONTENT}
    GenViewDimensionAttrs GVI_vertAttrs = {GVDA_NO_LARGER_THAN_CONTENT}
    GenViewInkType GVI_inkType = GVIT_PRESSES_ARE_NOT_INK
    void _optr GVI_content = tuto1:0{TutorialProcessClass}(0000h) (@9, ^l56c0h:0
000h)
    void _optr GVI_horizLink = null
    void _optr GVI_vertLink = null
}
Variable Data:
         *** No Variable Data ***
[tutorial:0] 9 =>

We certainly got a lot of data from that command!

*TutorialView{GenViewClass} (@5, ^l5230h:0020h)

The first line gives the object's class, shortcut and pointer information, similar to the output from gentree. The rest of the output consists of the object's instance data. For example:

GenViewDimensionAttrs GVI_horizAttrs = { GVDA_DONT_DISPLAY_SCROLLBAR,
GVDA_NO_LARGER_THAN_CONTENT}

These lines show which flags (of type GenViewDimensionAttrs) are set for the object's GVI_horizAttrs instance data field. Notice that Swat displays both the flag set in your source code, GVDA_NO_LARGER_THAN_CONTENT, as well as the default flag set by the system, GVDA_DONT_DISPLAY_SCROLLBAR.

You may recognize some of the instance data fields from your source code. Other fields you may not recognize because you didn't specify values for these fields, allowing the system to use default values instead.

With pobj , you took advantage of another Swat feature: command completion. There is no "pobj" Swat command; the command's name is really "pobject." Because "pobject" was the only Swat command that begins with p-o-b-j, Swat realized what you meant when you used "pobj."

Next let's try a series of exploratory Swat commands:

[tutorial:0] 9 => classes
TutorialProcessClass (@10, 42b8h:0040h), off ui::UserClassStructures::GenProcessClass
[tutorial:0] 10 =>

The classes command lists all classes created by the application. To view the class hierarchy for a particular class, use the cup ("class up") command.

[tutorial:0] 10 => cup @10
dgroup::TutorialProcessClass (@11, 42b8h:0040h)
ui::UserClassStructures::GenProcessClass (@12, 30c4h:11e6h)
geos::kcode::ProcessClass (@13, 153dh:a9d5h)
geos::kcode::MetaClass (@14, 153dh:a8edh)
[tutorial:0] 11 =>

As shown above, you can use the shortcut reference (the "@number") with the cup command or you can use the class name or reference address, e.g., cup TutorialProcessClass or cup 42b8h:0040h.

Some other Swat commands you might want to try out:

help
The help command provides documentation on Swat commands. Try help stop .
apropos
The apropos command allows you to search the Swat documentation by keyword. Try apropos instance .
heapspace
The heapspace command tells you the amount of memory your application requires; you may recall that this value goes in your . GP file on the heapspace line. Because this value should reflect a worse-case scenario, it's important to run this command several times towards the end of development so that the figure is accurate.
handles tutorial
The handles command scans the entire memory heap and returns information about all handles used by the application.

In the next chapter, you'll begin by editing the source code, so prepare to switch over to your editor window.


Tutorial Source Code

Here is the source code for the application discussed in this chapter. The source code is in two files:

TUTORIAL.GP

# Permanent name: This is required by Glue to set the permanent name
# and extension of the geode. The permanent name of a library is what
# goes in the imported library table of a client geode (along with the
# protocol number). It is also what Swat uses to name the patient.
#
name     tutorial.app
# Long filename: this name can displayed by the system. "EC " is
# prepended to this when the error-checking version is linked by Glue.
#
longname "Tutorial Sample Application"
# Token: The four-letter name is used by the system to locate the
# icon for this application in the token database. The tokenid
# number corresponds to the manufacturer ID of the program's author
# for uniqueness of the token. Since this is a sample application, we
# use the manufacturer ID for the SDK, which is 8.
#
tokenchars "TUTO"
tokenid    8
# Specify geode type: This geode is an application, and will have
# its own process (thread).
#
type   appl, process, single
# Specify class name for application thread. Messages sent to the
# application thread (a.k.a. "process" when specified as the output
# of a UI object) will be handled by this process class.
#
class  TutorialProcessClass
# Specify application object. This is the object that serves as
# the top-level UI object in the application.
#
appobj TutorialApp
# Specify for which platform this application will be compiled.
# Glue uses this to make sure that the libraries we are using
# (listed below) are available for this platform.
# In this case, the specified platform is the Nokia 9000i Communicator
#
platform n9000v20
# Heapspace: This is roughly the non-discardable memory usage
# (in paragraphs (16 bytes/paragraph)) of the application and any
# transient libraries that it depends on, plus an additional
# amount for thread activity. To find the heapspace for an
# application, use the Swat "heapspace" command.
#
heapspace 3K
# Libraries: list which libraries are used by the application.
# The foam library is for the Nokia 9000i Communicator only.
#
library geos
library ui
library foam
# Resources: list all resource blocks which are used by the
# application whose allocation flags can't be inferred by Glue.
# Usually this is needed only for object blocks, fixed code
# resources, or data resources that are read-only. Standard
# discardable code resources do not need to be mentioned.
#
resource APPRESOURCE ui-object
resource INTERFACE   ui-object

TUTORIAL.GOC

/********************************************************************
 *		Include Files
 *******************************************************************/

@include <stdapp.goh>
@include <foam.goh>
/********************************************************************
 *		Class Definitions
 *******************************************************************/
	/*
	 * Here we define "TutorialProcessClass" as a subclass of the
	 * system provided "GenProcessClass". As this application is
	 * launched, an instance of this class will be created, and
	 * will handle all application-related events (messages). The
	 * application thread will be responsible for running this
	 * object, meaning that whenever this object handles a message,
	 * we will be executing in the application thread.
	 *
	 * You will find no object in this file declared to be of this
	 * class. Instead, it is specified as the class for the
	 * application thread in "tutorial.gp".
	 */


@class TutorialProcessClass, GenProcessClass;
	/*
	 * Define messages for this class here. Most commonly, UI
	 * objects will send these messages to the application thread
	 * when they've been activated by the user.
	 */

@endc; /* end of class definition */
/********************************************************************
 *		Class Declarations
 *******************************************************************/
	/*
	 * Each object class requires a "class record" be stored in
	 * fixed memory for it. The class record is used by the GEOS
	 * message system for the delivery of messages sent to an
	 * object of the class. The class record needs to be defined
	 * in the file where the objects of that class are defined.
	 * The @classdecl GOC directive tells GOC to create the class
	 * record here.
	 *
	 * The neverSaved flag is necessary because ProcessClass
	 * objects are hybrid objects. It tells the system that no
	 * object of this class will ever be loaded from or stored to
	 * a state file.
	 */

@classdecl TutorialProcessClass, neverSaved;
/********************************************************************
 *		UI Object Resources
 *******************************************************************/
/********************************************************************
 *		AppResource Resource
 *******************************************************************/

@start AppResource;
/*
	*    Application Object
	*
	* The very top-level generic object of an application MUST be
	* a GenApplication object. The tutorial.gp file contains the "appobj"
	* statement which indicates that this "TutorialApp" object is in
	* fact the top-level UI object.
	*
	* This object should be in its own resource, as it is all that
	* need be in memory when the application is iconified. As such,
	* its resource should be as small as possible.
	*
	* FoamSubApplicationClass is for the Nokia 9000i Communicator
	* only. It adds special behavior for that platform.
	*/


@object FoamSubApplicationClass TutorialApp = {


		/*
		 * While the application object isn't shown on the screen,
		 * it has a list of VisMonikers for three purposes:
		 *   1) The GenPrimary (see below) inherits the moniker
		 *      when it comes up on screen.
		 *   2) When GeoManager needs to display an icon for the
		 *      application, and there's none for it in the Token
		 *      Database, it launches the app and sends a message
		 *      to the application object to install its list of
		 *      monikers in the token database under the
		 *      application's token.
		 *   3) When the GenPrimary is minimized, it uses the most
		 *      appropriate graphical moniker from this list for the
		 *      application's icon. If there's an abbreviated-text
		 *      moniker in the list, that's used as the icon title.
		 *      Else any regular-text moniker is used.
		 */
	GI_visMoniker = list { @TutorialTextMoniker };
		/*
		 * The GenApplication object has at least one child:
		 * the main application window.
		 */
	GI_comp = @TutorialPrimary;
		/*
		 * The main window should appear on-screen when the application
		 * is launched, so place it on the GAGCNLT_WINDOWS GCN list.
		 * This causes the application object to bring it on-screen at
		 * the appropriate time.
		 */
	gcnList( MANUFACTURER_ID_GEOWORKS, GAGCNLT_WINDOWS ) = @TutorialPrimary;
}
@visMoniker TutorialTextMoniker = "My Tutorial";
@localize "Program Title";
@end AppResource;
/********************************************************************
 *		Interface Resource
 * This resource is for miscellaneous UI objects.
 *******************************************************************/
@start Interface;
	/*
	 *    Primary window
	 *
	 * Every application has at least one GenPrimary object.
	 * This object serves as the main window of the application.
	 * Inside this window, various UI components, such as menus
	 * or lists, can be placed.
	 */

@object GenPrimaryClass TutorialPrimary  = {
		/*
		 * This window has two children:
		 * the GenView object and the Close button (see below).
		 */
	GI_comp = @TutorialView, @TutorialCloseTrigger;
}
	/*
	 *    GenView object
	 *
	 * This GenView object creates a window where the application can
	 * display portions of the document as necessary. As we want this
	 * window to be scrollable, the specific UI will create scroll
	 * bars with which the user can interact. Whenever a portion of
	 * the window needs to be redrawn, the GenView object will
	 * invalidate a portion of the window, causing a MSG_META_EXPOSED
	 * to be sent to the application. The application will draw the
	 * document into the window as requested. The window keeps track
	 * of a mask, which is used to clip the application's drawing
	 * operations, so that only the invalid portion of the window is
	 * drawn to.
	 */
@object GenViewClass TutorialView = {


		/*
		 * Make sure the view never gets larger
		 * than the thing being displayed within it.
		 */
	GVI_horizAttrs = @default | GVDA_NO_LARGER_THAN_CONTENT;
	GVI_vertAttrs = @default | GVDA_NO_LARGER_THAN_CONTENT;


		/*
		 * When the contents of this view (i.e. the document) must be
		 * updated, the UI should send a MSG_META_EXPOSED to the
		 * TutorialProcessClass object.
		 */
	GVI_content = process;
};
	/*
	 *    Close trigger
	 *
	 * On certain systems we should provide a way to exit the
	 * application. On the Nokia 9000i Communicator we have a
	 * close trigger like this one.
	 */
@object GenTriggerClass TutorialCloseTrigger = {
	GI_visMoniker = "Close";




		/*
		 * The next two instance fields are part of the
		 * GenTriggerClass. They specify the recipient object
		 * and the message that will be sent to that object
		 * when this trigger is activated.
		 */
	GTI_destination = @TutorialApp;
	GTI_actionMsg = MSG_FSA_RETURN_TO_LAUNCHER;




		/*
		 * The specific UI uses this combination of hints
		 * to place this trigger on the right side of the
		 * Nokia 9000i Communicator's screen.
		 */
	HINT_SEEK_MENU_BAR;
	HINT_SEEK_REPLY_BAR;
	HINT_SEEK_SLOT = 3;
}
@end Interface;

Adding Code and Debugging with Swat

Tutorial Source Code With Changes

Here is the source code for the application discussed in this chapter. Pieces of the code which have been added or changed from that in the previous chapter are called out in bold.

TUTORIAL.GP

# Permanent name: This is required by Glue to set the permanent name
# and extension of the geode. The permanent name of a library is what
# goes in the imported library table of a client geode (along with the
# protocol number). It is also what Swat uses to name the patient.
#
name     tutorial.app
# Long filename: this name can displayed by the system. "EC " is
# prepended to this when the error-checking version is linked by Glue.
#
longname "Tutorial Sample Application"
# Token: The four-letter name is used by the system to locate the
# icon for this application in the token database. The tokenid
# number corresponds to the manufacturer ID of the program's author
# for uniqueness of the token. Since this is a sample application, we
# use the manufacturer ID for the SDK, which is 8.
#
tokenchars "TUTO"
tokenid    8
# Specify geode type: This geode is an application, and will have
# its own process (thread).
#
type   appl, process, single
# Specify class name for application thread. Messages sent to the
# application thread (a.k.a. "process" when specified as the output
# of a UI object) will be handled by this process class.
#
class  TutorialProcessClass
# Specify application object. This is the object that serves as
# the top-level UI object in the application.
#
appobj TutorialApp
# Specify for which platform this application will be compiled.
# Glue uses this to make sure that the libraries we are using
# (listed below) are available for this platform.
# In this case, the specified platform is the Nokia 9000i Communicator
#
platform n9000v20
# Heapspace: This is roughly the non-discardable memory usage
# (in paragraphs (16 bytes/paragraph)) of the application and any
# transient libraries that it depends on, plus an additional
# amount for thread activity. To find the heapspace for an
# application, use the Swat "heapspace" command.
#
heapspace 3K
# Libraries: list which libraries are used by the application.
# The foam library is for the Nokia 9000i Communicator only.
#
library geos
library ui
library foam
# Resources: list all resource blocks which are used by the
# application whose allocation flags can't be inferred by Glue.
# Usually this is needed only for object blocks, fixed code
# resources, or data resources that are read-only. Standard
# discardable code resources do not need to be mentioned.
#
resource APPRESOURCE ui-object
resource INTERFACE   ui-object
#
# Any classes that we define in our application must be exported
# here for glue to process them.
#
export TutorialViewClass

TUTORIAL.GOC

/********************************************************************
 *		Include Files
 *******************************************************************/
    @include <stdapp.goh>
    @include <foam.goh>
/********************************************************************
 *		Constants
 *******************************************************************/
      /*
       * These constants are used in the TutorialDraw function.
       */
    #define TEXT_POINT_SIZE  48.0 /* point size */
    #define TEXT_ROTATION   -15   /* angle of rotation (degrees) */
    #define TEXT_X_POSITION  30   /* x position, in document coords */
    #define TEXT_Y_POSITION   0   /* y position, in document coords */
/********************************************************************
 *		Class Definitions
 *******************************************************************/
      /*
       * Here we define "TutorialProcessClass" as a subclass of the
       * system provided "GenProcessClass". As this application is
       * launched, an instance of this class will be created, and
       * will handle all application-related events (messages). The
       * application thread will be responsible for running this
       * object, meaning that whenever this object handles a message,
       * we will be executing in the application thread.
       *
       * You will find no object in this file declared to be of this
       * class. Instead, it is specified as the class for the
       * application thread in "tutorial.gp".
       */
    @class TutorialProcessClass, GenProcessClass;
      /*
       * Define messages for this class here. Most commonly, UI
       * objects will send these messages to the application thread
       * when they've been activated by the user.
       */
    @endc; /* end of class definition */

      /*
       * We subclass GenViewClass here because we need to
       * intercept a message for our GenView object.
       */
    @class TutorialViewClass, GenViewClass;
    @endc; /* end of class definition */
/********************************************************************
 *		Class Declarations
 *******************************************************************/
      /*
       * Each object class requires a "class record" be stored in
       * fixed memory for it. The class record is used by the GEOS
       * message system for the delivery of messages sent to an
       * object of the class. The class record needs to be defined
       * in the file where the objects of that class are defined.
       * The @classdecl GOC directive tells GOC to create the class
       * record here.
       *
       * The neverSaved flag is necessary because ProcessClass
       * objects are hybrid objects. It tells the system that no
       * object of this class will ever be loaded from or stored to
       * a state file.
       */
    @classdecl TutorialProcessClass, neverSaved;
    @classdecl TutorialViewClass;
/********************************************************************
 *		UI Object Resources
 *******************************************************************/

/********************************************************************
 *		AppResource Resource
 *******************************************************************/
@start AppResource;

  /*
   *    Application Object
   *
   * The very top-level generic object of an application MUST be
   * a GenApplication object. The tutorial.gp file contains the "appobj"
   * statement which indicates that this "TutorialApp" object is in
   * fact the top-level UI object.
   *
   * This object should be in its own resource, as it is all that
   * need be in memory when the application is iconified. As such,
   * its resource should be as small as possible.
   *
   * FoamSubApplicationClass is for the Nokia 9000i Communicator
   * only. It adds special behavior for that platform.
   */
@object FoamSubApplicationClass TutorialApp = {
      /*
       * While the application object isn't shown on the screen,
       * it has a list of VisMonikers for three purposes:
       *   1) The GenPrimary (see below) inherits the moniker
       *      when it comes up on screen.
       *   2) When GeoManager needs to display an icon for the
       *      application, and there's none for it in the Token
       *      Database, it launches the app and sends a message
       *      to the application object to install its list of
       *      monikers in the token database under the
       *      application's token.
       *   3) When the GenPrimary is minimized, it uses the most
       *      appropriate graphical moniker from this list for the
       *      application's icon. If there's an abbreviated-text
       *      moniker in the list, that's used as the icon title.
       *      Else any regular-text moniker is used.
       */
    GI_visMoniker = list { @TutorialTextMoniker };

      /*
       * The GenApplication object has at least one child:
       * the main application window.
       */
    GI_comp = @TutorialPrimary;

      /*
       * The main window should appear on-screen when the application
       * is launched, so place it on the GAGCNLT_WINDOWS GCN list.
       * This causes the application object to bring it on-screen at
       * the appropriate time.
       */
    gcnList( MANUFACTURER_ID_GEOWORKS, GAGCNLT_WINDOWS ) = @TutorialPrimary;
}

@visMoniker TutorialTextMoniker = "C Tutorial";
@localize "Program Title";

@end AppResource;
/********************************************************************
 *		Interface Resource
 * This resource is for miscellaneous UI objects.
 *******************************************************************/
@start Interface;

  /*
   *    Primary window
   *
   * Every application has at least one GenPrimary object.
   * This object serves as the main window of the application.
   * Inside this window, various UI components, such as menus
   * or lists, can be placed.
   */
@object GenPrimaryClass TutorialPrimary  = {
		/*
		 * This window has two children:
		 * the GenView object and the Close button (see below).
		 */
	GI_comp = @TutorialView, @TutorialCloseTrigger;
}

  /*
   *    GenView object
   *
   * This GenView object creates a window where the application can
   * display portions of the document as necessary. As we want this
   * window to be scrollable, the specific UI will create scroll
   * bars with which the user can interact. Whenever a portion of
   * the window needs to be redrawn, the GenView object will
   * invalidate a portion of the window, causing a MSG_META_EXPOSED
   * to be sent to the application. The application will draw the
   * document into the window as requested. The window keeps track
   * of a mask, which is used to clip the application's drawing
   * operations, so that only the invalid portion of the window is
   * drawn to.
   */
@object TutorialViewClass TutorialView = {
      /*
       * Make view scrollable in X and Y and ensure that it never
       * gets larger than the thing being displayed within it.
       */
    GVI_horizAttrs = @default | GVDA_SCROLLABLE
                              | GVDA_NO_LARGER_THAN_CONTENT;
    GVI_vertAttrs  = @default | GVDA_SCROLLABLE
                              | GVDA_NO_LARGER_THAN_CONTENT;

      /*
       * When the contents of this view (i.e. the document) must be
       * updated, the UI should send a MSG_META_EXPOSED to the
       * TutorialProcessClass object.
       */
    GVI_content = process;

      /*
       * Specify the dimensions of the document being displayed
       * within the view.
       */

    GVI_docBounds = {
        0,
        0,
        1000,
        1000
    };
}
	/*
	 *    Close trigger
	 *
	 * On certain systems we should provide a way to exit the
	 * application. On the Nokia 9000i Communicator we have a
	 * close trigger like this one.
	 */
@object GenTriggerClass TutorialCloseTrigger = {
	GI_visMoniker = "Close";

		/*
		 * The next two instance fields are part of the
		 * GenTriggerClass. They specify the recipient object
		 * and the message that will be sent to that object
		 * when this trigger is activated.
		 */
	GTI_destination = @TutorialApp;
	GTI_actionMsg = MSG_FSA_RETURN_TO_LAUNCHER;

		/*
		 * The specific UI uses this combination of hints
		 * to place this trigger on the right side of the
		 * Nokia 9000i Communicator's screen.
		 */
	HINT_SEEK_MENU_BAR;
	HINT_SEEK_REPLY_BAR;
	HINT_SEEK_SLOT = 3;
}
@end Interface;
/********************************************************************
 *		Function Definitions
 *******************************************************************/

/********************************************************************
 *              TutorialDraw
 ********************************************************************
 * SYNOPSIS:	 Redraws the entire document, given a graphics state
 *		 through which to draw.
 * CALLED BY:	 (INTERNAL) TutorialProcess::MSG_META_EXPOSED
 * RETURNS:      void
 * SIDE EFFECTS: Various aspects of the gstate are altered.
 * STRATEGY:     First set the font used by this gstate. Then
 *               set the text color. Using the constant angle lets
 *               rotate the gstate. To finish up, draw the text
 *               text to the gstate.
 *******************************************************************/
void


TutorialDraw( GStateHandle gstate )
  /*
   * gstate - GState to draw to.
   */
{




      /*
       * First change some of the default GState values,
       * such as font and point size.
       */
    GrSetFont( gstate, FID_DTC_URW_SANS, MakeWWFixed( TEXT_POINT_SIZE ) );


      /*
       * Apply a rotation to the transformation matrix,
       * so the text will be drawn at an angle.
       */
    GrApplyRotation( gstate, MakeWWFixed( TEXT_ROTATION ) );


      /*
       * Draw some text onto the document.
       */
    GrDrawText( gstate, TEXT_X_POSITION, TEXT_Y_POSITION,
                "The quick brown fox jumps over the lazy dog.",
                0 );
} /* TutorialDraw */
/********************************************************************
 *		Code for TutorialProcessClass
 *******************************************************************/

/********************************************************************
 *              MSG_META_EXPOSED
 ********************************************************************
 * SYNOPSIS:	 Redraw the recently-exposed portion of the View.
 *               See the Objects Reference book for more information
 *               on this message and its parameters.
 * PARAMETERS:	 WindowHandle win
 * RETURNS:      void
 * SIDE EFFECTS: The invalid region of the window is cleared out.
 * STRATEGY:	 This message is sent by the windowing system when a
 *	    	 portion of the GenView has become invalid, either
 *	    	 because a window that was obscuring it has been moved,
 *	    	 or because someone called GrInvalRect. We redraw the
 *               entire document, after telling the graphics system
 *               we're drawing to the invalid portion of the window.
 *
 *******************************************************************/


@method TutorialProcessClass, MSG_META_EXPOSED
{
      /*
       * gstate - This is a handle to the graphics state
       *          that we'll use to draw to the view.
       */
    GStateHandle gstate;


      /*
       * Get a default graphics state that we can use while drawing.
       */
    gstate = GrCreateState( win );


      /*
       * Start a window update. This tells the windowing system
       * that we are in the process of drawing to the invalid portion
       * of this window. GrBeginUpdate/GrEndUpdate are necessary only
       * when handling MSG_META_EXPOSED. For drawing at other times,
       * all you need do is create a graphics state and draw through it.
       */
    GrBeginUpdate( gstate );

      /*
       * Draw the pattern into the window (pass the GState). Breaking
       * the exposure and general drawing into two routines allows the
       * display to be updated by other routines without having to
       * invalidate the window.
       */
    TutorialDraw( gstate );



      /*
       * Now indicate that we are done drawing to the invalid area
       * and free the gstate.
       */
    GrEndUpdate( gstate );
    GrDestroyState( gstate );
} /* MSG_META_EXPOSED */

/* This is here to work around a bug in the Borland C 5.0 compiler. */
@method TutorialProcessClass, MSG_GEN_PROCESS_CLOSE_APPLICATION
{

    return( @callsuper() );
}
/********************************************************************
 *		Code for TutorialViewClass
 *******************************************************************/

/********************************************************************
 *              MSG_META_KBD_CHAR
 ********************************************************************
 * SYNOPSIS:     We intercept this message to add the scrolling
 *               behavior to the GenView. Normally this would work
 *               in GEOS but the Nokia 9000i Communicator has the
 *               scrolling disabled in GenViewClass.
 * PARAMETERS:   word character
 *               word flags
 *               word state
 * RETURNS:      void
 * SIDE EFFECTS: none
 * STRATEGY:     We first check the parameters to see if this
 *               keypress is one we are interested in. It has to be
 *               a "control" key, and must not be a key release
 *               (i.e. the user released the key after holding it).
 *               If both of these conditions are true we can then
 *               use a switch statement to see which key is being
 *               pressed and send the appropriate message to the
 *               GenView object.
 *******************************************************************/


@method TutorialViewClass, MSG_META_KBD_CHAR
{
      /*
       * theChar - A copy of the character with only the
       *           low byte. The high byte of character
       *           has some extra flags we don't need here.
       */
    byte        theChar;

      /*
       * Arrow keys and scroll buttons are control characters.
       * We handle first press and repeat presses of those keys.
       */
    if ( ( ( character >> 8 ) == CS_CONTROL ) &&
         ( flags & ( CF_FIRST_PRESS | CF_REPEAT_PRESS ) ) ) {
        theChar = character & 0xFF;

        switch ( theChar ) {

        case VC_PREVIOUS:
              /* This handles the Page Up key. */
            @send self::MSG_GEN_VIEW_SCROLL_PAGE_UP();
            break;

        case VC_UP:
              /* This handles the up arrow key. */
            @send self::MSG_GEN_VIEW_SCROLL_UP();
            break;

        case VC_NEXT:
              /* This handles the down arrow key. */
            @send self::MSG_GEN_VIEW_SCROLL_PAGE_DOWN();
            break;

        case VC_DOWN:
              /* This handles the up arrow key. */
            @send self::MSG_GEN_VIEW_SCROLL_DOWN();
            break;

        case VC_RIGHT:
              /* This handles the right arrow key. */
            @send self::MSG_GEN_VIEW_SCROLL_RIGHT();
            break;

        case VC_LEFT:
              /* This handles the left arrow key. */
            @send self::MSG_GEN_VIEW_SCROLL_LEFT();
            break;

        default:

              /*
               * Pass on other control chars to default handler.
               */
            @callsuper();
        } /* switch */
    } else {
          /*
           * Pass on all other chars to default handler.
           */
        @callsuper();
    }
} /* MSG_META_KBD_CHAR */

This document is a single-page version of a a multi-page document, suitable for easy printing.