These tutorials are excerpted from the book "Motif Programming: The Essentials and More" , by Marshall Brain.
#include <Xm/Xm.h> #include <Xm/Label.h> XtAppContext context; XmStringCharSet char_set=XmSTRING_DEFAULT_CHARSET; Widget toplevel, label; main(argc,argv) int argc; char *argv[]; { Arg al[10]; int ac; /* create the toplevel shell */ 1 toplevel = XtAppInitialize(&context,"",NULL,0, &argc,argv,NULL,NULL,0); /* create label widget */ 2 ac=0; 3 XtSetArg(al[ac],XmNlabelString, XmStringCreateLtoR("Hello World", char_set)); ac++; 4 label=XmCreateLabel(toplevel,"label",al,ac); 5 XtManageChild(label); 6 XtRealizeWidget(toplevel); 7 XtAppMainLoop(context); }
This tutorial will go over what each line means and does, talk about some bugs, and generally explain what is going on so that you can understand the basic structure of any Motif program. [Note: this program may seem extremely odd the first time through - even this tiny piece of code embodies quite a few concepts. Wade through once , and if it feels uncomfortable then go through it a second time the next day. You might also consider reading tutorial 2, then tutorial 3, and then rereading the pair. Tutorial 3 contains examples and listings of resources that will help you here.]
Notice first that this program includes two libraries. They are both Motif libraries. "Xm.h" is the general Motif library and will be included into all Motif programs that you create (it includes many other libraries as well, including "Xlib.h" (the X library) and "Intrinsics.h" (the Xt library)). "XmLabel.h" is the include file for the "label widget" - see below and Tutorial 3 for more information on this widget and its use. A big Motif program might include 20 or 30 header files from X11, Xm, etc.
The program also declares several global variables. The context variable holds information about the application itself. It gets initialized in the call to XtAppInitialize and then is used by a set of functions whose names start with XtApp. You will never use this variable except as an argument to one of these functions. The toplevel and label variables, declared as type Widget, are actually pointers that will point to structures that hold information about the toplevel and label widgets. In a moment (and in Tutorial 3) you will learn about resources--the widget pointers point to structures that hold, among other things, the current resource values for a widget.
Any Motif program, like all C programs, has a main procedure. The mainprocedure accepts the command line arguments as its parameters. Even if the code you write doesn't use command line arguments, the main procedure needs to accept argc and argv. The X interface defines certain standard command line parameters that work the same way in all X applications (such as -iconic, -geometry, etc.) (you can read about them with "man X"). In practice you will pass argc and argv off to a routine that extracts all the standard X options and then returns to you what's left.
Before describing the rest of the program, you must understand the concept of a "widget". Motif tries to be an object oriented sort of programming envrionment, and under X the objects used to implement user interfaces are called widgets. Generally widgets are made out of other widgets in a hierarchical fashion. Each widget has associated with it a set of "resources", and a set of "callbacks" (both of these topics will get massive treatment as we go along). The resources are a set of variables that control the appearance and behavior of a widget, and the callbacks are functions that the widget calls so that your code can respond to user events. [Just for your own edification, the X intrinsics are an extension to X that makes widget sets possible. There are several different widget sets that you will hear about - Motif has become the single standard widget set, but there was/is also the Athena widget set, the OpenLook widget set, and several others.]
toplevel = XtAppInitialize(&context,"",NULL,0, &argc,argv,NULL,NULL,0);
It accepts several parameters. The first one is the address of the context variable. This functiion will initialize the variable for you with information important to the application. It is later used at the end of the program. The second parameter is the class name of the application. It is used when setting resources in the program using resource files. See Chapter 12 of "Motif Programming: The Essentials and More" for more information, as well as Tutorial 9.
The fourth and fifth parameters have to do with command line parsing and will not be discussed in the tutorials. See the Schiefler and Gettys for more information.
The next two parameters are argc and argv. Because XtAppInitialize extracts the command line arguments that relate to X but leaves the rest of them, it has to be able to change argc. You MUST pass argc and argv, 0 and NULL cannot be used. Be sure you use the ADDRESS of argc, since argc is changed by XtAppInitialize.
The next parameter handles fallback resources. See chapter 12 of "Motif Programming: The Essentials and More" for more information. The last two handle an argument list.
The call to XtAppInitialize initializes the toplevel widget. The toplevel widget is the main window for your application. The toplevel widget will hold all of the other widgets in your application.
That's the initilization line. It should be the first line of all of your Motif programs. But it is easy to make mistakes. Follow the template given in the listing above and you should do fine.
ac=0; XtSetArg(al[ac],XmNlabelString, XmStringCreateLtoR("Hello World", char_set)); ac++;
Here is what is going on. "toplevel" (line 1) is the top-most widget. It is essentially the window that holds this application (also known as a "shell widget"). toplevel was created for you by XtAppInitialize to hold the application. toplevel is empty however - you place other widgets into this empty shell to create the user interface. In this case, we are creating one widget called a label widget. A label widget holds a static text label. In this label widget goes the static text "hello world".
A label widget has 18 resources that you can change to customize its appearance. A resource is simply a variable that controls the behavior of the widget. For example, in a label widget you can change the text it displays, the font used, the size, etc. [How do you know what the resources are, and what they are called? You get the Motif Programmer's Reference Manual which contains complete descriptions of all widgets and their resources, or you get "Motif Programming: The Essentials and More", which summarizes them, or you can download a summary from the ftp site. See the file named motif.widget.reference.]
In this case we want to change the labelString resource of the label widget we are about to create. The labelString resource is going to be set as the widget is created. All of the other resources of the label widget are set to their default values.
To change the resources of any widget from inside of a program: you create an argument array, fill that array with the resource values you wish to change, and then pass that argument array to the widget either at creation (as shown here) or after creation using the XtSetValues or XtVaSetValues call. A counter is used to keep track of the number of resource values stored in the array (ac is the counter in this program, and al is the argument list). Using the XtSetArg call, the code is placing the value "hello world" into al[0], and specifying that the value should be used for the XmNlabelString resource. The value of ac is incremented as well (EXTREMELY IMPORTANT - make sure ac accurately reflects the number of resources in al).
There is also the XmStringCreateLtoR call to contend with. Motif strings are different from normal strings (because they contain more information, such as which direction the characters are normally drawn (r-to-l or l-to-r), etc.), so a special creation procedure is used to create them. The first parameter is the value of the string, and the second is the character set that should be used for the string.
There are a number of errors that are easy to create with resource setting and argument lists. You can misspell the resource name, forget to initialize or increment ac, place too many values in al (since it's an array it can overflow), forget to create an actual XmString, etc. Be careful.
All of this is done to set up the argument list. Now we can create the actual widget itself.
label=XmCreateLabel(toplevel,"label",al,ac); XtManageChild(label);
In this line, the parameter "label" is the name of the widget. You can place any name here. This name is used when setting the widget's resources from a resource file, and is also used during error messages to tell you which widget is having problems. You want to make these widget names unique and descriptive. The toplevel parameter declares which widget is the parent of the label widget. All widgets must have a parent. Finally the al and ac parameters let you modify the value of the widget's resources as the widget is created.
Once the widget is created, the function returns a value to the label variable, that can be used later to refer to that widget (eg - to change its resources).
As with line 1, there are many ways to make this line create segmentation faults. In this case however, the al and ac parameters can be replaced by NULL and 0 respectively if no resources are being changed at creation. An extremely common bug here is to leave out the #include for the label widget. On many compilers this will generate irrational errors in many places. Be sure you have all the libraries needed for all of the Widgets used.
Note, by the way, that there is another way to do the same thing that lines 2, 3 4 and 5 are doing. You can use the following:
label=XmCreateLabel(toplevel,"label",NULL,0); XtManageChild(label); XtVaSetValues(label,XmNlabelString, XmStringCreateLtoR("Hello World", char_set), NULL);
This form eliminates the need to set up the al and ac variables, and therefore shortens the code a bit. See Tutorial 3 for more information, some alternatives, and a note about memory leaks and how to prevent them.
There it is - an entire Motif program. Just to recap, this program created a shell widget name toplevel, and then created a label widget containing the string "hello" as its child. It then realized the toplevel shell and started the event loop to handle events. That's all. It's a little messy when you see it the first time, but you will get used to it as time goes on.
If none of this made sense, try reading it again now that you've read it once. Also try looking at tutorial 3, which contains more information about resources.
In the next tutorial, we'll spend time looking at resources and what they can do.