\begindata{text,539040528} \textdsversion{12} \template{default} \define{global } \define{itemize } \define{enumerate } \define{programexample } \define{footnote attr:[Flags OverBar Int Set] attr:[FontSize PreviousFontSize Point -2]} \smaller{\indent{Copyright 1989 IBM 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. IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL IBM 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. }} \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{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{ a hellov.ch 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 hellov.c file -- will contain statements that import Andrew Toolkit classes and define the class \italic{helloworldview}'s methods and class procedures. a helloa.ch 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 helloa.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. Makefile -- will contain the directions for compiling, linking and loading the modules. } For a complete listing of these files, see \italic{Program Listing for Example1}, p. \begindata{textref,539236104} \textdsversion{12} # ExOneListing\ \enddata{textref,539236104} \view{textrefv,539236104,1009,0,0}. 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 source code is available in the directory /usr/andrew/examples/atk/ex1, together with the compiled program. 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} Figure \footnote{\ \begindata{textref,539315976} \textdsversion{12} ex1\ \enddata{textref,539315976} \view{textrefv,539315976,1010,0,0}} depicts the application program as it would appear on a workstation screen. Before reading the discussion of the example program, you may find it helpful to run the program on your workstation. If you are running the X11 window manager, first type \italic{setenv BE2WM x11} from your Xterm window, before proceeding with the following steps. \indexi{X11++Environment variable} \formatnote{\bold{Action 1:} \bold{command }prompt type \formatnote{To run the program, at the \bold{/usr/andrew/examples/ex1/hw} and press the Enter key. } \bold{Response: }The program will produce a window with \italic{hello world} centered in the body as in figure \begindata{textref,539314952} \textdsversion{12} ex1\ \enddata{textref,539314952} \view{textrefv,539314952,1011,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 it has no menus. Later examples will illustrate how to extend the program so that the view responds to user input. \bold{Action 4: title }To quit the program, move the cursor to the window bar, pop-up the menus and choose \bold{Zap} from the \italic{This Window} card. \bold{Response: }The program will disappear from the screen. } Figure: \formatnote{\formatnote{(Helloworld application program)} }\ \begindata{bp,538929224} \enddata{bp,538929224} \view{bpv,538929224,1012,0,0} \section{Creating a class} Creating a class \indexi{Class++Creating} in the Andrew Toolkit involves two steps: \enumerate{ 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{hellov} 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{ if (! $?SYS) setenv SYS `/usr/andrew/bin/sys` setenv CLASSPATH .:"$SYS":$HOME/lib/do/"$SYS":/usr/andrew/dlib/atk } Or, if you are running the Andrew Toolkit on top of the X11 window manager, type the following from your Xterm window: \programexample{ setenv BE2WM x11 } With this class path, the Andrew Toolkit dynamic object search will look in the \italic{current directory}, in \italic{/usr/andrew/bin/sys}, in the user's \italic{home directory} under \italic{lib/do} and in \italic{/usr/andrew/dlib/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 \italic{/usr/andrew/dlib/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{.ch}, 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{ .ch}, not\bold{ .h}). Thus the class declaration for the class \italic{helloworldview} is in the file \italic{hellov.ch.} The general format for a class declaration is: \indexi{Class declaration++Format} \example{ \bold{class} <class name> \bold{\bold{[}}<class file name>\bold{\bold{] :}} <super-class> \bold{[}<superclass file name>\bold{] \{} \bold{ overrides:} list of inherited methods that this class is overriding \bold{ methods:} list of methods for this class \bold{ macromethods:} list of methods for this class that are macros \bold{ classprocedures:} list of class procedures \bold{ macros:} list of class procedures that are macros \bold{ data:} data structures \bold{ \};} } If the filenames of the class or superclass are the same as their class names, you need not include them. You can also leave out the line "overrides:" if there are no overrides, or "methods:" if there are no methods, and so forth. The following is the declaration for the class \italic{helloworldview}, from the file hellov.ch: \programexample{ class helloworldview[hellov] : view \{ overrides: 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}. The filename for \italic{helloworldview} is \italic{hellov}, and the filename for \italic{view} is \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. Subclasses \indexi{Subclass} inherit the methods and data structures of their parents, or superclasses. \indexi{Superclass} Although \italic{helloworldview} declares no methods or data, it inherits the methods and data from its parent superclasses. The class \italic{view}, \italic{helloworldview}'s immediate parent, is part of the class hierarchy, \italic{basicobject}, \italic{observable}, \italic{view}, depicted in Figure \begindata{textref,539314696} \textdsversion{12} classhierarchy\ \enddata{textref,539314696} \view{textrefv,539314696,1013,0,0}. \formatnote{Figure: \formatnote{(Part of the Andrew Toolkit class hierarchy)} \center{basicobject | | observable | | view | | helloworldview} } Therefore, \italic{helloworldview} inherits the methods and data structures of \italic{basicobject, 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{view_Hit}, it will inherit that 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 method \italic{helloworldview} inherits, \italic{view_Hit}. \italic{view_Hit} 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 a subclass of a superclass. \indexi{Class declaration} \indexi{Subclass} \indexi{Superclass} If you leave the \italic{\bold{:} <super-class>} slot blank, the superclass defaults to \italic{basicobject}, which is the class at the top of the Andrew Toolkit class hierarchy. \subsection{C data structure for a class} \indexi{Data structure} \indexi{Class++Data structure} \indexi{Class preprocessor} \indexi{Preprocessor} \indexi{Class++Preprocessor} There is a class preprocessor that converts a class declaration to (1) a C structure for the class and (2) a set of macros that the system uses to call both the methods and class procedures associated with the class. The preprocessor also generates code that defines class procedures common to all classes and some procedures required by the Class run-time system. When processing a \italic{basic} class (i.e., a subclass of \italic{basicobject}), \indexi{Basicobject} the preprocessor creates a structure that contains the fields provided in the class' \italic{data\bold{:}} declaration, along with an initial first entry that points to the set of methods associated with the class. When processing a \indexi{Subclass} \italic{subclass} declaration, the preprocessor creates a structure that contains the fields provided in the class' \italic{data\bold{:}} declaration appended to a structure containing the data associated with the superclass. \indexi{Superclass} For example, the preprocessor creates the following structure for the class \italic{helloworldview}: \programexample{ struct helloworldview \{ union \{ struct basicobject_methods *helloworldview_methods; struct observable observable; struct view view; \} header; \}; } You will learn how to run the class preprocessor later in this example. \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->header.view} to access the field \italic{view}. \formatnote{@foot<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 can dereference through the header. 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->header.observable.nObservers}. \subsection{Writing class methods} \indexi{Class++Methods} \indexi{Methods} Up to this point, we have seen how to declare a class and have introduced the data structures generated by the class preprocessor. 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. When you call a method, the system assumes that the first argument is the object (i.e., an instance of a class) that you are requesting to perform the method. Each class has a \italic{method dictionary} which associates the names of methods with the actual methods for carrying out the operation. When you call a method, the system searches\formatnote{@foot< The system does not actually search on each invocation, although it is useful to think of it as a search. In order to increase efficiency, the search is done once and stored in a table for fast look-up.>} the method dictionary of the object's class for a method to execute. a method is not found in the object's class, the system searches its superclass' method dictionary, and so on until it reaches the root \italic{basicobject}, the root of the class hierarchy. If 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, if you call \italic{helloworldview_MoveTo}, for example, without an instance of the class, in this case \italic{hwv}, the program would not call \italic{helloworldview__MoveTo} since the parameter would not contain the list of methods pointing to \italic{helloworldview__MoveTo}. As mentioned previously, the \italic{helloworldview }class inherits methods from its superclasses \italic{observable} and \italic{view}. \indexi{Superclass} When you use a method defined in another class, you should call it with the class name of its first actual parameter, not the class name of the method itself. \indexi{Methods++Inheritance} This is because an intervening class may have redefined the method or may redefine the method in the future. Thus, to insure that you use the method appropriate to your place in the class hierarchy, you call \italic{helloworldview_GetVisualBounds}, not \italic{view_GetVisualBounds}, even though \italic{GetVisualBounds} is defined in \italic{view}, since the first parameter to the method is \italic{hwv}. In general, for any object \italic{x} in \italic{classx}, (\italic{i.e.}, \italic{struct classx *x)}, you call \italic{classx_methodname (x, <other 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{helloworldview_GetVisualBounds (hwv, <other parameters>)} to call the \italic{view} method \italic{GetVisualBounds}. \paragraph{Defining vs. using class procedures and methods} \indexi{Methods++Defining} \indexi{Class procedures++Defining} Note that when you \italic{define} class procedures or methods, you must use a double underscore; when you \italic{use}, or call, the procedures or methods, you only use a single underscore. For example, if you are creating the class \italic{helloworldview} and defining a \italic{FullUpdate} method, you use the double underscore, and write \italic{helloworldview__FullUpdate} as above. If you were to call helloworldview's \italic{FullUpdate} method, you would use a single underscore, i.e., \italic{helloworldview_FullUpdate}.\formatnote{@foot< Actually, you could write \italic{FullUpdate} alone rather than \italic{helloworldview_FullUpdate}. If you do so, however, you would need to run the \italic{.c} file through the \italic{Class} preprocessor.>} \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_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{hellov.c.} The following is the \italic{FullUpdate} method in its entirety, followed by a detailed explanation of its various parts: \programexample{ void helloworldview__FullUpdate(hwv, type, left, top, width, height) struct helloworldview *hwv; enum view_UpdateType type; long left; long top; long width; long height; \{ int x,y; struct rectangle VisualRect; helloworldview_GetVisualBounds(hwv,&VisualRect); x = rectangle_Left(&VisualRect) + rectangle_Width(&VisualRect)/2; y = rectangle_Top(&VisualRect) + rectangle_Height(&VisualRect)/2; helloworldview_MoveTo(hwv,x,y); helloworldview_DrawString(hwv,"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} (The parameters for all the methods are documented in Volume II.) \begindata{bp,538928968} \enddata{bp,538928968} \view{bpv,538928968,1014,0,0} For example, the following are the parameters for view's \italic{FullUpdate} method: \programexample{ void helloworldview__FullUpdate(hwv, type, left, top, width, height) struct helloworldview *hwv; enum view_UpdateType type; long left; long top; long width; long height; \{ } The \italic{FullUpdate} method has six parameters: \italic{hwv}, a pointer to the \italic{view} that needs to be redrawn; \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 (see \italic{FullUpdate} in the chapter, \bold{View}, Volume II). \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 (see \bold{Graphic}, Volume II). 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 hardwaredependent 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{@blankspace(1 lines)} \formatnote{@p(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 three parameters: an instance of a \italic{graphic}, 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 \italic{macromethod} that takes three parameters, an instance of a \italic{view}, the text to be drawn and the specification of \italic{how} it is to be drawn. The \italic{view} macromethod calls the \italic{graphic} method, sending it the \italic{view}'s \italic{graphic} as its first parameter. The following is an example of how \italic{view}'s \italic{DrawString} macromethod could be defined: \programexample{ DrawString(Text, Operation) (graphic_DrawString((self)->viewgraphic, (Text), (Operation))) } Note that the arguments to \italic{macromethods}, like the arguments to C \italic{macros}, should not have side effects. \indexi{Macromethods} \indexi{Macros} \indexi{Class++Macromethods} \formatnote{\flushleft{\bold{Graphic rectangles}}} \indexi{Graphic++Rectangles} \indexi{Rectangles} Drawing in the 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} (Figure \begindata{textref,539484168} \textdsversion{12} rectangle\ \enddata{textref,539484168} \view{textrefv,539484168,1015,0,0}). 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. Figure: \formatnote{(The logical and visual rectangles)} \indexi{Rectangles++Logical}\indexi{Rectangles++Visual} The class \italic{graphic} supplies a \italic{logical rectangle} which defines the coordinate system for drawing. The units are pixels. \indexi{Pixel} The coordinates of the logical rectangle are \italic{initially }given by (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}, gives the coordinates that you can scale your drawing to. The class \italic{graphic} also provides a \italic{visual rectangle}, \italic{vr}, that gives the coordinates for what is potentially visible in the window. To illustrate \italic{logical rectangles} and \italic{visual rectangles}, Figure \begindata{textref,539484424} \textdsversion{12} lvrec\ \enddata{textref,539484424} \view{textrefv,539484424,1016,0,0}, p. \begindata{textref,539484680} \textdsversion{12} # lvrec\ \enddata{textref,539484680} \view{textrefv,539484680,1017,0,0}, depicts a multi-media editor 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). \formatnote{Figure: rectangles)} } \formatnote{(The logical and visual graphic \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) as the example in Figure \begindata{textref,539484936} \textdsversion{12} lvrect\ \enddata{textref,539484936} \view{textrefv,539484936,1018,0,0} illustrated, 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} macromethod that takes two arguments. The first argument is a pointer to a \italic{view}. The second argument is 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{ helloworldview_GetVisualBounds(hwv, &VisualRect); x = rectangle_Left(&VisualRect) + rectangle_Width(&VisualRect)/2; y = rectangle_Top(&VisualRect) + rectangle_Height(&VisualRect)/2; } The statement, \italic{helloworldview_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. \begindata{bp,538929288} \enddata{bp,538929288} \view{bpv,538929288,1019,0,0} \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 macromethod \italic{helloworldview_MoveTo} is a \italic{view} macromethod that moves the graphic's \italic{current point} to a specified coordinate. It takes three arguments. The first is a pointer to a view, \italic{v}; the second and third are (x,y) coordinates. The macromethod \italic{helloworld_MoveTo} \indexi{ \italic{MoveTo}} \indexi{ \italic{graphic_MoveTo}} \indexi{ \italic{view_MoveTo}} \indexi{Graphic++\italic{MoveTo}} \indexi{View++\italic{MoveTo}} moves \italic{v}'s graphic drawing point to (x,y). Thus, 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{helloworldview_MoveTo(hwv, x, y); helloworldview_DrawString(hwv,"hello world", graphic_BETWEENTOPANDBASELINE |graphic_BETWEENLEFTANDRIGHT); } The statement, \italic{helloworldview_MoveTo(hwv, x, y)}, moves \italic{hwv}'s graphic drawing point to coordinates (x,y), the center of \italic{hwv}'s visual rectangle. The next statement, \italic{helloworldview_DrawString}, \indexi{Graphic++\italic{DrawString}} \indexi{View++\italic{DrawString}}\indexi{ \italic{DrawString}} \indexi{ \italic{graphic_DrawString}} \indexi{ \italic{view_DrawString}} is a \italic{view} macromethod 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 center coordinate (x,y). 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{graphic_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. Suppose, for example, that a user were running an \bold{EZ} process and two \bold{command} processes. Figure \begindata{textref,539485192} \textdsversion{12} processmem\ \enddata{textref,539485192} \view{textrefv,539485192,1020,0,0} depicts the logical memory organization for the three processes, including their text regions, data regions, and stack regions. Note that the process \italic{typescript1} shares its text region, \italic{region a} with the process \italic{typescript2}. Processes running separate programs, however, have separate text regions (e.g., \italic{region a} for \bold{typescript} vs. \italic{region f} for \bold{ez}). Note further that even though all three processes have a great deal of text in common (i.e., the Andrew Toolkit library code for basicobject, observable, and view), the \bold{ez} process cannot share the library code with the \bold{typescript} processes in a shared memory region: most \italic{UNIX} systems do not support shared libraries. \formatnote{Figure: \formatnote{(Processes and memory regions)} } The \italic{runapp} scheme is designed to allow Andrew Toolkit applications to share significant portions of program code. Figure \begindata{textref,539485448} \textdsversion{12} runapp\ \enddata{textref,539485448} \view{textrefv,539485448,1021,0,0} depicts the logical memory organization for \bold{EZ} and two \bold{commands} as they would appear running under a single \bold{runapp} process. \indexi{Runapp++Memory management} Thus, applications can share significant amounts of code. Shared code leads to the following performance improvements: 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. \formatnote{Figure: \formatnote{(Runapp processes and memory regions)} } \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{ \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{helloa.ch}. 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}. Note that both classes are more than eight letters long, so both have filename abbreviations. \programexample{ class helloworldapp[helloa] : application[app]\{ overrides: Start() returns boolean; \}; } \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{helloworldapp.c}, followed by a detailed explanation of its various parts: \programexample{ boolean helloworldapp__Start(hwapp) struct helloworldapp *hwapp; struct helloworldview *hwv; struct im *im; if(!super_Start(hwapp)) return FALSE; hwv=helloworldview_New(); if(hwv==NULL) return FALSE; im=im_Create(NULL); \{ if(im==NULL)\{ helloworldview_Destroy(hwv); return FALSE; \} im_SetView(im,hwv); return TRUE; \} } \paragraph{Initializing the application} \programexample{ if(!super_Start(hwapp)) return FALSE; } The first statement in an application's \italic{Start} method should be a call to its superclass' \italic{Start} method: \italic{if (!super_Start(hwapp)) return FALSE;}. In this case, the call executes \italic{application}'s \italic{Start} method, which initializes foreground and background colors for graphics to some default values. If the call is unsuccessful (\italic{i.e.}, \italic{!super_Start(hwapp)}), you should return \smaller{FALSE}. In general, when you precede a class' method name with the prefix \italic{super}, \indexi{Methods++Naming} \indexi{Superclass} the system searches for the method in the superclass of the currently executing method's class. Note that this may not necessarily be the superclass of the object's class. For example, if called from \italic{graphic_MoveTo}, \italic{super_MoveTo(hwv,x,y)} would begin the search for the method \italic{MoveTo} in \italic{graphic}'s superclass, \italic{observable}, not in \italic{hwv}'s superclass, \italic{view}. \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 call the \italic{New} class \indexi{ \italic{New}} \indexi{Class procedures++\italic{New}} procedure. For a class \italic{x}, you call \italic{x_New}. To create an instance of helloworldview, you write \programexample{ hwv=helloworldview_New(); if(hwv==NULL) return FALSE; } The call to \italic{helloworldview_New} creates an instance of the class \italic{helloworldview} and assigns it to \italic{hwv}. If \italic{hwv} is \smaller{NULL}, the attempt to create the instance 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 and on Andrew's window manager, \italic{wm}. 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}: \programexample{ im=im_Create(NULL); if(im==NULL)\{ helloworldview_Destroy(hwv); return FALSE; } 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{helloworldview_Destroy (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 the views represent space on your computer's display screen. Views are organized into trees. \italic{im_SetView (hwv, 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 parent-child relationships among classes; the view hierarchy defines a tree of parent-child relationships among \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 \italic{im}, an instance of the class \italic{im}. child of the view \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, the loop that 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{ while (there is not an exit signal) case (event) an event on the event queue is scheduled to happen at this time: call the event handler; break; there is user input pending: call the child's appropriate method; break; there is file I/O on a file: call the appropriate file I/O handler; break; the user has done something that requires a full update of the screen: call child's FullUpdate method; break; there are requests for updates on the want update list: call the child's Update method; break; there are child processes that have died: release the process to allow reuse of its resources; break; default: 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{Compiling and linking under the Andrew Toolkit} \indexi{Compiling} \indexi{Linking} \section{The class preprocessor} \indexi{Class preprocessor} \indexi{Class} \indexi{Class++Preprocessor} The \italic{Class} preprocessor takes a .ch file as input. \indexi{Header files} When it runs, it generates two files: (1) a .ih file which you must #include when you want to import (i.e., use) a class in another module; and (2) a .eh file which you must #include in the module that is defining the class in order to export the class. There can be only one class declaration within a .ch file and only one class defined within a module. The Class preprocessor copies all the contents of the .ch file except for the class declaration. It uses the class declaration to generate a C structure for the class and a set of macros for calling the methods and class procedures associated with the class. In the .eh file, it also generates code that defines a set of class procedures: \description{ \italic{x_New}\formatnote{ \indexi{ \italic{New}} -- }Creates an instance of the class x \italic{x_Initialize}\formatnote{ -- }Initializes an instance of the class x; called by x__New. \indexi{ \italic{Initialize}} \italic{x_Destroy}\formatnote{ -- }Destroys an instance of the class x; used in conjunction with x__New. \indexi{ \italic{Destroy}} \italic{x__Finalize}\formatnote{ -- }Destroys a class x; used if the class has been statically allocated or automatically allocated on the stack (see Class, Volume II). \indexi{ \italic{Finalize}} } Finally, the Class preprocessor creates several procedures required by the class run-time system. For example, the Class preprocessor takes hellov.ch and generates two files: \italic{hellov.ih} and \italic{hellov.eh}. Both files contain a \italic{struct helloworldview} declaration and macro definitions. In addition, \italic{hellov.eh} contains the class procedures helloworldview__New, helloworldview__Initialize, helloworldview__Destroy, helloworldview__Finalize. \section{Dynamic loading and modules} \indexi{Dynamic loading} The dynamic loading system used by the Andrew Toolkit requires a single class per module. The module must contain all the code associated with the class and any data associated with the class. You can create a module by using separately compiled C files and linking them. You may reference data directly between the files within a module, but you may not reference data directly between modules. (The Class system itself provides the mechanism for making indirect references to other modules.) These reference restrictions result in modules that are self-contained and that can be quickly dynamically loaded into a running program. For small programs, the class procedures and methods for the class are typically all located in a single \italic{.c} file. When the class is compiled, it is easiest if the module name for this \italic{.c }file is the same as your class name. For example, the class procedures and methods for an view named \italic{piechart} should all be located in a file named \italic{piechart.c}. \subsection{Imports and exports} The file\italic{ hellov.c}, the program file for the \italic{helloworldview}'s class procedures and methods, begins by importing the constructs it needs from the Andrew Toolkit library and exporting its class procedures and methods: \indexi{Exporting class procedures} \example{ #include <class.h> #include "graphic.ih" #include "hellov.eh" } \italic{hellov.c} must #include \italic{class.h} to access the Andrew Toolkit class facilities, and \italic{graphic.ih} to use the Andrew Toolkit graphic class. It must export \italic{hellov.eh}, the file containing the declaration of exported class procedures and methods. In general, you must include all the classes that your class uses directly or indirectly. If you leave one out, when you run the program you will get the following run-time error message in your \bold{command}: \indent{\italic{Could not find the class methods for <class name> (xxxxx) exiting}} where \italic{<class name>} will be the name of a specific class that must be included. \section{Makefiles and compiling} \indexi{Compiling} \indexi{Makefile} \formatnote{\example{SRCDIR=/usr/andrew/ INCLUDES= -I. -I$\{SRCDIR\}include/atk -I$\{SRCDIR\}include INCLUDESRC = $\{SRCDIR\}include/atk CC=cc DEBUG = -g TOOLS = $\{SRCDIR\}bin/ CFLAGS= $\{DEBUG\} $\{INCLUDES\} CLASSFLAGS=$\{INCLUDES\} MAKEDO = $\{TOOLS\}makedo $\{DEBUG\} -b $\{TOOLS\} -d $\{SRCDIR\}lib CLASS = $\{TOOLS\}class .SUFFIXES: .ih .eh .ch .do .ch.ih: $\{CLASS\} $\{CLASSFLAGS\} $*.ch .ch.eh: $\{CLASS\} $\{CLASSFLAGS\} $*.ch .o.do: $\{MAKEDO\} $< all: helloa.do hellov.do helloa.do: helloa.o helloa.eh hellov.do: hellov.o hellov.eh helloa.o: helloa.c helloa.o: $\{INCLUDESRC\}/app.ih helloa.o: $\{INCLUDESRC\}/graphic.ih helloa.o: $\{INCLUDESRC\}/im.ih helloa.o: $\{INCLUDESRC\}/observe.ih helloa.o: $\{INCLUDESRC\}/point.h helloa.o: $\{INCLUDESRC\}/rect.h helloa.o: $\{INCLUDESRC\}/view.ih helloa.o: $\{SRCDIR\}include/class.h helloa.o: hellov.ih helloa.o: helloa.eh helloa.eh helloa.ih: helloa.ch helloa.eh helloa.ih: $\{INCLUDESRC\}/app.ih hellov.o: hellov.c hellov.o: $\{INCLUDESRC\}/graphic.ih hellov.o: $\{INCLUDESRC\}/observe.ih hellov.o: $\{INCLUDESRC\}/point.h hellov.o: $\{INCLUDESRC\}/rect.h hellov.o: $\{INCLUDESRC\}/view.ih hellov.o: $\{SRCDIR\}include/class.h hellov.o: hellov.eh hellov.eh hellov.ih: hellov.ch hellov.eh hellov.ih: $\{INCLUDESRC\}/graphic.ih hellov.eh hellov.ih: $\{INCLUDESRC\}/observe.ih hellov.eh hellov.ih: $\{INCLUDESRC\}/point.h hellov.eh hellov.ih: $\{INCLUDESRC\}/rect.h hellov.eh hellov.ih: $\{INCLUDESRC\}/view.ih hellov.eh hellov.ih: $\{SRCDIR\}include/class.h} } 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. \subsection{Compiling and linking the class and the program} To compile the class and the program using this \italic{Makefile}, you should have the files \italic{hellov.ch}, \italic{hellov.c}, \italic{helloa.ch}, \italic{helloa.c} and the \italic{Makefile} in a single directory in 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 (make it the current directory). Then at the \bold{command} prompt, type cp /usr/andrew/examples/ex1/* . \begindata{bp,538928712} \enddata{bp,538928712} \view{bpv,538928712,1022,0,0} You will also need to change the protections on the files to +w. Type \leftindent{chmod +w *} and press the Enter key. (For more information on file protections, see \italic{chmod} in the online help pages.) To compile and link the program, type \bold{\leftindent{make}} and press the Enter key. \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: \bold{\leftindent{runapp helloa}} and press the Enter key. \begindata{bp,538271624} \enddata{bp,538271624} \view{bpv,538271624,1023,0,0} \section{Program listing for Example 1} \formatnote{ \bold{hellov.ch} class helloworldview[hellov]: view \{ overrides: FullUpdate(enum view_UpdateType type, long left, long top, long width, long height); \}; \bold{hellov.c} #include <class.h> #include "hellov.eh" #include "graphic.ih" void helloworldview__FullUpdate(hwv, type, left, top, width, height) struct helloworldview *hwv; enum view_UpdateType type; long left; long top; long width; long height; \{ int x,y; struct rectangle VisualRect; helloworldview_GetVisualBounds(hwv,&VisualRect); x = rectangle_Left(&VisualRect) + rectangle_Width(&VisualRect)/2; y = rectangle_Top(&VisualRect) + rectangle_Height(&VisualRect)/2; helloworldview_MoveTo(hwv,x,y); helloworldview_DrawString(hwv,"hello world", graphic_BETWEENTOPANDBASELINE | graphic_BETWEENLEFTANDRIGHT); \} \bold{helloa.ch} class helloworldapp[helloa] : application[app]\{ overrides: Start() returns boolean; \}; \bold{helloa.c} #include <class.h> #include "helloa.eh" #include "im.ih" #include "hellov.ih" boolean helloworldapp__Start(hwapp) struct helloworldapp *hwapp; \{ struct helloworldview *hwv; struct im *im; if(!super_Start(hwapp)) return FALSE; hwv=helloworldview_New(); if(hwv==NULL) return FALSE; im=im_Create(NULL); if(im==NULL)\{ helloworldview_Destroy(hwv); return FALSE; \} im_SetView(im,hwv); return TRUE; \} \bold{Makefile} SRCDIR=/usr/andrew/ INCLUDES= -I. -I$\{SRCDIR\}include/atk -I$\{SRCDIR\}include INCLUDESRC = $\{SRCDIR\}include/atk CC=cc DEBUG = -g TOOLS = $\{SRCDIR\}bin/ CFLAGS= $\{DEBUG\} $\{INCLUDES\} CLASSFLAGS=$\{INCLUDES\} MAKEDO = $\{TOOLS\}makedo $\{DEBUG\} -b $\{TOOLS\} -d $\{SRCDIR\}lib CLASS = $\{TOOLS\}class .SUFFIXES: .ih .eh .ch .do .ch.ih: $\{CLASS\} $\{CLASSFLAGS\} $*.ch .ch.eh: $\{CLASS\} $\{CLASSFLAGS\} $*.ch .o.do: $\{MAKEDO\} $< all: helloa.do hellov.do helloa.do: helloa.o helloa.eh hellov.do: hellov.o hellov.eh helloa.o: helloa.c helloa.o: $\{INCLUDESRC\}/app.ih helloa.o: $\{INCLUDESRC\}/graphic.ih helloa.o: $\{INCLUDESRC\}/im.ih helloa.o: $\{INCLUDESRC\}/observe.ih helloa.o: $\{INCLUDESRC\}/point.h helloa.o: $\{INCLUDESRC\}/rect.h helloa.o: $\{INCLUDESRC\}/view.ih helloa.o: $\{SRCDIR\}include/class.h helloa.o: hellov.ih helloa.o: helloa.eh helloa.eh helloa.ih: helloa.ch helloa.eh helloa.ih: $\{INCLUDESRC\}/app.ih hellov.o: hellov.c hellov.o: $\{INCLUDESRC\}/graphic.ih hellov.o: $\{INCLUDESRC\}/observe.ih hellov.o: $\{INCLUDESRC\}/point.h hellov.o: $\{INCLUDESRC\}/rect.h hellov.o: $\{INCLUDESRC\}/view.ih hellov.o: $\{SRCDIR\}include/class.h hellov.o: hellov.eh hellov.eh hellov.ih: hellov.ch hellov.eh hellov.ih: $\{INCLUDESRC\}/graphic.ih hellov.eh hellov.ih: $\{INCLUDESRC\}/observe.ih hellov.eh hellov.ih: $\{INCLUDESRC\}/point.h hellov.eh hellov.ih: $\{INCLUDESRC\}/rect.h hellov.eh hellov.ih: $\{INCLUDESRC\}/view.ih hellov.eh hellov.ih: $\{SRCDIR\}include/class.h } \begindata{bp,537558784} \enddata{bp,537558784} \view{bpv,537558784,1025,0,0} Copyright 1992 Carnegie Mellon University and IBM. All rights reserved. \smaller{\smaller{$Disclaimer: Permission to use, copy, modify, and distribute this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice, this permission notice, and the following disclaimer appear in supporting documentation, and that the names of IBM, Carnegie Mellon University, and other copyright holders, not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. IBM, CARNEGIE MELLON UNIVERSITY, AND THE OTHER COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL IBM, CARNEGIE MELLON UNIVERSITY, OR ANY OTHER 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,539040528}