Programming with XView
There are many window systems out there in the computer world—some are taking control of the desktop, while others are still strong in their workstation niche. Just as most of us would prefer to program in a high-level language rather than assembly, XView provides us with a high-level approach to GUI development. XView components come with default settings that make sense, so that a newly created button, for example, will look and act “correct” as soon as it is made. The API for XView is at once both simple and extensive. Simple, because we can do most jobs using only three different library routines, and extensive because we can control nearly all aspects of each component with those routines.
Let's jump right in and take a look at the simple XView program shown in Listing 1. Make sure you have XView and the OpenLook libraries on your system; otherwise, you'll get compile errors. Put this example into a file called sample.c and compile it using the following command:
cc -o sample -I$OPENWINHOME/include\ -L$OPENWINHOME/lib\ -L/usr/X11/lib sample.c -lxview -lolgx -lX11
where OPENWINHOME is the home directory on your system for OpenWindows, usually /usr/openwin.
When you run sample.c, you'll be presented with a simple text editor, a functionality of the standard XView text sub-window component. Type in the text window, using the keyboard cursor keys to move around. Highlight words, lines and paragraphs with mouse clicks and drags. The right mouse button brings up a menu to open, save and insert files, exit the text and search for strings. Grab the end-stop of the slider and pull it down—you now have two views of the same text.
This is truly neat, but how did we get here? Let's walk through the sample program together.
First, we include two header files: one for generic XView information and one for the text sub-window component. If we had additional components (perhaps a pair of push buttons to open and save files), we would also include the header file for those panel components.
Next, inside of our main routine, we declare a Frame variable, which is used by XView as a place to put other components. It becomes an invisible layer between our text sub-window and the window decorations from the window manager.
Next, we call xv_init to initialize XView and pass the command-line arguments to it. (Check the xview man page for all the command-line options.) With this xv_init call, we first come upon a strong theme that runs through all XView calls—a null terminated list of attribute, value pairs. The first argument to xv_init is defined in the XView headers. xv_init expects to see two more arguments: the address of main's argument count and the argument values. To tell xv_init that we have nothing more for it to do, we pass one final argument of NULL to terminate the argument list.
On the next line, we create our frame, using xv_create. In the first argument we specify the parent of this component. Since we're just creating the outermost frame, we have no parent, and we use XV_NULL. The second argument specifies the type of component we want to create, in this case a FRAME. Notice that the remaining arguments form a null-terminated list of following attribute, value pairs. For example, the following attribute, value pair:
sets the label of the frame, which becomes the text on the window's title bar. If we wanted to set the size of the frame on the screen, we would simply add two pairs to set the width and height (before the terminating NULL):
XV_HEIGHT, 200, XV_WIDTH, 400,Similar attributes are used to set the maximum and minimum sizes of the frame, the initial position on the screen, the header and footer, etc.
Moving on, we create the text sub-window. We pass in our frame variable to this xv_create call, because we want the frame to become the parent of the text sub-window, affecting its size and position. The type of component we're creating is TEXTSW for a text sub-window, and we are adding no other options to it (although many are available).
Next, we call xv_main_loop, which handles all X events for the window that appears on the screen. It calls lower-level xlib routines to create the window, slider and canvas. It listens for mouse and keyboard input and handles it. xv_main_loop doesn't return until the window is closed by the user. At that point, our program can quietly exit.
Before we go further, there are two other important XView routines we need to know: xv_set and xv_get. As their names imply, they are used to set and to get attribute values for XView components.
In sample.c, we saw how to set the size of the frame when it was created. We also could have set the size after it was created with the xv_set call in this way:
xv_set(frame, XV_HEIGHT, 200, XV_WIDTH, 400, NULL);
Although the vertical formatting isn't necessary, it shows more clearly what is happening: namely, using the frame component, we have set its height to 200 and its width to 400.
Suppose that at some point in the program, we needed to determine the position of the frame on the screen:
int x, y; x = (int)xv_get(frame, XV_X); y = (int)xv_get(frame, XV_Y);
This fragment retrieves the x and y coordinates of the frame on the screen. Yes, it looks like we violated the rule of using a null-terminated list, but since xv_get returns a single value, we fetch only one attribute; therefore, xv_get accepts only two arguments.