-->

Previous | Table of Contents | Next

Page 537


/* give the app a name and initial size */

skeleton = XtVaAppInitialize(&skel_app, "Skeleton", NULL, 0, &argc, argv,

NULL, XmNwidth, 320, XmNheight, 240, NULL);



/* create the main window */

skel_window = XtVaCreateManagedWidget("skel", xmMainWindowWidgetClass, skeleton,

XmNscrollingPolicy, XmAUTOMATIC, NULL);



/* build a menu bar across main window */

skel_menubar = XmCreateMenuBar(skel_window, "skel_menubar", NULL, 0);



/* build the File pull-down menu */

skel_filepulldown = XmCreatePulldownMenu (skel_menubar, "File", NULL, 0);

Âskel_string = XmStringCreateLocalized ("File");



/* create the menu, assign ALT+F as mnemonic key */

XtVaCreateManagedWidget ("File", xmCascadeButtonWidgetClass, skel_menubar,

XmNlabelString, skel_string, XmNmnemonic, `F', XmNsubMenuId,

Âskel_filepulldown, NULL);



    /* release storage */

    XmStringFree(skel_string);



/* now add File pull-down menu elements */

skel_new = XtVaCreateManagedWidget("New", xmPushButtonGadgetClass,

skel_filepulldown, NULL);

skel_open = XtVaCreateManagedWidget("Open", xmPushButtonGadgetClass,

skel_filepulldown, NULL);

XtVaCreateManagedWidget("separator", xmSeparatorGadgetClass, skel_filepulldown,

        NULL);

skel_close = XtVaCreateManagedWidget("Close", xmPushButtonGadgetClass,

skel_filepulldown, NULL);

skel_save = XtVaCreateManagedWidget("Save", xmPushButtonGadgetClass,

skel_filepulldown, NULL);

XtVaCreateManagedWidget("separator", xmSeparatorGadgetClass, skel_filepulldown,

        NULL);

skel_exit = XtVaCreateManagedWidget("Exit", xmPushButtonGadgetClass,

skel_filepulldown, NULL);



/* add what to do when user selects Exit */

XtAddCallback(skel_exit, XmNactivateCallback, skel_exit_action, NULL);



/* build Edit menu */

skel_editpulldown = XmCreatePulldownMenu(skel_menubar, "Edit", NULL, 0);

skel_string = XmStringCreateLocalized ("Edit");

XtVaCreateManagedWidget ("Edit", xmCascadeButtonWidgetClass, skel_menubar,

XmNlabelString, skel_string, XmNmnemonic, `E', XmNsubMenuId,

Âskel_editpulldown, NULL);



    /* release storage */

    XmStringFree(skel_string);



/* add Edit pull-down menu elements */

skel_cut = XtVaCreateManagedWidget("Cut", xmPushButtonGadgetClass,

skel_editpulldown, NULL);

skel_copy = XtVaCreateManagedWidget("Copy", xmPushButtonGadgetClass,

skel_editpulldown, NULL);


                                    continues

Page 538

Listing 26.1. continued


skel_paste = XtVaCreateManagedWidget("Paste", xmPushButtonGadgetClass,

skel_editpulldown, NULL);



/* build Help menu */

skel_helppulldown = XmCreatePulldownMenu(skel_menubar, "Help", NULL, 0);

Âskel_string = XmStringCreateLocalized ("Help");

