Kenton Lee

X Application Software Engineering:
Preventing Widget Resource Syntax Errors

by Kenton Lee

Published in The X Journal, May, 1995.
Copyright © 1995 Kenton Lee. All rights reserved.

Key words: X Window System, X11, Motif widgets, X Toolkit widget resources, debugging, programming.


Introduction

In my March column[Lee95], I discussed some of the more common semantic errors that programmers commit with X Toolkit and Motif widget resources. Since resources are the primary programming interface to the X Toolkit and Motif, I thought one more column on the subject would be helpful. In this month's column, I will cover common syntax errors that programmers commit with X Toolkit resources.

You may think that the programming interface to X Toolkit resources is so simple that errors in this area are rare. One of the nice features of the X Toolkit is that it does provide a simple interface to a powerful feature and this simple interface does cut down on programming errors. Still, mistakes are common. In this column, I will look at the most common resource syntax errors, ways to avoid the errors, and ways to debug them.

By reading this material, you should learn how to identify resource syntax errors in your code, either when writing the code or later when debugging it. Hopefully, you'll be able to go one step further, as well. As Doug Young wrote in his November, 1994 The X Journal column[Young], many times bugs can be caught early through defensive programming and "self-debugging" code. Defensive code uses extensive error checking to discover bugs early in the development cycle. We'll look at ways to do this with your resource-handling code.

Function Calls

You can set and get X Toolkit widget resources through a number of different functions, but the general syntax of all the calls is similar. The functions generally look like this: XtSetArg(arg[n], XtNbackground, color); XtSetValues(widget, arg, count); or like this: XtVaSetValues(widget, XtNbackground, color, NULL); I have seen users commit syntax errors with all of the argument fields. Let's look at each of them.

The Widget ID

The widget ID is probably the hardest argument to get wrong. The widget is usually returned by XtCreateWidget() or similar. Immediately using this value is unlikely to lead to problems.

The most common way to have an invalid widget ID is to attempt to retrieve it from a linked list or other data structure, but get an invalid value instead. The best way to avoid this type of problem is to use data structure access methods that return NULL if the variable cannot be found. Since NULL is always an invalid widget ID, you can check for it using an assertion:

assert(widget); XtSetValues(widget, arg, count); Note: the assert() macro is available with most modern C and C++ compilers. If the macro's argument is zero, then it prints a descriptive error message and aborts your program. It is very simple, but useful tool for catching programming errors. For more information, check your system manual pages for details.

Valid Resource Names

Fortunately, all standard widgets provide a set of macros (like XtNbackground) for their resource names. By using these in your code, you minimize the possibility of typographical errors in these names.

Your only chance to get a resource name wrong is if you use a resource name that is not supported by your widget. If you try to set or get a resource that doesn't exist, your widget will silently ignore your request. You'll have a serious problem if your code requires something to happen. There are a couple of ways to avoid errors of this sort, depending on what you are trying to do in your code.

One possible case is an application procedure that takes a widget as an argument and tries to set or get resources on or from the widget. For example, your procedure may try to display a status message in a Motif label widget using the XmNlabelString resource. Since this resource is only used by XmLabel and its subclasses, you will have an incorrect user interface if you use the function on other classes of widget. This error was probably caused by faulty control logic in your program. A simple assertion will catch bugs of this sort:

void ShowString(Widget widget, XmString newLabel) { assert(XtIsSubclass(widget, xmLabelWidgetClass) || XtIsSubclass(widget, xmLabelGadgetClass)); XtVaSetValues(widget, XmNlabelString, xmstring, NULL); }

If you're interested in only the XmLabel and XmLabelGadget classes, rather than all of their subclasses, you could use this assertion instead[Young]:

assert(XmIsLabel(widget) || XmIsLabelGadget(widget)); You can, of course, use the above assertions with XtGetValues() as well. An alternative is to take advantage of the fact that the XtGetValues() does nothing if the resource name is invalid: int GetLabelPixmap(Widget widget) { Pixmap pixmap = 0; XtVaGetValues(widget, XmNlabelPixmap, &pixmap, NULL); assert(pixmap); } In this case, if the widget does not support the XmNlabelPixmap resource, the variable pixmap is left at its initial value of 0 and the assertion fails. If the widget does support XmNlabelPixmap, the assertion succeeds since 0 is never a valid value for this resource. This technique also works very well for pointers, when you know that a NULL pointer is indicates a bug in your program.

