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
2 TUTORIAL.GP Changes
3 TUTORIAL.GOC Changes
3.1 Subclassing the View
3.2 Adding Scrolling Behavior
3.3 Drawing the Content
4 Swat: Setting Breakpoints
5 Swat: Backtraces
6 Exercises Left for the Reader
7 Source 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.
exit tutorial
to exit the earlier version of the application; (remember to use
Ctrl+C
to gain control back in your Swat window).
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
.
send tutorial
in your Swat window to send the newly compiled version to the emulator.
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.)
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.
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.
The changes to TUTORIAL.GOC include:
GenViewClass
called
TutorialViewClass
so that you can add scrolling behavior to the view window;MSG_META_KBD_CHAR
in TutorialViewClass
so that the user can scroll the window by pressing the arrow and PageUp/Down keys; and
MSG_META_EXPOSED
so that the system knows how to redraw the window's contents whenever the contents change due to the user pressing the scroll button.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
.
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.
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.)
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.
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.
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:
where
command to generate the backtrace and the
save
command to save it out.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:
process
object to a
VisContent
object. Do this by creating a separate resource for the
VisContent
object and have the
GenView
object point to this new object.(See the
\PCGEOS\APPL\SDK_C\VIS\
sample applications for reference.) Then intercept
MSG_VIS_DRAW
for the new content object and perform the drawing there.
VisClass
object and add it as a child of the
VisContent
you created in the previous step. Have this
Vis
object intercept
MSG_VIS_DRAW
and perform the drawing there.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.
| GEOS SDK TechDocs | | | Tutorial Part 2: A New Application | Source Code With Changes