Tutorial Part 3: Adding Procedural Code

Up: GEOS SDK TechDocs| Up| Down| Prev: Tutorial Part 2: A New Application | Next: Source Code With Changes

In this chapter, you'll add some procedural code to your Tutorial application which will draw a string of text to the viewing window. You'll explore the application's new code using Swat and learn how to set breakpoints and step through code.


1: Adding Code

At the end of this chapter you will find a complete code listing for this application. Pieces of code which have been added or changed since the previous chapter are in bold. Follow these steps to edit, re-compile and run your new application.

  1. Add the new pieces of code using your favorite text editor. If you don't want to type it the source code by hand, follow the links to the revised Tutorial.gp and Tutorial.goc, then copy and paste the new code into tutorial.gp and tutorial.goc.
  2. In your Swat window, type exit tutorial to exit the earlier version of the application; (remember to use Ctrl+C to gain control back in your Swat window).
  3. In your command window, type pmake to compile the application (make sure you are still in your proper working directory). You may recall that in the previous chapter, you also had to use mkmf to create a makefile and a dependencies file. Those files will still work; we need only re-compile using pmake .
  4. Once you've successfully compiled, type send tutorial in your Swat window to send the newly compiled version to the emulator.
  5. Type run tutorial in the Swat window to run the new version of the application on the emulator.

Your code now lets your application have graphics in its view and allows the user to press the scroll buttons to scroll the view (see the image below). You have the beginnings of a typical GEOS application which displays its contents in a GenView object. (To learn more about views and displaying visual objects, see the \PCGEOS\APPL\SDK_C\VIEW\ and \PCGEOS\APPL\SDK_C\VIS\ sample applications.)

Image of N9000 screen
with text running across screen.
Figure 1: "Tutorial" application with added code.

This is how your application will look after you type in the additional pieces of code. Notice that the main window is no longer blank; it now contains a string of text and a scrolling bar.

The next sections take a closer look at the code you've just added.


2: TUTORIAL.GP Changes

You added one line to your TUTORIAL.GP file.

export TutorialViewClass

TutorialViewClass is a new class that you'll define in your TUTORIAL.GOC file. Whenever you define a new class (with the exception of your process class), you'll need to export it in the .GP file so that Glue knows about the class when it builds the application.


3: TUTORIAL.GOC Changes

The changes to TUTORIAL.GOC include:

Before we look at the new pieces of code, let's discuss what we mean by messages. A message is simply a set of procedural code that gets called when a specific event occurs. For example, when the user presses a button, the system sends out a specific message to a specific object; by sending out a message, the system is calling the handler or method for that message.