Valid Resource Types

A common beginner syntax error is using an incorrect data type for resource values. Values must have the correct type for the widget to use them and using a different type is normally a serious error.

For example, many beginners try something like this to set the background color of a widget to the color blue.

/* set values bug */ XtVaSetValues(widget, XmNbackground, "blue", 0) This, of course, fails since the background resource has type Pixel, not (char *). You must be careful to always use the correct types for resources. Unfortunately, there is no foolproof way for the X Toolkit to validate types; integers are usually indistinguishable from pointers.

This typing is especially an issue with XtGetValues(). For example, the following are both incorrect and I think most Motif beginners have gotten these wrong at some time:

/* two get values bugs */ char *title; XtVaGetValues(widget, XmNtitle, title, 0); int width; XtVaGetValues(widget, XmNwidth, &width, 0); In the first case, XtGetValues() needs the address of the string pointer, not the string pointer itself. What is really needed is: XtVaGetValues(widget, XmNtitle, &title, 0); In the second case, the data type of the width variable is incorrect. The correct type is Dimension, not int: Dimension width; On many computers, Dimension is 16 bits and int is 32 bits. Incorrectly using an int may cause the remaining 16 bits to be filled with garbage, giving you impossibly large values as a result.

Type Conversions

In the last section, I mentioned that colors must be pixel values, not string color names. You probably know that the X Toolkit and the widget sets provide a large number of built-in type converters. How, you might ask, should use these to convert strings to pixel values?

One technique is to use XtConvertAndStore(). Any X Toolkit text should have examples using this function.

An alternative is to use variable argument lists and the XtVaTypedArg token. This example uses the X Toolkit's string-to-pixel converter to set the pixel value resource. Note that you must correctly specify the original and the desired resource types.

XtVaSetValues(widget, XtVaTypedArg, XtNbackground, XtRString, "white", strlen("white") + 1, NULL); The XtVaTypedArg token works with XtVaGetValues() as well, though programmers rarely use this functionality since few string-to-type converters are normally installed. One XtVaGetValues() conversion that works is: XColor color; XtVaGetValues(widget, XtVaTypedArg, XtNbackground, XtRColor, &color, sizeof(color), NULL);

Argument Lists

Most of the above examples use the varargs versions of the set and get values functions. Many programmers prefer them because they make their code look cleaner.

Others prefer the older argument-list style, since it is slightly more efficient to execute. For example:

Arg args[5]; Cardinal nargs = 0; XtSetArg(args[0], XmNlabelString, xmstring); nargs++; XtSetValues(widget, args, nargs); There are two possible syntax errors with this coding style. First, if you use hard coded numbers, you could easily get the count wrong in the XtSetValues() or XtGetValues() function call. The above style of incrementing the "nargs" count variable avoids that problem, thus allowing you to easily add additional resources without having to adjust your count.

A second, and probably more common, error is to exceed the bounds of the "args" array. In the above example, the array size is 5, so you'll have a syntax error if you try to set more than 5 resources. This kind of error might be easy to make after many revisions of your code.

One easy way to catch the error is to use an assertion like this [Young]:

assert(nargs < XtNumber(args)); XtSetValues(widget, args, nargs); The XtNumber() macro computes the size of your array (assuming that it is declared as an array, rather than as a pointer) and the assertion assures you that the number of resources fits in the array.

Memory Leaks

Memory leaks can cause serious problems with X Toolkit programs. Since event driven programs often call the same resource handling code repeatedly, even small leaks can result in large problems.

Memory leaks errors are common when getting and setting resources. When setting a resource, you must decide if the widget copied the value so that you can free (or modify) your copy. When getting a resource, you must decide if the widget returned you a copy that you must free.

Unfortunately, widget sets too often do not directly document their behavior in these cases. A few general rules will help, though. Almost all widgets will copy strings, font lists, and other pointers that you set as resources, so you can free your copy. Most widget will not copy pixmaps and other server-side resources, though, so you must not free your copies of those.