XtVaCreateManagedWidget ("Help", xmCascadeButtonWidgetClass, skel_menubar,

XmNlabelString, skel_string, XmNmnemonic, `H', XmNsubMenuId,

Âskel_helppulldown, NULL);



    /* release storage */

    XmStringFree(skel_string);



/* now move the Help pull-down to right side - thanks, Motif FAQ! */

XtVaSetValues(skel_menubar, XmNmenuHelpWidget, XtNameToWidget(skel_menubar,

"Help"), NULL);



/* now label, create, and assign action to Help menu */

skel_version = XtVaCreateManagedWidget ("Version", xmPushButtonGadgetClass,

skel_helppulldown, NULL);

XtAddCallback(skel_version, XmNactivateCallback, skel_help_action, NULL);



    XtManageChild(skel_menubar);

    XtRealizeWidget(skeleton);

    XtAppMainLoop (skel_app);

    return (0);



}



To compile this program, you can use the following command line:

# gcc -o skel skeleton.c -L/usr/X11R6/lib -lXm -lXpm -lXt -lXext -lX11

This line directs the GNU linker to look in the /usr/X11/lib directories for needed libraries. The program is then linked, using the shared Xm, Xpm, Xt, Xext, and X11 libraries. The final size of the program is fewer than 13,000 characters.

How the Program Works

When you program in C to build Linux command-line or X programs, you know that if you use certain routines or functions, you must tell the compiler which #include files contain definitions needed by the functions in your program. This program starts out by listing the needed #include files for the different functions used in skeleton.c.

Next, the declaration of skeleton as a top-level widget makes information about our program available outside main(). This is because skel_help_action(), which creates a Motif dialog, needs to know whom the dialog belongs to. The next two routines, skel_exit_action() and skel_dialog_handler(), are what as known as callback routines.

Callback routines make your program work. These routines are called when you push buttons or select menu items and when your program receives information from other programs or the operating system. If you look at skel_dialog_handler(), you'll see the following line:

Page 539

XtAddCallback(skel_dialog, XmNokCallback, skel_dialog_handler, NULL);

This function tells the program what to do after the dialog appears, and when you either click the OK button, or hit the Enter key—all without a lot of extra code.

skel_help_action() is also a callback routine, called in response to the main() program line:

XtAddCallback(skel_version, XmNactivateCallback, skel_help_action, NULL);

In this instance, skel_help_action() is run when you pull down the menu item Version from the program's Help menu. The routine skel_exit_action() is called when you choose Exit from the program's File menu. After creating room for the text string containing the version information to be displayed, the skel_help_action() routine then creates the dialog with

skel_dialog = XmCreateMessageDialog (skeleton, "dialog", args, 0);

and then fills in required information with the routine

XtVaSetValues(skel_dialog, XmNmessageString, skel_string, NULL, NULL);

followed by the callback routine designation, and finally, displays the dialog with

XtManageChild(skel_dialog);

The main() routine starts with declarations for different widgets and widget elements. The call to XtVaAppInitialize() declares the application name, indicates whether or not the program should read any command-line arguments, and assigns an initial size in pixel width and height.

Sample Program Resources

The initial window size (and many other default actions of all other Motif and many X11 programs) can also be set by using resources. One way to do this is first, open your .Xdefaults file in your home directory, then type

Skeleton.height: 480

Skeleton.width:  640

and save the file. Next, replace the line

skeleton = XtVaAppInitialize(&skel_app, "Skeleton", NULL, 0, &argc,

Âargv, NULL, XmNwidth, 320, XmNheight, 240, NULL);

with

skeleton = XtAppInitialize(&skel_app, "Skeleton",NULL,0, &argc, argv,

        NULL, NULL,0);

Rebuild the program and run it. You should see a much larger window than the earlier version. Finally, yet another way to feed resources to this program is to create a file called Skeleton, type in the resource strings for width and height mentioned earlier, and save the file into the

/usr/X11R6/lib/X11/app-defaults directory. This way, the program will start with a default window size for everyone on your system.

Page 540

Continuing with the example, the client's main window as a managed widget is created next with XtVaCreateManagedWidget(); then a menu bar is built across the top of the window with XmCreateMenubar(). After that, a pull-down menu is created with XmCreatePulldownMenu(), and then a File button is built on the menu, which will respond not only to a mouse click, but also to Alt+F.

Building the rest of the File menu is now easy. Note the callback routine to tell the program what to do when the Exit menu item is selected. After the File menu, the Edit menu is created in the same way, along with the Help menu.

NOTE
Thanks are due to Ken Lee's Motif FAQ for the tip on moving the Help menu string to the end of the main window's menu bar.

Finally, the menu bar is displayed, along with the application, and the program starts waiting for keystrokes, clicks, and other events in XtAppMainLoop().

As you can see, even in a simple Motif program, there's a lot of code devoted to handling the user interface. Using Motif can save you a lot of time and effort because a lot of the code required to build, display, and handle the interface is hidden in the Motif routines. This can free you to concentrate on the internals of what your program does and gives your programs a consistent look and feel.

Shared and Static Libraries

Using shared libraries when you build applications makes sense because program binaries use a lot less space on your hard drive. But what if you want to compile a program for someone else who might not have the Motif libraries installed?

In this case, you might want to build the program using Motif's static libraries. If you do, be prepared to find that a lot of extra code is linked into your program. How much bigger will the program be, and how much of a difference using a static build will this make, you might ask? Let's see! First, you'll build a sample program in two different versions, using the gcc compiler option -static:

# gcc -static -o skel.static skeleton.c -L/usr/X11/lib

Â-lXm -lXpm -lXaw -lXt -lXext -lX11

# gcc -o skel.shared skeleton.c -L/usr/X11/lib

Â-lXm -lXpm -lXaw -lXt -lSM -lICE -lXext -lX11

Now let's see the size of the files skel.static and skel.shared:

# ls -l skel.*

-rwxr-xr-x   1 root     root        12708 Sep 12 05:12 skel.shared

-rwxr-xr-x   1 root     root      1978564 Sep 12 05:11 skel.static

Previous | Table of Contents | Next