Keywords: TechDoc

Next: 5. TCM Class Hierarchy Up: Toolkit for Conceptual Modeling Previous: 3. Source Code Organization
Subsections

- 4.1 X/Motif user interface
- 4.2 User interface implementation
  - 4.2.1 Overview
  - 4.2.2 Application startup
  - 4.2.3 Main window structure
  - 4.2.4 Calling functions from the user interface
- 4.3 Xlib drawing

# 4. TCM User Interface

# 4.1 X/Motif user interface

Figure 4.1: typical X/Motif application structure.

Figure 4.1 shows the relationships between the built-in X, Motif and Unix libraries and an arbitrary X/Motif application. All X, Motif and Unix libraries have a C interface (functions, defines, typedefs, structs, enums, unions and variables). When a library is depicted on top of another library, this means that a library is implemented by means of the interface provided by the underlying layer. You are referred to the X and Motif books and manuals in the list of references at the end of this text.

The TCM X/Motif user interface is restricted to that part of the source (classes and functions) that directly uses the Motif, Xt and Xlib libraries. That part consists of most of the classes in the `src/ui` directory and some of the classes in the other editor libraries. The names of the editor specific user interface classes all end on `Window` or `Stubs`, such as `ERWindow`, `DFWindow` and `DiagramStubs`, `TableStubs` etc. The window classes are all specializations of the abstract class `ui/MainWindow`. The stub classes contain functions that are called from the user interface widgets (menus, push buttons, text fields etc.) and these functions in turn call application specific functions of non-GUI objects.

The `ed/DrawingArea` class is not part of libgui but of libeditor because it also has application specific behavior (albeit at a high level). The drawing area needs a viewer class (a descendent of class `ed/Viewer`). The viewer class should provide functions that are called when mouse buttons are pressed or dragged in the drawing area, when the mouse pointer is moved or when a characters are typed in while the mouse pointer is in the drawing area.

When asked what code contains X/Motif calls (and forms the GUI) then the answer is: almost all code of src/ui, all classes that end on `Window` or end on `Stubs` and the DrawingArea class.

The entire TCM distribution of the current version consists of about 450 classes and about 83000 lines of code (source and headers files, including white spaces and comments, but excluding the 20-line header part of the GNU General Public License). The X/Motif dependent part is about 19000 lines of code. This is the part that should be rewritten when TCM is translated to a non-X Windows environment.

The TCM user interface is more or less insulated into a restricted part of the source code, put in a number of C++ classes that are clearly distinguishable from the rest. But the user interface code is spread over all the TCM libraries (except libglobal). The reason for this organization is that factoring out the commonalities between all different tools was for us more important than a complete separation of the entire application code on one hand and the entire user interface code on the other. This means that each diagram editor has its own specific node and edge buttons. The code for creating tiled buttons in general is part of libgui but the specific initialization is done in the code of a specific diagram editor.

The approach of factoring out commonalities was a design for evolution and that has proved to work for TCM. It makes it relatively easy to add new tools or modify individual existing tools while maintaining a stable core of libraries and unrelated tools. When features are added to some library or to some tool, all tools that are included in the area of that library or tool (see figure 3.1) are also updated minimizing the risk of code redundancy or inconsistencies.

# 4.2 User interface implementation

## 4.2.1 Overview

Like all X11 applications, the TCM tools are event driven. This means they have the following basic structure:

1.
  Create the widgets.
2.
  Register the event handlers for these widgets.
3.
  Go into the main event loop.
4.
  Activate the appropriate event handler when a specific event occurs on a specific widget.
5.
  Return to the main event loop when done.

When a TCM tool is started the widgets that form the main window are created. The class `ed/EditWindow` and its specializations contain the functions to create the constituent parts of the main window. These widgets have one or more so-called call-back functions: the widget reacts to a certain set of X events (that set is built-in) and when such an event occurs a user-supplied action, in the form of ordinary C functions, will be called. In our implementation we do not use ordinary C functions but instead we provide C++ static member functions.

