\begindata{text,539494632} \textdsversion{12} \template{default} \define{global } \define{footnote attr:[Flags OverBar Int Set] attr:[FontSize PreviousFontSize Point -2]} \define{programexample } \define{itemize } \define{enumerate } \formatnote{\chapter{Example 1: program }} Creating a class and an application This section describes how to create a simple class and how to create an application program that uses the class. The application program will create a new window, create an instance of the class, and set the instance in the window. Then the instance of the class will draw the string \italic{hello world} in the window's center. This example program illustrates the following activities: \ \itemize{\leftindent{declaring a class defining class procedures and methods drawing, using the Andrew Toolkit class \italic{Graphic} compiling in the Andrew Toolkit environment creating and running a stand-alone application program }} After reading Example1, you will know the very basic program structure needed to create a simple Andrew Toolkit class and a stand-alone application program that uses an object that is an instance of that class. Later examples will introduce the structures you need in order to build an object that responds to user input (e.g., mouse, keyboard, menus), reads and writes to files, and so on. \ The discussion that follows presents a step-by-step description of how to write the example program. If you were to follow the steps, you would produce a program, called \italic{helloworldapp}, in five files: \ \itemize{\leftindent{a hwview.H file -- will contain the class definition for the \italic{helloworldview} class, the class whose instances draw the string \italic{hello world}. The class \italic{helloworldview} will be a subclass of the Andrew Toolkit class \italic{view}. \ a hwview.C file -- will contain statements that import Andrew Toolkit classes and define the class \italic{helloworldview}'s methods and class procedures. \ a hwapp.H file -- will contain the class definition for the application program that will display an instance of the \italic{helloworldview} class in a window on the workstation. By convention, Andrew Toolkit application modules are named \italic{<x>app}, where \italic{<x>} is the name of the application or an abbreviation for it (e.g., \italic{helloworld}) and \italic{app} is an abbreviation for the class \italic{application}. \ a helloahwapp.C file -- will contain declarations needed by the Andrew Toolkit linking and loading facilities as well the definition of an application method that creates an instance of \italic{helloworldview}, creates a window, puts the object in the window, and enters an interaction loop. \ Imakefile -- will contain the directions for compiling, linking and loading the modules. \ }} For a complete listing of these files, see $ANDREWDIR/examples/ex1/*. On a first reading of this section, you may find it useful to skim the program listing, then refer to the listing when needed as you study how to build the program. The compiled program is also available in the directory /usr/andrew/examples/ex1. \ Although the discussion of the steps refers directly to this example, the information applies generally to the creation of any class or inset that will be used in a \indexi{Stand-alone application} and to the creation of any stand-alone application. \ \section{Running the example program} Before reading the discussion of the example program, you may find it helpful to run the program on your workstation. \formatnote{\bold{Action 1:} \bold{command }prompt type \formatnote{To run the program, at the \bold{\leftindent{/usr/andrew/examples/ex1/helloworld}} and press the Enter key. } \bold{Response: }The program will produce a window with \italic{hello world} centered in the body as in this figure \center{ \ \begindata{raster,539010728} 2 0 68266 68266 0 0 183 138 bits 539010728 183 138 zi | zh02 | 2a/aa$aaa4 | zh0a | 2a/aa$aaa4 | 12492492492492 49249249249249 09249249249249 24924924924924 24924924924924 92492492492492 11041041041041 04104104104104 2228a28a28a28a 28a28a28a28a28 09451451451451 45145145145145 1228a28a28a28a 28a28a28a28a28 24f2105efa1041 04104785e84107 12f4a52e38a52a 52a52bd2f294aa 0472124f7d1244 91124791e44915 28f4a49e384929 24a493a4f124a3 057f178f7afbef 7bcf7796e48915 287faede3cccef 3763b3afe92425 0573ddef79eef7 6e7bd79de4494d 12779fce3bcf77 7ef383bce9!22 24f3dc5eb9eef7 4f7bd7dee49114 24924924924924 92492492492492 49249249249249 10410410410410 a28a28a28a28a2 14514514514514 a28a28a28a28a2 11610410410410 a58a52a52a52a5 11612449112449 a6ca4924a4!92 55d1c753492044 a2862aeae48a92 55ed7315185124 ea8aaaa6e28a12 d96c558d944144 924a | 4914 | 24a2 | 4114 | 8a22 | 514c | 8a12 | 4144 | !2a | 1144 | 4a0a | 9154 | !22 | 948c | 4252 | 9104 | 12779e8f3bde3b 097bdc5e79cf7f 2473afcf3aee19 09Gcfbf7d795d 12509080!4a12 248a2455209144 021049224a4228 294a9249249485 04222124911128 29494a110a4885 0224114a512252 2912a420889488 0449094a522225 29224422094948 2adab5daf6aaab !555a552a#aaa5 zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | ee77a39cf244a2 cf7397bee42915 ae77a3cfe94224 87c7!d772294d a8aa4408549210 221129450244a5 94a44128548884 22129485212529 44a412288a4842 29094492509294 40a49244852210 9511249250494a !2488490a9210 !492510a124a5 !555ad6ad!555d 5556!aaa6"aaab 22cb72d2112a12 7954550fa51564 a5a6b3a2aadab2 21494d55459544 1552a4a15214a8 4209111424a205 94!a4a14888a8 !210914!251214 148a5222904824 a25088944a9289 84852521240924 51284894895249 8a!21!2241248a 21!4a49489442 "5556ab5d56ea | 5552aa94 | 24aa | 9214 | 44a2 | 9114 | !4a | 1094 | a242 | 94 | a24a | 1114 | 4a22 | 214a | 24 | 5114 | zi | zi | zi | zi | zi | zi | zi | k0180g1980k30 k0180g1980k30 k0180g1980k30 k0180g1980k30 k01bc1e1987c0 k01fe3f198fe0 k01c661998c60 k018661999830 k01867f999830 k018660199830 k018660199830 k018671998c60 k01863f998fe0 k01861e1987c0 zi | zi | zi | v04l | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | zi | v04l | zi | 06l | 06l | 06l | 06l | 18c61f0db0f6l 18c63f8db1fel 18c6318e318el 0ccc60cc3306l 0ccc60cc3306l 0d2c60cc3306l 052860cc3306l 0738318c318el 03303f8c31fel 03301f0c30f6l | | | | | | | | | | zi | zi | zi | zi | zi | zi | zi | zi | zi | \enddata{raster, 539010728} \view{rasterview,539010728,32,0,0}.} \bold{Action 2:} Re-shape the program's window. \bold{Response:} The object will respond to an update request and redraw \italic{hello world }in the center. \bold{Action 3: }Click with a mouse button. \bold{Response: }The program will make no response. This simple object does not respond to keyboard or mouse input and has only the Quit menu item. Later examples will illustrate how to extend the program so that the view responds to user input. \bold{Action 4: }To quit the program, select \bold{Quit} from the \bold{helloworld} menu. \bold{Response: }The program will disappear from the screen. }\ \begindata{bp,539549576} Version 2 n 0 \enddata{bp,539549576} \view{bpv,539549576,19,0,0} \section{Creating a class} Creating a class \indexi{Class++Creating} in the Andrew Toolkit involves two steps: \ \enumerate{ \leftindent{Declaring the class as a subclass of an Andrew Toolkit class Writing class procedures and methods for the class. \ }} \subsection{The Andrew Toolkit class View} \indexi{View} \indexi{Class++View } In the next section, we will define the class \italic{helloworldview} to be a subclass of the Andrew Toolkit class \italic{view}. The class \italic{view} is at the heart of the Andrew Toolkit. It provides the methods, class procedures and data structures needed to (1) display a data object in a window, (2) request display updates and respond to such requests, and (3) respond to mouse and keyboard inputs. Thus, to create any class that interacts with the user, you should declare it as a subclass of \italic{view}. \ To simplify the exposition, Example1 does not include a data object and does not not respond to mouse and keyboard inputs, but it does respond to requests to update the display. In general, you will want to create a view-data object pair (called an inset) or some hierarchy of insets, and an application module to run/display the program. Insets will be discussed in greater detail in Examples 10 and 11. \ \subsection{Choosing a name for a class} \indexi{Class++Naming} \indexi{View++Naming} The first step in creating a class is to pick a name for the class. The name is important for two reasons. First, most Toolkit objects are loaded dynamically. \indexi{Dynamic loading} When the Andrew Toolkit encounters the name of a class to load dynamically, it searches for the class along a class path, a path that specifies a list of directories to search. Thus, if you want to avoid the Toolkit finding the wrong class, the name you pick should be unique and not conflict with already existing ones. The second reason the name is important is that, for some classes, in particular, for classes that are data objects, \indexi{Data object++Naming} the user will sometimes type the class name in order to obtain an instance of it. For example, the user types the name of a class in order to dynamically load an instance of it into the Andrew Toolkit-based editor, \bold{ez}. In such cases, the name should be memorable for users. Since the class in Example 1 is not a data object, it need only be unique, not memorable. We chose the class name \italic{helloworldview}. \ You should also pick a filename for the class. The easiest filename to use is, of course, the class name itself. However, for portability, filenames should be no longer than eight characters. If the class name is longer than eight letters, you should pick a shorter abbreviation to use as the filename. We chose the filename \italic{hwview} for the class \italic{helloworldview}. (The abbreviation is used only for files; the methods for this class and the name used to invoke it will still be \italic{helloworldview}.) \indexi{Class++Filename} There is no direct way to tell if the class name you chose is already being used. However, you can see whether the \italic{filename} you picked is on your class path. \indexi{Class path} In the \bold{command}, type: \ \leftindent{\bold{whichdo \italic{<your class filename>}}} The command \italic{whichdo} \indexi{ \italic{whichdo}} (\italic{which} \italic{d}ynamic \italic{o}bject) is analogous to the \italic{Unix 4.2 BSD} command \italic{which} (see \bold{help which} for more information); it takes a list of class names and looks for the files which the Andrew Toolkit would dynamically load in response to the names. Each argument is expanded if it is aliased, and searched for along the dynamic class path, \smaller{CLASSPATH}. Both aliases and path are taken from the user's \italic{.cshrc} file. The following is the recommended class path for inclusion in a \italic{.cshrc}.: \ \programexample{\leftindent{setenv CLASSPATH .:$ANDREWDIR/lib/atk} } With this class path, the Andrew Toolkit dynamic object search will look in the \italic{current directory} and in $ANDREWDIR/\italic{lib/atk}. If you do not have a class path defined in your \italic{.cshrc}, you will probably want to define one. The class path defaults to $ANDREWDIR\italic{/lib/atk}. \indexi{Class path++Default} \subsection{Declaring a class} \indexi{Class++Declaring} \indexi{Class declaration} To create a class, you should declare the class in a \italic{.H}, or header file, that has the filename you have chosen for your class. (Note that the file extension \indexi{File extensions} is by convention \bold{ .H}, not\bold{ .h}). Thus the class declaration for the class \italic{helloworldview} is in the file \italic{hwview.H.} The following is the declaration for the class \italic{helloworldview}, from the file hellov.ch: \example{class helloworldview: public view \{ public: virtual ATKregistryEntry *ATKregistry(); void FullUpdate(enum view_UpdateType type, \ long left, long top, long width, long height); \};} The declaration specifies that a class, named \italic{helloworldview,} is to be a subclass of the Andrew Toolkit class \italic{view}. One method, \italic{FullUpdate}, will override \indexi{Override} \indexi{Methods++Overriding} the class \italic{view}'s \italic{FullUpdate} method, which it otherwise would have inherited. No other methods, special class procedures, or data are necessary in the class declaration for this simple example. \ \subsection{Class hierarchies and inheritance} \indexi{Class hierarchy} \indexi{Inheritance} \indexi{Class++Hierarchy} In the Andrew Toolkit, classes form a hierarchy. Derived classes \indexi{Subclass} inherit the methods and data structures of their parent, or "base" class. \indexi{Superclass} Although \italic{helloworldview} declares no methods or data, it inherits the methods and data from its parent base classes. The class \italic{view}, \italic{helloworldview}'s immediate parent, is part of the class hierarchy, \italic{basicobject}, \italic{observable}, \italic{view}, depicted as \formatnote{ \center{ATK | v traced | v observable | v view | v helloworldview} } Therefore, \italic{helloworldview} inherits the methods and data structures of \italic{ATK}, \italic{traced}\italic{, observable} and \italic{view}. For example, \italic{view} provides the method\italic{ Hit}, which will be called when the user clicks with the mouse on the left or right button. Because \italic{helloworldview} does not override \italic{Hit}, it will inherit view's Hit method. So, when the user clicks with the mouse in a window containing a \italic{helloworldview} object, the Andrew Toolkit \italic{Interaction Manager}, which manages interaction events, will call the \italic{Hit} method \italic{helloworldview} inherits from view, which does nothing in response to a mouse hit, so the \italic{helloworldview} object in this example will not respond to mouse hits. Example 3 will show how to override \italic{view}'s method so that the class \italic{helloworldview's} instances will respond to mouse hits. \ In general, you will declare a class as derived from a base class. \indexi{Class declaration} \indexi{Subclass} \indexi{Superclass} Fail all else, your object can derive from the \italic{ATK} class at the top of the Andrew Toolkit class hierarchy. \ \subsection{Accessing data structures for a class} \indexi{Data structure++Access} You access a field defined in a subclass \indexi{Subclass} in the same way you access one in a normal C structure. For example, given a pointer, \indexi{Class++Pointer to} \italic{hwv}, to the object's \italic{helloworldview struct}, you would write \italic{hwv->view} to access the field \italic{view}. \formatnote{(Later examples will introduce examples in which accessing fields in the structure is useful.}) To access a field defined in a superclass, \indexi{Superclass} you should use the class' access method for the field if one is defined. An access method \indexi{Class++Access method} is simply an encapsulation of a reference to the field. By using the access method, you avoid making your subclass dependent on implementation details of the Andrew Toolkit (This is especially important since the implementation might change). If an access method for the field is not defined and you really need to access it, you usually can because most fields are have the "public" attribute. For example, if you needed to find out how many observers a particular \italic{helloworldview} object had, you might need to access the class \italic{observable}'s \italic{nObservers} field. There is no access method defined for it. (Since access methods are defined for most fields which you will need to access, you should spend some time thinking about whether there is a better way to do what you want to do). Given a pointer, \italic{hwv}, to the object's \italic{helloworldview struct}, you would write \italic{hwv->nObservers}. \ \subsection{Writing class methods} \indexi{Class++Methods} \indexi{Methods} Up to this point, we have seen how to declare a class. In this section, we discuss how to write class methods and illustrate it by writing a class method for \italic{helloworldview} that allows it to respond to requests from the Andrew Toolkit \italic{Interaction Manager} to update the screen. \ A \italic{method} is like a C procedure, except for how it is invoked. The method name is treatd like a field of an object of that class. Thus the \italic{Update} method of object \italic{hwv} is called with the syntax \example{hwv->Update(...)} If the object itself does not define the method, the method is used from the nearest base class which does define the method. In the case of \italic{hwv->Update}, the method actually called would be that provided by the \italic{view} class. Methods increase the understandability of your code because they allow you to create useful data abstractions \indexi{Data abstraction} that hide implementation details. For example, suppose you are writing an application in which you defined an abstract data type, \indexi{Abstract data types} linked list, consisting of the data \italic{Element} and the operations, \italic{InsertElement}, \italic{DeleteElement} and so forth. At the level of data abstractions, you would be dealing with a single data element and a set of operations. In a conventional programming language like C, however, you might need to create several actual data types and duplicate sets of procedures to implement a single abstract data type. For example, suppose that you needed to work with both strings and integers. In that case, you would need to define two types of arrays, an array of \italic{int}s and an array of \italic{char*}, and create two procedures for the \italic{InsertElement} operation, the one \italic{InsertInteger} and the other \italic{InsertString}. When you called these procedures, you would use the two different procedure names. Thus, in the implementation, you lose the data abstraction. An object-oriented system allows you keep the useful abstract representation. You would still need to \italic{write} two methods, one for integers and one for strings. But you could set your program up so that you could \italic{use the same method name}, for example, \italic{InsertElement}, to invoke both methods. \indexi{Methods++Naming} \paragraph{Calling a method} \indexi{Methods++Calling} The call to a method is actually an indirect call via the list of methods attached to an instance of the class. Thus, when you call \italic{hwv->}\italic{MoveTo}, the \italic{MoveTo} method actually called is in a field of a list pointed to from the \italic{hwv} object. In general, for any object \italic{x} in \italic{classx}, (\italic{i.e.}, class\italic{ classx *x)}, you call \italic{methodname (x, x->methodname(<parameters>)} in order to call either a method for object x or a method for any of \italic{x}'s superclasses. Thus, for object \italic{hwv} in the class \italic{helloworldview}, you write \italic{hwv->}\italic{GetVisualBounds(<parameters>)} to call the \italic{view} method \italic{GetVisualBounds}. \ \subsection{Writing a class method for full update requests} \indexi{Full update} \indexi{Methods++Full update} When you subclass an already existing Andrew Toolkit class, you will want to write methods that respond to the requests for which the class provides methods. For example, when you subclass \indexi{Subclass} the Andrew Toolkit class, \italic{view}, you will typically want to write methods that respond to requests to update the screen, to handle keyboard input, and so forth. In this example, \italic{helloworldview}, we will write a method that responds to requests to update the screen. Later examples will introduce further \italic{view} methods. \ Whenever the user takes an action that requires the \italic{helloworldview} object's window to be redrawn, the Andrew Toolkit \italic{Interaction Manager} will call the \italic{FullUpdate} method. The method should do whatever it must do to redraw the display. \indexi{Redraw} In this example, when \italic{helloworldview's FullUpdate} gets called, we would like it to draw the string \italic{hello world} in the center of the window. \ To write the \italic{FullUpdate} method, you should declare it in a \italic{.C} file that has the same name as your class. The declaration for the \italic{helloworldview}'s \italic{FullUpdate} method is in the file \italic{hwview}\italic{.c.} The following is the \italic{FullUpdate} method in its entirety, followed by a detailed explanation of its various parts: \ \programexample{ }\example{\programexample{ void \ helloworldview::FullUpdate(enum view_UpdateType long left, long top, long type, \ width, long height) \{ int x,y; struct rectangle VisualRect; \ GetVisualBounds(&VisualRect); x = rectangle_Left(&VisualRect) + rectangle_Width(&VisualRect)/2; y = rectangle_Top(&VisualRect) + rectangle_Height(&VisualRect)/2; MoveTo(x,y); DrawString("hello world", graphic_BETWEENTOPANDBASELINE | graphic_BETWEENLEFTANDRIGHT); \}} } \paragraph{Parameters and method definitions} Whenever you override a superclass' method, you must use the same parameters in the method definition as in the superclass. \indexi{Overrides} \indexi{Superclass} \indexi{Parameters} \indexi{Methods++Parameters} \indexi{Methods++Overrides} For example, the following are the parameters for view's \italic{FullUpdate} method: \ \programexample{\leftindent{enum view_UpdateType type \ long left \ long top \ long width \ long height}} The \italic{FullUpdate} method has five parameters: \italic{type}, the type of redraw and \italic{left}, \italic{top}, \italic{width} and \italic{height}, the limits of what needs to be redrawn. The last five parameters allow you to optimize the redraw. We will ignore them in this simple example. \ \paragraph{Drawing on the screen: The class 'graphic'} \indexi{Drawing} \indexi{Graphic} \indexi{Class++Graphic} Responding for a request to update the screen requires drawing on the screen. The Andrew Toolkit has a class, \italic{graphic}, that provides the class procedures and methods necessary for drawing. Thus, to understand how to do a \italic{FullUpdate}, it is necessary to introduce some graphic concepts. \ The class \italic{graphic} provides an output interface to hardware-dependent window management systems. \indexi{Window managers} As an application programmer, you should understand why application programs should not display their pictures directly to an underlying window management system: application programs must often be ported to other workstations that will eventually be deployed. The workstations often have similar, but not identical display capabilities and the hardware can be significantly different; the underlying window manager may be different. To insure portability \indexi{Application program++Portability} of your application, you should never make direct calls to an underlying window management system; you should always use the \italic{graphic} class procedures and methods; doing so will maximize the device independence and portabilty of your application program. \ You should use instances of the class \italic{graphic} to do output to workstation displays. For example, to draw text and put box around it, you would make calls to the methods and class procedures provided by the class \italic{graphic}. The class graphic provides methods for drawing lines, shapes, and text. It also provides methods for transferring entire blocks of bits. \ \formatnote{\italic{View interface to graphic}} \indexi{Class++View} \indexi{Graphic++View interface} \indexi{Class++Graphic}\indexi{View++Graphic macromethods} Each \italic{view} object has an associated \italic{graphic} object in which drawing takes place. In addition, for each method that \italic{graphic} provides, the class \italic{view} provides a corresponding \italic{macromethod}. For example, the class \italic{graphic} provides the method \italic{DrawString}, a drawing primitive for drawing text on the workstation screen. The graphic method \italic{DrawString} requires two parameters: the text to be drawn on the screen, and a specification of \italic{how} the text is to be drawn. The class \italic{view} provides a corresponding inline \italic{method} that takes two parameters, the text to be drawn and the specification of \italic{how} it is to be drawn. The \italic{view} method calls the \italic{graphic} method. \ \formatnote{\flushleft{\bold{Graphic rectangles}}} \indexi{Graphic++Rectangles} \indexi{Rectangles} Drawing in a graphic is done in relation to rectangles. A \italic{rectangle} is specified by a point, \italic{(left, top)}, and a \italic{width} and \italic{height: \center{\ \begindata{figure,539714152} $origin 0 0 $printscale 1.000000 1.000000 #none 0 \begindata{figogrp,539715240} \figattr{ } $ 0 28 163 2029 837 $endatt \enddata{figogrp,539715240} \begindata{figotext,540016520} attrs: -1 2 10 black 12 0 andysans $ 332 381 $ 0 0 (x,y)=000 $endatt \enddata{figotext,540016520} \begindata{figospli,540020744} attrs: -1 2 10 black 12 0 andy 0 5 $$ 0 4 0 0 $ 231 313 $ 57 -97 $ 201 -97 $ 345 -25 $endatt \enddata{figospli,540020744} \begindata{figotext,540023576} attrs: -1 2 10 black 12 0 andysans $ 1609 500 $ 0 0 Height=000 $endatt \enddata{figotext,540023576} \begindata{figorect,539973720} attrs: 1 2 10 blue 12 0 andy 0 8 0 $ 576 288 $ 864 432 $endatt \enddata{figorect,539973720} \begindata{figoplin,540010952} attrs: -1 1 10 black 12 0 andy 0 8 $$ 0 2 0 0 $ 1512 288 $ 144 0 $endatt \enddata{figoplin,540010952} \begindata{figoplin,540023800} attrs: -1 1 10 black 12 0 andy 0 8 $$ 0 2 0 0 $ 1512 720 $ 144 0 $endatt \enddata{figoplin,540023800} \begindata{figoplin,540028664} attrs: -1 1 10 black 12 0 andy 0 8 $$ 0 2 0 0 $ 1440 792 $ 0 144 $endatt \enddata{figoplin,540028664} \begindata{figoplin,540029320} attrs: -1 1 10 black 12 0 andy 0 8 $$ 0 2 0 0 $ 576 792 $ 0 144 2 8 0 5 0 1 5 0 1 5 1 5 0 5 0 0 5 0 0 5 0 0 5 0 0 5 0 $endatt \enddata{figoplin,540029320} \begindata{figoplin,540030072} attrs: -1 1 10 black 12 0 andy 0 5 3 5 0 $$ 0 2 0 0 $ 1584 288 $ 0 432 $endatt \enddata{figoplin,540030072} \begindata{figoplin,540032600} attrs: -1 1 10 black 12 0 andy 0 5 3 5 0 $$ 0 2 0 0 $ 576 864 $ 864 0 $endatt \enddata{figoplin,540032600} \begindata{figotext,540033256} attrs: -1 1 10 black 12 0 andysans 0 5 3 5 0 $ 1008 936 $ 0 0 Width=000 $endatt \enddata{figotext,540033256} #end \enddata{figure,539714152} \view{figview,539714152,57,376,193}}} F\formatnote{igure: \formatnote{(A rectangle)} } The Andrew Toolkit defines the following macros for setting the dimensions of a rectangle and finding out the values of those dimensions: \indexi{Rectangles++Size} \ \leftindent{\formatnote{\italic{rectangle_SetRectSize dimensions of a rectangle. \italic{rectangle_Left \italic{rectangle_Top --- \italic{rectangle_Width \italic{rectangle_Height -- }set the }get the value of the point, left. }get the value of the the point, top. --- }get the width. }get the height. }} In the tutorial, we will introduce these macros as they arise in the examples. \ \indexi{Rectangles++Logical}\indexi{Rectangles++Visual} The class \italic{graphic} defines the coordinate system for drawing. The units are pixels. \indexi{Pixel} The coordinate space has (0,0) at the origin on the rectangle's top left to 2\superscript{32}- 1, 2\superscript{32}-1 at its bottom right. You can draw anywhere in this logical unsigned 32-bit coordinate space. \indexi{Rectangles++Coordinates} The logical rectangle, \italic{lr}, specifies the rectangle to which a view should scale its drawing. The class \italic{graphic} also provides a \italic{visual rectangle}, \italic{vr}, that is a subrectangle of the logical rectangle and gives the coordinates for what is potentially visible in the window. To illustrate \italic{logical rectangles} and \italic{visual rectangles}, the Figure below depicts an inset displaying some text (\smaller{ZORK}) and a drawing. Note that the drawing happens to be at the very bottom of the window and its logical rectangle, \italic{lr} falls outside the window boundary. \indexi{Window boundaries} If a graphic's logical rectangle falls outside the window boundary and the drawing is relative to \italic{lr}, then the drawing will be clipped to the graphic's visual rectangle, \italic{vr}. The part of the drawing that falls within the coordinates given by the \italic{visual rectangle} normally corresponds to what the user sees on the screen, except if another drawing were laid over the first (e.g., a message box could be temporarily laid on top all or part of the drawing). \ \begindata{figure,539014712} $origin 0 0 $printscale 1.000000 1.000000 #none 0 \begindata{figogrp,539039368} \figattr{ } $ 0 280 136 2594 1609 $endatt \enddata{figogrp,539039368} \begindata{figotext,539497752} attrs: -1 2 10 black 12 0 andysans 1 8 0 5 0 $ 1634 469 $ 0 0 Window=040on=040screen=000 $endatt \enddata{figotext,539497752} \begindata{figotext,539845352} attrs: -1 2 10 magenta 14 0 andy 1 8 0 5 0 $ 475 519 $ 0 0 ZORK=000 $endatt \enddata{figotext,539845352} \begindata{figorect,539894952} attrs: -1 4 10 blue 14 0 andy 1 8 0 5 0 $ 720 1008 $ 576 720 $endatt \enddata{figorect,539894952} \begindata{figorect,539908312} attrs: 5 2 10 green 14 0 andy 1 8 0 5 0 $ 720 1008 $ 576 432 $endatt \enddata{figorect,539908312} \begindata{figorect,539909912} attrs: -1 2 10 red 12 0 andysans 1 8 0 5 0 $ 288 1440 $ 1152 -1296 $endatt \enddata{figorect,539909912} \begindata{figotext,539965112} attrs: 1 4 10 black 12 0 andysans 1 8 0 5 0 $ 1584 1152 $ 0 0 Visual=040rectangle=000 $endatt \enddata{figotext,539965112} \begindata{figotext,539965528} attrs: 1 4 10 black 12 0 andysans 1 8 0 5 0 $ 1584 1440 $ 0 0 Logical=040rectangle=012(includes=040visual)=000 $endatt \enddata{figotext,539965528} \begindata{figospli,539966200} \figattr{ shade:1 color:black linewidth:2 rrectcorner:10 fontsize:12 fontstyle:0 fontfamily:andysans textpos:1 arrowpos:1 arrow:5 linestyle:0 } $$ 0 3 0 0 $ 1759 544 $ -100 125 $ -319 176 $endatt \enddata{figospli,539966200} \begindata{figospli,539967176} attrs: 1 2 10 black 12 0 andysans 1 5 2 $$ 0 3 0 0 $ 1327 1195 $ 138 69 $ 238 19 $endatt \enddata{figospli,539967176} \begindata{figospli,540082008} attrs: 1 2 10 black 12 0 andysans 1 5 1 $$ 0 3 0 0 $ 1512 1512 $ -79 78 $ -173 78 $endatt \enddata{figospli,540082008} \begindata{figospli,540081016} attrs: 1 2 10 black 12 0 andysans 1 5 1 $$ 0 4 0 0 $ 1537 1512 $ -104 -4 $ -135 -110 $ -198 -148 $endatt \enddata{figospli,540081016} #end \enddata{figure,539014712} \view{figview,539014712,58,436,316} Figure: The logical and visual graphic 5 0 5 0 5 0 rectangles \formatnote{\bold{Scaling the drawing to the visual rectangle}} \indexi{Drawing++Scaling} \indexi{Rectangles++Scaling} \indexi{Graphic++Scaling} Rather than scaling the drawing to the logical rectangle (and being clipped), a view can scale its drawing to its graphic's visual rectangle. For example, in order to draw the string \italic{hello world} in the center of the display, \italic{helloworldview} will scale its drawing to its graphic's visual rectangle. Whenever such a \italic{view} receives a call to do a \italic{FullUpdate} of its part of the screen, it must call \italic{GetVisualBounds} \indexi{ \italic{GetVisualBounds }} \indexi{ \italic{view_GetVisualBounds}} \indexi{ \italic{graphic_GetVisualBounds}} \indexi{View++\italic{GetVisualBounds}} \indexi{Graphic++\italic{GetVisualBounds}} in order to find out the size of its graphic's visual rectangle and get its coordinates. \italic{GetVisualBounds} is a \italic{view} method that takes as its argument a \italic{struct rectangle}. \italic{GetVisualBounds} sets the rectangle to the coordinates of the view's graphic visual rectangle. For example, in \italic{helloworldview}'s \italic{FullUpdate} \indexi{Full update} method, the following lines get the coordinates of the visual rectangle: \ \programexample{\leftindent{ GetVisualBounds(hwv, &VisualRect); \ x = rectangle_Left(&VisualRect) + rectangle_Width(&VisualRect)/2; \ y = rectangle_Top(&VisualRect) + rectangle_Height(&VisualRect)/2; }\ } The statement, \italic{GetVisualBounds(hwv, &VisualRect)} sets \italic{VisualRect} to the dimensions of \italic{hwv}'s visual rectangle. That is, that part of \italic{hwv}'s graphic rectangle that is potentially visible in the window. The statements that assign values to \italic{x} and \italic{y} calculate the horizontal and vertical centerpoints of the visual rectangle. The values of \italic{left} plus the \italic{width} divided by two yield the horizontal center point; the values of \italic{top} plus \italic{height} divided by two yield the vertical. \ \formatnote{\bold{Moving the graphic point and drawing}} \indexi{Graphic++Point} \indexi{Drawing} The \italic{graphic} drawing primitives use a \italic{current point} as a reference point. Drawing is done from the \italic{current point} to a specified (x,y) coordinate. The method \italic{MoveTo} is a \italic{view} method that moves the graphic's \italic{current point} to a specified coordinate. It takes two arguments, the (x,y) coordinates. The method \italic{MoveTo} \indexi{ \italic{MoveTo}} \indexi{ \italic{graphic_MoveTo}} \indexi{ \italic{view_MoveTo}} \indexi{Graphic++\italic{MoveTo}} \indexi{View++\italic{MoveTo}} moves its object's graphic drawing point to (x,y). Before drawing, a \italic{view} should move the drawing point, then call a drawing primitive. For example, to draw the string \italic{hello world} in the center of the window, the following part of \italic{helloworldview's} \italic{FullUpdate} \indexi{Full update} method moves the \italic{current point}, then calls a string-drawing primitive: \ \programexample{\example{MoveTo(x, y); \ DrawString("hello world", graphic_BETWEENTOPANDBASELINE | graphic_BETWEENLEFTANDRIGHT); }\ } As in all methods, the object to which MoveTo and DrawString apply is the object to which the FullUpdate method applies. (This object is the value of the implicit pointer \italic{this}.) The statement, \italic{MoveTo(x, y)}, moves \italic{this}'s graphic drawing point to coordinates (x,y), the center of its's visual rectangle. The next statement, \italic{DrawString}, \indexi{Graphic++\italic{DrawString}} \indexi{View++\italic{DrawString}}\indexi{ \italic{DrawString}} is a \italic{view} method that actually draws \italic{hello world} in the window at the center point. The alignment options \smaller{BETWEENTOPANDBASELINE} and \smaller{BETWEENLEFTANDRIGHT} are used to center the string around the current drawing point as set by the preceding MoveTo. Other alignment options are available to start the string at point (x,y), to end the string at (x,y), and so forth (see \italic{DrawString}, \bold{Graphic.doc}). As mentioned earlier, \italic{graphic} provides other drawing methods for drawing lines, polygons, and other shapes. \ \section{Creating a stand-alone application program} \indexi{Stand-alone application} At this point, we have defined a complete subclass, \indexi{Subclass} \italic{helloworldview}. In the Andrew Toolkit, such a class can be used in one of two ways: (1) It can be paired with a \italic{dataobject} \indexi{Data object} to form an inset \indexi{Inset} (i.e., a dataobject/view pair); (2) it can be used in a stand-alone application program, illustrated in this example. \formatnote{Note: insets can also be used in a stand-alone application program. (See Example 10)} \subsection{Applications and the base program, 'runapp'} \indexi{Runapp} Andrew Toolkit applications are designed to run from a single base program called \italic{runapp}, short for \italic{run} \italic{app}lication). The program \italic{runapp} contains the code for all the basic components of the Andrew Toolkit. The program \italic{runapp} dynamically loads the code that is unique to individual applications into memory at run time. \indexi{Dynamic loading} To understand why this scheme is desirable, it is useful to examine, in brief, part of the \italic{UNIX} memory management subsystem. \indexi{Memory management} Each process on the UNIX system consists of three logical memory regions: text, data, and stack. The text region contains the set of instructions that the machine executes for the process; the data region contains global data; and the stack region contains the data local to a subroutine. Several processes can share a region; the most usual case is that of several processes executing the same program and sharing one copy of the text region. \formatnote{\ } The \italic{runapp} scheme is designed to allow Andrew Toolkit applications to share significant portions of program code. Shared code leads to decreased paging activity, decreased page faults (key portions of code are almost always paged in), decreased virtual memory use, decreased number of file fetches (under a distributed file system), and decreased file size of an application. \ \section{The class Application} \indexi{Application} \indexi{Class++Application} The class \italic{application} provides an interface between \italic{runapp} and application programs. In particular, \italic{application} provides the following methods that \italic{runapp} will call when it loads an application into memory: \ \formatnote{ \leftindent{\italic{ParseArgs(int argc,char **argv); -- }A method that should parse the command line arguments for the application. Returns boolean. \indexi{ \italic{ParseArgs}} \ \italic{ReadInitFile(); -- }A method that should read any initialization files for the application. \indexi{ \italic{ReadInitFile}} \italic{Start(); -- }A method that should set-up the application so that it can start running (e.g., create instances of classes, windows, etc.). Returns boolean. \indexi{ \italic{Start}} \ \italic{Run(); -- }A method that actually begins running the application. Returns int. \indexi{ \italic{Run}} \italic{Fork(); -- }A method that frees the typescript when not debugging. Returns boolean. \indexi{ \italic{Fork}}} } The program \italic{runapp} \indexi{Runapp} calls these methods when it loads an application into memory. In particular, it calls \italic{ParseArgs} to request the application to parse any command line arguments it may have, then call \italic{ReadInitFile} to request the application to read its initialization file, if any, then calls \italic{Start} to request the application program to create and initialize its objects and window, and finally calls \italic{Run} which (if not debugging), calls the method \italic{Fork} and enters the \italic{Interaction Manager's} keyboard interaction loop that mediates communication between a user and the application. \ Thus, to set up as a stand-alone application program, you should create a class that is a subclass of the Andrew Toolkit class, \italic{application}. The \italic{application} subclass should override those \italic{application} methods that you need. For example, for simplicity of exposition, this introductory example has no command line arguments or initialization files, so it does not need to override \italic{ParseArgs} or \italic{ReadInitFile}. Nor does it need to override the method \italic{Run} or \italic{Fork}. Thus, the only override we need to make is to \italic{application}'s \italic{Start} method, the method that should create instance of classes (e.g., an instance of \italic{helloworldview}, create a window, and so on. \ In this example, we create a subclass, \italic{helloworldapp}, in the file \italic{hwapp.H}. By convention, Andrew Toolkit application modules are named \italic{<x>app}, where \italic{<x>} is the name of the application or an \indexi{Application++Naming} \indexi{Application++Modules} \indexi{Application program} abbreviation for it (e.g., \italic{helloworld}) and \italic{app} is an abbreviation for the class \italic{application}. \programexample{ \example{class helloworldapp : public application \{ public: virtual ATKregistryEntry *ATKregistry(); boolean Start() ; \};} } \subsection{Writing a 'Start' method} \indexi{ \italic{\ Start}} To create a stand-alone application program, you must write a \italic{Start} method. The program \italic{runapp} will call your \italic{Start} method in order to run your program. Basically, the method should create an instance of the class, create a window, put the object in the window. For example, for \italic{helloworldview}, the application's \italic{Start} method should create an instance of the class \italic{helloworldview}, create a window, and put the \italic{helloworldview} instance in the window. \ To write the \italic{Start} method, you should declare it in a \italic{.C} file that has the same name as your application class. The following is the declaration for \italic{helloworldapp}'s \italic{Start} method is in the file \italic{hw}\italic{app.c}, followed by a detailed explanation of its various parts: \ \programexample{ \example{boolean helloworldapp::Start() \{ class helloworldview *hwv; class im *im; if( ! application::Start()) return FALSE; hwv = new helloworldview; if(hwv == NULL) return FALSE; im=im::Create(NULL); if(im == NULL)\{ (hwv)->Destroy(); return FALSE; \} (im)->SetView(hwv); (hwv)->WantInputFocus(hwv); return TRUE; \}} } \paragraph{Initializing the application} The first statement in an application's \italic{Start} method should be a call to itsbase class's \italic{Start} method. \programexample{\example{ if( ! application::Start(hwapp)) return FALSE; }\ } In this case, the call executes \italic{application}'s \italic{Start} method, which initializes to default values the foreground and background colors for graphics. If the call is unsuccessful, you should return \smaller{FALSE}. \ \paragraph{Creating an instance of a class} \indexi{Class++Creating} Most applications will create instances of objects that they will be using. In general, to create an instance of a class, you apply the \italic{new} operator to the class name. For a class \italic{x}, you call \italic{new} \italic{x}. To create an instance of helloworldview, you write \programexample{ \example{hwv = new helloworldview; if(hwv == NULL) return FALSE;} } \ The \italic{new} operator creates an instance of the class \italic{helloworldview} which is then assigned to \italic{hwv}. If \italic{hwv} is \smaller{NULL}, the \italic{new} was unsuccessful and you should return \smaller{FALSE} (\italic{i.e.}, failure). \ \paragraph{Creating an Interaction Manager and a window} In addition to creating an instance of a class, a stand-alone application will want to create an \italic{Interaction Manager}, an instance of the Andrew Toolkit class \italic{im} that manages the communication between the underlying window manager and views. As a side effect, creating an \italic{Interaction Manager} creates a window using whatever window manager is running on the workstation. Currently, the Andrew Toolkit runs on the X window system. There is one \italic{Interaction Manager} per window. \indexi{Windows} \indexi{Window manager} \indexi{Interaction manager} \indexi{View++Interaction manager} For example, the following creates an \italic{Interaction Manager}, \italic{im}, for the helloworldview application, \italic{helloworldapp}: \ \example{im=im::Create(NULL); if(im==NULL)\{ (hwv)->Destroy(); return FALSE; \}}\programexample{ } The call to \italic{im::Create(NULL)} creates an \italic{Interaction Manager} (\italic{im}) view and, as a side effect, creates a window using whatever window manager is running on the workstation. If \italic{im} is \smaller{NULL}, then the attempt to create the \italic{Interaction Manager} was unsuccessful and you should destroy any objects, (e.g., \italic{hwv}) and return \smaller{FALSE}, \italic{i.e.}, failure. \indexi{Objects++Destroying} \subsection{The view tree} \indexi{View tree} \indexi{View} The \italic{im} view is the root of the window's view tree. Recall that views represent space on your computer's display screen. Views are organized into trees. \italic{hmv->SetView (im)} puts \italic{hwv} in the view hierarchy with \italic{im}, which happens to be the root view, as the parent. The screen space assigned to a view is always totally included within the screen space allocated to its parent view. Two sibling views, however, may find their screen space overlapping in any way, as long as both siblings are contained within their parent's screen space allocation. \ It is important to understand the difference between the Andrew Toolkit class hierarchy and a view hierarchy. The class hierarchy defines a \indexi{Class hierarchy} \indexi{Class++Hierarchy} tree of base-class / derived-class relationships among classes; the view hierarchy defines a tree of \italic{view objects}, i.e., actual instances of the class \italic{view}. In the class hierarchy, defined through the statements \bold{class} <class name> \bold{\bold{:}} <super-class>, both the Andrew Toolkit class \italic{im} and the class \italic{helloworldview} are subclasses of the class \italic{view;} in the view \indexi{Superclass} \indexi{Subclass} hierarchy, defined by calls to \italic{im::SetView}, \indexi{Interaction manager++\italic{SetView}}\indexi{ \italic{SetView}} the view \italic{hwv}, an instance of class \italic{helloworldview, }is a child of the view \italic{im}, an instance of the class \italic{im}. \ \subsection{The interaction loop} \indexi{Interaction manager} \indexi{Interaction loop} After calling an application's \italic{Start} method, \italic{runapp} calls the application's \italic{Run} method. \indexi{ \italic{Run}} In this example, \italic{helloworldapp} inherits \italic{application}'s \italic{Run} method, which frees the \bold{command} (provided the debugging flag is not set) and calls \italic{im::KeyboardProcessor}. \indexi{Interaction manager++\italic{KeyboardProcessor}} The call to \italic{im::KeyboardProcessor()} enters the \italic{Interaction Manager}'s interaction loop, which mediates communication between a user (and the underlying window system) and the view(s) in the view tree (e.g., helloworldview). Logically, the interaction loop can be thought of as having the following pseudo-code structure: \ \programexample{ \example{while (there is not an exit signal) if a timed event on the event queue is scheduled to happen at this time: \ call the event handler; else if there is user input pending: \ call the child's appropriate method; \ else if there is file I/O on a file: \ call the appropriate file I/O handler; \ else if the user has done something that requires a full update of the screen: \ call child's FullUpdate method; \ else if there are requests for updates on the want update list: \ call the child's Update method; \ else if there is a child process that has died: \ release the child process to allow reuse of its resources; \ else wait for an event; \ end /* while */ }} In general, you will not need to override \italic{application}'s \italic{Run} method. If you do override it, however, note that a call to \italic{im::KeyboardProcessor} will normally be the last statement in the \italic{Run} method, since once the interaction loop is entered, subsequent calls will not be processed until the loop is exited. \ \section{Makefiles and compiling} \indexi{Compiling} \indexi{Makefile} \ Andrew utilizes the imake system from the X system, but with its own set of macros and conventions. For the helloworld application the following is sufficient in the Imakefile: \leftindent{OBJS = hwapp.o HFILES = hwapp.H hwview.o hwview.H DIRX = $(DESTDIR)/examples MkdirTarget($(DIRX) $(DIRX)/ex1) ATKLibrary(ex1, $(OBJS), , , ) RunappWithLibrary(helloworld,ex1, -r .) \ InstallProgram(helloworld,$(DIRX)/ex1) InstallExampleClassFiles($(HFILES), $(DIRX)/ex1) InstallDocs(ex1.doc, $(DIRX)/doc) } The \italic{Makefile} \indexi{Makefiles} \indexi{ \italic{make}} for a class that will stand-alone is for the most part, like any other \italic{Makefile} (see \italic{make} in the online help pages). This particular Makefile creates the dynamically loadable versions of helloworldapp and helloworldview from the corresponding .o and .eh files. The respective .o and .eh files also depends on information in the corresponding .c and .h files and from .ih files of all classes that provide necessary information to this particular application (application, graphic, view, observable, im, point, rectangle). The list of classes that need to be included in the dependencies list is determined by each individual application -- the rule of thumb is to include all classes that are explicitly called, their parents and ancestors, and any other non-classes (such as point and rectangle) that provide information to the classes. Note that class.h must also be included to create the .o and .eh files. \ The Imakefile given above will succeed on any platform. On some platforms it may be quicker to create a dynamically loadable object. To do this, replace the three lines ATKLibrary ... InstallProgram with these lines: \example{DynamicMultiObject(helloworldapp, helloworldview, $(OBJS),,,) InstallDynamicObject(helloworldapp, helloworldview, $(DIRX)/ex1) }\ Before running the resulting program, the directory containing the output must be listed in the value of the CLASSPATH environemnt variable. For most cases the CLASSPATH value can be .:$ANDREWDIR/lib/atk, where the initial dot adds the current directory to the list. Then the program is executed from the build directory with the command runapp helloworldapp \subsection{Compiling and linking the class and the program} To compile the class and the program using the \italic{Imakefile}, you should have that file and the files \italic{hwview.H},\italic{ hwview\italic{.}}\italic{C}, \italic{hwapp}\italic{.H}, and \italic{hwapp}\italic{.C }in a single directory to which you have read, write and list permissions. You may copy these files from /usr/andrew/examples/atk/ex1. \ Go to the directory in which you have put the files (that is, make it the current directory). Then at the command prompt, type \example{cp /usr/andrew/examples/ex1/* . }\ You will also need to change the protections on the files to +w: \leftindent{\example{chmod +w *}} (For more information on file protections, see \italic{chmod} in the online help pages.) \ Then check that ANDREWDIR is set properly in your environment variables and that $ANDREWDIR/bin is on the list given by the PATH environment variable. Finally, compile and link the program thusly: \example{\leftindent{genmake}; make} \subsection{Running an application} Andrew Toolkit applications are designed to run from a single base program called \italic{runapp}, short for \italic{run} \italic{app}lication). The program \italic{runapp} actually dynamically loads the application into memory. \indexi{Runapp} \indexi{Application program++Running} To run after compilation, type: \ \example{./helloworld} and the window will appear. \begindata{bp,539796616} Version 2 n 0 \enddata{bp,539796616} \view{bpv,539796616,31,0,0} Copyright 1992, 1996 Carnegie Mellon University and IBM. reserved. All rights \smaller{\smaller{$Disclaimer: # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose and without fee is hereby granted, provided # that the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation, and that the name of IBM not be used in advertising or # publicity pertaining to distribution of the software without specific, # written prior permission. # # THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD # TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ANY COPYRIGHT # HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL # DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, # DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # $ }}\enddata{text,539494632}