A new class inherits the behavior and characteristics (messages and instance data) of its parent class. To add custom behavior to objects of your new class, either define your own message(s) for your new class or intercept inherited messages (which is what you're doing with your Tutorial application). To intercept a message, you simply write your own handler for it and the system will call that piece of code that when the message is sent.

Note that by Geoworks' naming conventions, all messages begin with "MSG_" followed by the name of the message's class. For example, MSG_META_EXPOSED and MSG_META_KBD_CHAR are both defined for MetaClass.

3.1: TUTORIAL.GOC Changes: Subclassing the View

The first step is to create a new subclass of GenViewClass.

@class TutorialViewClass, GenViewClass;
@endc;
@classdecl TutorialViewClass;

You use the @class and @endc keywords to define your new class and the @classdecl keyword to declare it.

@object TutorialViewClass TutorialView = { ... 

Next, you declare TutorialView as an object of your new subclass, TutorialViewClass (instead of GenViewClass).

	GVI_horizAttrs  = @default |
		GVDA_SCROLLABLE |
		GVDA_NO_LARGER_THAN_CONTENT;
	GVI_vertAttrs  = @default |
		GVDA_SCROLLABLE |
		GVDA_NO_LARGER_THAN_CONTENT;

Setting the GVDA_SCROLLABLE flag in the view's GVI_...Attrs fields mkaes the content scrollable.

	GVI_docBounds = { 0, 0, 1000, 1000 };

The GVI_docBounds field sets the dimensions of the scrollable area. The first two coordinates are the top and left bounds; the last two coordinates are the right and bottom bounds.

3.2: TUTORIAL.GOC Changes: Adding Scrolling Behavior

To add scrolling behavior, TutorialViewClass needs to intercept MSG_META_KBD_CHAR.

@method TutorialProcessClass, MSG_META_KBD_CHAR {
...
}

The method for this message is straightforward. It tests to make sure the key pressed is either an arrow or PageUp or PageDown key. It then takes the key press value and handles it through a switch statement.

@send self::MSG_GEN_VIEW_SCROLL...();

Notice the syntax for sending a message programmatically. The @send keyword causes the system to place the message in the recipient's event queue. In this case, the recipient object is the calling object. In other words, TutorialView is sending a message to itself. The keyword for sending a message to yourself is, appropriately enough, self; if you were sending the message to another object, you would use the name of the recipient object instead. (@send is used when the message does not return a value; if the message returns a value or needs immediate handling, you would use the keyword @call. For more information on sending messages, see the GEOS Programming chapter.)

3.3: TUTORIAL.GOC Changes: Drawing the Content

To specify how the system should draw the content in your view, you need to intercept MSG_META_EXPOSED.

@method TutorialProcessClass, MSG_META_EXPOSED {

According to its documentation, MSG_META_EXPOSED takes one argument: the window handle of the window to draw to. In this case, that window is the view.

When you draw the contents of a view, you need to create a graphics data structure called a GState. A GState contains information about a window's graphics state or "gstate;" for example, its current drawing color, its current drawing font, etc.

	gstate = GrCreateState( win );

Once you've created a GState, you can begin drawing. The following code begins updating the view, then calls TutorialDraw() to draw some text to the view, then ends the update and destroys the GState :

	GrBeginUpdate( gstate );
	TutorialDraw( gstate );
	GrEndUpdate( gstate );
	GrDestroyState( gstate );

All drawing routines (those starting with Gr..()) take a GStateHandle as an argument.


4: Swat: Setting Breakpoints

Now that your application has some procedural code, you can use Swat to set breakpoints and step through the code line by line. By now, you should have Tutorial running on the emulator. Type Ctrl-C to regain control in the Swat window. After halting the target emulator you should see the following:

GEOS Halted
Stopped in DOSIdleHook, address 2522h:109dh
DOSIdleHook+16: INT 40 (28h)
(geos:0) 5 =>

Before setting a breakpoint in your code, you need to switch to your application's thread so that Swat will recognize your application's variable, class and function names. To do this, enter the name of your application's thread: tutorial .

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

Next, you're going to set a breakpoint in the method for TutorialProcessClass' MSG_META_EXPOSED. The easiest way to set a breakpoint in a method is to first use the methods command which lists all methods for a class; the -p argument specifies the process class.

[tutorial:0] 6 => methods -p
  MSG_GEN_PROCESS_CLOSE_APPLICATION     (@2), TUTORIALPROCESSGEN_PROCESS_CLOSE_A
PPLICATION
                     MSG_META_EXPOSED     (@4), TUTORIALPROCESSMETA_EXPOSED

Now that you have a list of all the methods for the process class, you can refer to a particular message using the shortcuts Swat gives you. To set a breakpoint, you use the commands stop or brk.

[tutorial:0] 7 => stop @4
brk5
[tutorial:0] 8 =>

"brk5" indicates that you've sucessfully set the breakpoint. Swat should now halt whenever this routine is called. The number "5" indicates that this is your fifth breakpoint; you will be able to manipulate this breakpoint later by referring to it by this number. (Swat automatically sets breakpoints 1 through 4; we'll look at those later.)

To test the breakpoint, continue by typing c in the Swat window, then scroll the view on the target emulator. The system will tell the process object that it needs to redraw its content, and this should trigger your breakpoint:

[tutorial:0] 8 => c
Breakpoint 5
Stopped in TUTORIALPROCESSMETA_EXPOSED, line 382, "c:/pcgeos/Appl/Tutorial/TUTORIAL.
GOC"
    gstate = GrCreateState( win );
(tutorial:0) 9 =>

Swat tells you it broke at Breakpoint 5. (This information is useful when you've set several breakpoints.) Swat also shows you which statement in the program is about to be executed: gstate = GrCreateState( win ) .

Next, you'll use the srcwin command to display your source code.

(tutorial:0) 9 => srcwin 15
(tutorial:0) 10 =>

At this point, the bottom fifteen lines of your Swat window should display the source code; the highlighted line is the line about to be executed on the emulator. To the left side of the source code are line numbers.

To move around the source code file, use the Page Up , Page Down , left arrow , and right arrow keys. You can even set (and unset) breakpoints by clicking on the line numbers with the mouse.

Next you'll use the source-stepper command sstep to step through your source code line by line. At each line of code, you can step to the next line, step into a routine being called, or finish the routine.

(tutorial:0) 10 => sstep
Stepping in c:/pcgeos/Appl/Tutorial/TUTORIAL.GOC...
  382:    gstate = GrCreateState( win );

You are about to execute the GrCreateState() command. Press the n key.

  391:    GrBeginUpdate( gstate );

Notice that the highlight in the srcwin has moved to GrBeginUpdate() , the next line to be executed. Let's continue for another few steps and then get out of sstep mode. Press n three times to step through three more lines of code, then press q or the space bar to quit out of sstep mode.

  399:    TutorialDraw( gstate );
  405:    GrEndUpdate( gstate );
  406:    GrDestroyState( gstate );
(tutorial:0) 11 =>

To display a list of the variables local to a routine, use the locals command. To get a continuous display of local variables, use the localwin command (for example, localwin 15). You can use the print command to learn the value of any variable, and you can change the value of a variable using the assign command.


5: Swat: Backtraces

Backtraces are useful when you're figuring out where your program crashed. Though your program hasn't crashed, it's useful to test the where Swat command.

(tutorial:0) 11 => where
* 1:  far TUTORIALPROCESSMETA_EXPOSED(win = 52d0h), TUTORIAL.GOC:406
  3: call tutorial:0{TutorialProcessClass}MSG_META_EXPOSED(52d0h 0000h 0000h 0000h) (@
5, ^l52f0h:0000h)
------------------------------------------------------------------------------
The event queue for "tutorial:0" currently holds:
send tutorial:0{TutorialProcessClass}MSG_META_MOUSE_PTR(00d9h 0095h 0100h 0000h) (@6,
^l5370h:0000h)
send tutorial:0{TutorialProcessClass}MSG_META_KBD_CHAR(ff91h 0001h 5000h 0000h) (@7, ^
l5370h:0000h)
===================================================================================

From the first line, you can see that this thread is executing TUTORIALPROCESSMETA_EXPOSED() . The next line tells you that it is doing so to handle a MSG_META_EXPOSED which was sent to the process object.

The asterisk at line 1 indicates the current frame that Swat is examining. To examine another frame of the backtrace, use the frame command.

(tutorial:0) 12 => frame 3
CallCHandler+4: MOV BX, WORD SS:[12h]
(tutorial:0) 13 => 

At this point, the srcwin goes blank because Swat has switched to another level of examination for which you don't have source code. Note that frame doesn't change which code the target is executing, just which level Swat is looking at. If you use the where command again, you can see that the asterisk has moved to the second line. Type c to allow the program to continue; execution will then halt again since you still have a breakpoint set in MSG_META_EXPOSED.

(tutorial:0) 16 => c
Breakpoint 5
Stopped in TUTORIALPROCESSMETA_EXPOSED, line 382, "c:/pcgeos/Appl/SDK_C/TUTORIAL/TUTORIAL.
GOC"
    gstate = GrCreateState( win );
(tutorial:0) 17 =>

It would be nice to disable this breakpoint temporarily since you don't need it right now. Before you do that, use the brk list command to get a list of the current set of breakpoints:

(tutorial:0) 17 => brk list
Num S Address                        Patient    Command/Condition
1   E loader::kcode::LoaderError     all        echo Loader death due to [penum
LoaderStrings [read-reg ax]]
                                                  expr 1
2   E geos::kcode::FatalError        all
                                                  why
                                                  assign {word
 [address-kernel-internal errorFlag]} 0
                                                  expr 1
3   E geos::kcode::WarningNotice     all        why-warning
4   E geos::kcode::CWARNINGNOTICE    all        why-warning
5   E <T::TUTORIALPROCESSMETA_EXPOSED+4 all        halt
(tutorial:0) 18 =>

For each listed breakpoint, Swat displays where they break and what Swat commands which will be executed when the breakpoint is hit. The first breakpoint prints out an error message whenever you enter a routine called LoaderError() . The second breakpoint stops when execution has entered the GEOS kernel routine FatalError() and executes the why Swat command. Why returns an exiting error code and a string that pertains to the cause of the crash. Breakpoints 3 and 4 won't halt execution but will execute the why-warning Swat command, which echoes a warning message to the Swat screen. Swat sets these four breakpoints automatically. The fifth breakpoint is the one you set. It causes the system to halt when execution is at the specified address.

You can delete and disable breakpoints by using the brk delete and brk disable commands.

(tutorial:0) 18 => brk disable 5

Once you've disabled breakpoint 5, you can re-enable it by typing en 5 ("en" being short for "enable").

Other Swat commands you might want to try:

objwatch
shows you all messages sent to an object.
help
presents an interactive menu for retrieving help on all of the Swat commands.
alias
allows you to set up aliases for simple Swat commands.
save
saves the last 1000 lines of your Swat session to a text file. If you're encountering a crash bug in your program and enter a question to one of the GEOS development forums, you will often be asked to provide a backtrace of the crash. Use the where command to generate the backtrace and the save command to save it out.

6: Exercises Left for the Reader

The Tutorial sample application that you created in this Tutorial is very basic but should help introduce you to the basics of GOC and the SDK Tools. To continue learning more about the language and the tools, we encourage you to compile, run and Swat through any of the other sample applications on the SDK and/or try some of the following exercises:

This tutorial and the exercises mentioned above should give you an introduction to the power and flexibility of GEOS. As you continue exploring the API and the tools, don't forget to take advantage of the many resources at hand: the SDK comes with a complete set of documentation and our web site features a searchable knowledgebase, an FAQ, and other self-help resources. Check out the Geoworks Developer Relations home page.


Up: GEOS SDK TechDocs | Up| Down| Prev: Tutorial Part 2: A New Application | Next: Source Code With Changes