An exception to this use of callbacks, is the drawing area widget which, by default, does not react on the events that are needed to draw pictures as we like to do in TCM. Therefore, so-called translations are used, an X-Toolkit data structure to define some specified mapping of X events to user supplied actions. All details of translations and drawing area events are hidden in the `ed/DrawingArea` class.

Most pop-up window dialog widgets are created during initialization. When they are popped up they do not have to be created (which is much faster) and when these dialogs are dismissed they are not destroyed, but they are simply kept unmanaged (invisible). An exception to this are so-called message dialogs, for error and warning messages etc. These are created on the fly because we can not determine in advance how many of which kind will be necessary.

A special kind of message dialog is the question dialog which is application modal. This means that the user can only respond to this dialog and other user actions in the applications are prohibited. This is necessary when the application has to have an answer before it can proceed (e.g. the `save before quit?' dialog).

The main event loop is built-in in Motif, as well as the calling of the event handlers (via callback or translation).

## 4.2.2 Application startup

In contrast with an ordinary C program the editors don't start by directly entering the `main()` function. Instead, each editor is compiled with a distinct file `??editor.c`, e.g. `gdeditor.c` for TGD. In that file two global objects are created (but the two instance variables are not visible outside this file). For example:

    Application *app = new Application("Tcm");
    MainWindow *mw = new GDWindow("Tcm");

This means that the very first thing that is done on start-up is calling the constructor
`Application::Application` and then the constructor `GDWindow::GDWindow`. So, for each editor first an instance of class `ui/Application` is created and then an instance of an editor specific main window class is created (but both are not initialized yet). MainWindow and Application are both part of libgui. Specific main window classes such as GDWindow are specializations of MainWindow and are included in the specific diagram editor sources.

There should be just one instance of class Application per editor instance, which can be accessed via the global variable named `theApplication`. The application opens the X display, sets the color map and does some other things that are applicable for the entire application. Furthermore, the application class keeps track of a list of the application (main) windows. The current TCM implementation is limited to a single main window (the other windows are made as pop-up dialog windows) but in principle the framework of libgui can be utilized in programs that have multiple main windows.

After the creation of both class instances, the function `main(argc, argv)` is entered in which `theApplication->Initialize(argc, argv)` is called. The `main` function is generic and is part of libgui. The application then creates an object config of type Config, which reads in the configuration file and keeps tracks of various editor defaults. Then the application initializes the Xt application context and subsequently calls the main window initialization functions.

The main window initialization consists of the creation of the main window widgets. After the main window widgets are created, some other important objects are created (in the DiagramWindow or TableWindow class), notably:

- `printer` of class `ed/Printer`. This object keeps track of all page and print options and takes care of printing and generating PostScript.
- `helper` of class `ed/Helper`. This object shows the on-line help messages. It reads the help messages from file.
- `document` of an editor specific specialization of the abstract class `ed/Document`, depending on the base class of the main window. E.g. GDWindow creates GDDiagram, DFWindow creates DFDiagram etc. The document object keeps track of the document information (like document name, author etc.) and takes amongst others care of loading documents from file and saving them to file.
- Depending on the kind of document that is created some extra objects are created such as a graph object for diagram editors (a GDGraph in the case of TGD), that manages the nodes and edges of the document and a viewer object (GDViewer in the case of TGD) that manages in the case of a diagram editor one or more views containing a set of graphical shapes. In the case of a table editor the viewer object manages the rows and columns of the table.

These objects (of which exactly one instance exist per main window), will be supplied as parameter to the Motif callback functions 4.1. The callback function are static member functions of one of the stub classes. When the stub is called then the object is casted to the right type (because the parameters to stubs are simply pointers) and the appropriate class member of this object is called possibly with some other parameters that are supplied to the stub.

And finally, after the creation of the main window, the application object and the other main editor objects, the X main event loop is entered, giving X the control.

## 4.2.3 Main window structure

Figure 4.2: Main window of the generic diagram editor.

See figure 4.2 for the basic main window's widget structure. The boxes are Motif widgets (widget type and name between parentheses). The arrows connect widgets with their parents. The root is the top-level shell (TCM). To be more exact: the figure shows the main window of the generic diagram editor, TGD. The other diagram editors look almost the same, the main difference are their node and edge buttons. The table editors are almost similar too but they do not have node and edge buttons of course.

When libeditor.so is compiled with the option `-DDUMPWIDGETTREE`, a textual representation of the widget structure will be written to standard output when the editor is started (its output is also used for making this figure).

The details about creation of the widgets can be found in the classes `ui/MainWindow`, `ed/EditWindow`, `ed/DrawWindow`, `dg/DiagramWindow`, `tb/TableWindow` etc. See the class hierarchy of chapter 5 for the relationships and all the members of these classes.

## 4.2.4 Calling functions from the user interface

Menus are created by the constructor function of class `ui/Menu`. For an example for how to create a menu see `dg/DiagramWindow::CreateMenuBar`.

The items of a menu are specified by means of the `ui/MenuItem` class. A menu contains a list of menu items, which can be supplied to the menu constructor function. The menus common to all drawing editors are made in `ed/DrawWindow`, the menus common to all diagram editors are made in `dg/DiagramWindow` and the menus common to all table editors are made in `tb/TableWindow`. Likewise, menus that are specific for a single editor, are made in the corresponding main window class.

One of the fields of a MenuItem is the function that will be called when the menu item is selected. These functions are called stubs and have to be static C++ class members. The functions that are supplied are all part of a `...Stubs` class which consist entirely of these static functions. Menu items also have a so-called callback data. The callback data is always used to pass a pointer to the object whose class member should be called. For example, the Print menu item has as callback function the Print function of `ed/Editstubs` and as callback data a pointer to a printer of class `ed/Printer`. In the stubs function `Printer::Print` is called.

You can also call functions via the other main window widgets, for instance the diagram name text field or the node and edge toggle buttons. This works similar as with menus. You have to supply a callback function (`XtCallBack`) after the widget creation. These callbacks are also listed in the stub classes.

# 4.3 Xlib drawing

This is a very short introduction to drawing lines etc. in Xlib. For the rest you are referred to the documentation mentioned in the references.

X has 16 drawing modes (so called raster operations). A technique for simulating graphical objects moving or stretching (like resizing a box or a ``rubber band'' line), is to set the Graphics Context to the eXclusive-OR raster operation mode. The Graphics Context is an Xlib data structure which determines how an object will be drawn when a drawing routine is called (XDrawLine, XDrawRectangle etc.). In XOR mode, the new destination pixel is produced by the exclusive or of the old destination pixel with the source pixel. In this mode, you can easily draw and erase a figure. You draw a figure to let it appear, and when you redraw it, you erase it. By sequencing drawing and redrawing you can simulating an object being moved or dragged. Furthermore, in XOR mode, objects can overlap each other without damaging each other. The overlapping part is then white, and when one of the objects is moved or removed it will be redrawn, so that the overlapping part will appear black again. All details of drawing graphics with Xlib is hidden in the `XGrafport` class. An XGrafport has as attributes some GCs.

Note that each Xlib drawing operation is performed twice: one on the drawing area (window) and one on a Pixmap that serves as a backup store. This is needed because X does not automatically save the window contents when the window is overlapped or resized.

All the entire Xlib drawing functionality is hidden in the `ui/XGrafport` class which is a descendant of the abstract `ui/Grafport` class. Because XGrafport only uses a reference to the X Display and an X Window it can be used rather easily in any 2D drawing program under X (it uses Xlib but it does not use Motif nor the other classes of libgui that use Motif).

#### Footnotes

... functions 4.1
  `callback' is Motif-speak. `stub' is TCM-speak and means in this context the kind of callback function that is used in TCM and it forms an intermediate between the GUI (which uses X/Motif) and the other classes which do not depend on X/Motif.

Next: 5. TCM Class Hierarchy Up: Toolkit for Conceptual Modeling Previous: 3. Source Code Organization