When getting resource values, you have to be a little more careful. Motif should always copy the XmString's and XmFontList's it returns, so you must free your copy. The base X Toolkit widgets (Core, Composite, Shell, etc.), however, do not copy the strings that they return. For example, you must not free or modify the string returned from WMShell's XtNtitle resource.

Unfortunately, some early versions of Motif had bugs in this area, so be careful, especially with Motif 1.1. Better yet, upgrade to Motif 1.2 or Motif 2.0.

As you probably know, there are now several high quality memory debugging tools on the market. These tools catch memory leaks and other memory errors (such as over running array bounds or dereferencing invalid pointers). While good programming technique is always important, these tools will usually catch the things you miss. I highly recommend using them.

Convenience Functions

Many widgets provide convenience functions for setting and getting resource values. In most cases, using these is a good idea since their function prototypes will catch many syntax errors at compile-time rather than run-time. Compile-time error catching is always preferable, since you may not always execute particular pieces of code (until, of course, your boss asks for a demo).

Also, the convenience functions tend to be better documented than the resource values. Convenience function manual pages almost always tell you when you can free returned pointers. If your documentation isn't clear, though, Donald McMinds' book [McMinds], includes an excellent appendix on Motif convenience function memory issues.

Debugging

Now that we've learned to code defensively, hopefully we won't have any more resource syntax errors. In the remote case that you do find get one, however, here are a couple of hints for debugging them.

First, try editres[Lee94]. editres allows you to dynamically set resources for widgets in running programs. It can be very helpful in finding incorrect resource settings.

Another technique is to insert XtGetValues() debugging calls at various points in your code to make sure resources are set as you expected.

Finally, you could use a source level debugger to examine internal structure of widgets. This technique requires some understanding of the (generally undocumented) structure fields and a good understanding of how your debugger works. If you'd like to try it, first #include the private widget header files into your source files. These private header files have names with a "P.h" suffix, so you might use:

#include <Xm/LabelP.h> Then, cast your widgets' IDs to their internal widget structures. The internal widget structures are defined in the private widget header files. Some debuggers allow you to perform the cast within the debuggers. With others, you must do the cast in your code: Widget label = XtCreateWidget(...); XmLabelWidget labelTest = (XmLabelWidget) label; At a break point, you can use your debugger to examine the internal widget structure members: (dbx) print *labelTest struct _XmLabelRec { core = struct _CorePart { self = 0x1001ac20 widget_class = 0xe3d40b8 parent = 0x1000f3b0 ... Again, this output is generally only useful to people who understand the internal structure of widgets. Paul Asente's book [Asente] is a good place to learn about widget internals. Due to the complexity of widget internals, I cannot recommend using debuggers techniques to attempt to modify the values of widget structure members.

Conclusion

Setting and getting widget resource values are the main programming interfaces for the X Toolkit and Motif. While the programming interfaces are simple, syntax errors are still common. Hopefully, this material has taught you how to program defensively to avoid these errors.

References

[Asente]
Paul Asente and Ralph Swick, X Window System Toolkit, Digital Press, 1990.
[Lee94]
Ken Lee, "Debugging X Toolkit Resources with Editres", The X Journal, November, 1994.
[Lee95]
Ken Lee, "Indirect Motif Widget Resources", The X Journal, March, 1995.
[McMinds]
Donald McMinds, Mastering OSF/Motif Widgets, second edition, Addison-Wesley, 1993.
[Young]
Doug Young, "Self-debugging Code," The X Journal, November, 1994.


THE AUTHOR

Kenton Lee is an independent software consultant specializing in X Window System and OSF/Motif software development. He has been developing UNIX graphical user interface software since 1981.

Ken has published over two dozen technical papers on the X Window System. Most are available over the World Wide Web at http://www.rahul.net/kenton/bib.html.

Ken may be reached by Internet electronic mail to kenton @ rahul.net or the World Wide Web at http://www.rahul.net/kenton/.


[HOME] For more information on the X Window System, please visit my home page..


Please send me your comments on this paper:

Name: E-mail:

[X Consulting] [Home] [Mail] [X Papers] [X WWW Sites]