The 40 Most Common X Programming Errors (And How To Avoid Repeating Them) byKenton Lee Published in The X Journal, March, 1993. An earlier version of this paper, titled "Behind Curtain X," was published in Unix Review, vol. 2, no. 4, June, 1991. Copyright © 1991, 1993 Kenton Lee. All rights reserved. Key words: X Window System, X11, Motif widgets, application development, programming errors. ------------------------------------------------------------------------ ABSTRACT The X Window System has come a long way since Version 11 was first released in 1987. There are now thousands of X programmers developing thousands of X applications. Together these X programmers have probably made thousands of programming errors, many of them the same errors over and over. This paper reviews the 40 most common X programming errors. Hopefully, by seeing them here, you will be able to avoid repeating them in your programs. CONTENTS * INTRODUCTION * DESIGN AND STYLE ERRORS o ERROR 1. Not using the X Toolkit. o ERROR 2. Improper event handling. o ERROR 3. Improper exposure handling. o ERROR 4. Violating the X Toolkit's object-oriented paradigm. * SYNTAX ERRORS o ERROR 5. Confusing functions with similar names. o ERROR 6. Exceeding data set length limits. o ERROR 7. Boundary conditions. o ERROR 8. Zero window sizes. o ERROR 9. Invalid event masks. o ERROR 10. Using XGetWindowAttributes() with pixmaps. * USAGE ERRORS o ERROR 11. Expecting synchronous behavior. o ERROR 12. Backing store expectations. o ERROR 13. Default GC expectations. o ERROR 14. GC Root and depth. o ERROR 15. GC cache. o ERROR 16. Window background. o ERROR 17. Pixmap backgrounds. o ERROR 18. Drawing on window backgrounds. o ERROR 19. Top level windows and the window and the window manager. o ERROR 20. Input hints. o ERROR 21. Multi-screen errors. * X TOOLKIT USAGE ERRORS o ERROR 22. Realizing widgets. o ERROR 23. XtApp* vs. non-App functions. o ERROR 24. XtAppAddInput() and regular files. o ERROR 25. XtSetValues() and type converters. o ERROR 26. X Toolkit resource pointers. o ERROR 27. X Toolkit data types. o ERROR 28. Top level shell widget resizing. o ERROR 29. Not all X Toolkit functions apply to application programs. o ERROR 30. Invalid pointers to application callback data. * INTEROPERABILITY ERRORS o ERROR 31. Hardware characteristics. o ERROR 32. Bitmaps vs. pixmaps in windows. o ERROR 33. Bitmaps vs. pixmaps in widgets. o ERROR 34. PseudoColor vs. StaticColor. o ERROR 35. Fonts. o ERROR 36. Colors names. o ERROR 37. Simultaneous colors. o ERROR 38. Pixmap and property sizes. o ERROR 39. X Protocol Extensions. o ERROR 40. Other ICCCM issues. * CONCLUSION * REFERENCES * THE AUTHOR INTRODUCTION The X Window System has come a long way since Version 11 was first released in 1987. There are now thousands of X programmers developing thousands of X applications. Together these X programmers have probably made thousands of programming errors, many of them the same errors over and over. This paper reviews the 40 most common X programming errors. Hopefully, by seeing them here, you will be able to avoid repeating them in your programs. X programming errors, like most programming errors, fall into four general categories: 1. Design and style errors. 2. Syntax errors. 3. Usage errors. 4. Interoperability errors. The following sections describe the most common X programming errors in each of these areas. This paper is not a tutorial on X programming, but could be used as a companion to an X tutorial. Several excellent X Window System programming tutorials are listed in the references section at the end. [1-3] DESIGN AND STYLE ERRORS X, like all other window systems, supports some program programming architectures much better than it does others. By designing your programs to follow these styles, you can more efficiently use the best features of the X Window System. Programs with very different architectures may not be able to access all the features of X, if they work at all. ERROR 1. Not using the X Toolkit. The X Toolkit (sometimes called Xt) is an integral part of the X Window System. It encapsulates user interface functionality into subclassable and reusable widgets and manages an X application's input distribution. The X Toolkit greatly simplifies and standardizes the development of high quality X application[4] Popular UNIX graphical user interfaces such as OSF/Motif are based on the X Toolkit. Almost any X program can be written using the X Toolkit, so there is rarely a need to use any other programming interface. ERROR 2. Improper event handling. Event handling is probably the most difficult window system concept for beginners. Most text-based UNIX programs perform blocking reads on the standard input while they wait for user interaction, as shown in Figure 2a. This is fine when the only input stream is the keyboard, but rarely works in a graphical, pointer-oriented environment. A robust X client must be able to respond to any valid user input at any point in time. This includes user requests for resizing, iconifying, or exposing a window, as well as pointer or text input to any of its input fields. ------------------------------------------------------------------------ puts("login: "); gets(name); puts("Password: "); gets(password); Figure 2a. Dumb terminal string input ------------------------------------------------------------------------ An event loop is built in to the X Toolkit, eliminating this problem for X Toolkit users. If you must use the lower level Xlib programming interface to manage your events, the easiest and most flexible way to handle all this input is to write your program as a single event loop or event driven state machine. Figure 2b shows an Xlib example using a single event loop. Designs with no event loop or more than one event loop can sometimes be made to work, but often not easily or very well. ------------------------------------------------------------------------ /* request events */ XSelectInput(dpy, win1, ExposureMask | ButtonPressMask | ... ); XSelectInput(dpy, win2, ExposureMask | ButtonPressMask | ... ); ... /* infinite event loop */ while(1) { XEvent xev; XNextEvent(dpy, &xev); switch(xev.type) { case Expose: redraw(&xev); break; case ButtonPress: button(&xev); break; /* other events ... */ } /* procedure to redraw contents of window */ redraw(XExposeEvent *xev) { if (xev->window == win1) /* draw based on contents of event */ } Figure 2b. Xlib event loop example. ------------------------------------------------------------------------ ERROR 3. Improper exposure handling. The most common special case of ERROR 2 is not properly synchronizing your graphics drawing with X expose events. If your client requests, the X server will send it an expose event whenever a portion of one of its windows is ready for drawing. If the client attempts to draw without waiting for these expose events, the drawing may never be displayed. A good design is to request expose events for your event loop and to only call your drawing procedure after expose events are received. Again, the X Toolkit automatically handles expose events for you. If you must use Xlib, the example in Figure 2b handles expose events properly. ERROR 4. Violating the X Toolkit's object-oriented paradigm. If you use the X Toolkit, as recommended above, you should follow two basic rules to fully take advantage of it. The first rule is to use the event loop feature, as described above. The tutorials[1] all cover this point pretty well. The second rule is to not fight the object-oriented paradigm built into the the X Toolkit. The X Toolkit organizes user interface semantics into object-oriented widgets classes and instances. This structure of encapsulating all your user interface semantics into widgets works very nicely. Some programmers, however, intentionally violate the object-oriented paradigm by extracting internal widget data and putting most of their user interface semantics into external functions. An example of undesirable code is extracting the windows from widgets using XtWindow() and putting the drawing (exposure handling) semantics into callback functions. A common excuse for writing code like this is that the proper technique, writing new widgets with the desired semantics, is too difficult. In reality, hacking around the object-oriented paradigm is much more difficult, especially when you try to maintain it later. Now that there's a good tutorial available on writing your own widgets[1], there's really no excuse for violating the object-oriented paradigm. SYNTAX ERRORS The most popular X Window System application programming interfaces are function libraries for the C programming language. As with any other C function interfaces, syntax errors, such as providing invalid arguments to functions, are very easy to make. Here are some of the most common ones. Some will cause X protocol errors. Others will give everyone's favorite UNIX error message: Segmentation fault (core dumped). ERROR 5. Confusing functions with similar names. Unfortunately, a few incompatible X functions and data types have similar names. You must be careful to use the correct one. If you're lucky, you'll get a segmentation fault if you use the wrong one. If you're not so lucky, your program will just give you random results. Some common problem areas are listed below. XSetWindowAttributes, XWindowAttributes, and XWindowChanges are similar, but different, X data structures. XSetWindowAttributes is used with XChangeWindowAttributes() and XCreateWindow(). XWindowAttributes is used with XGetWindowAttributes(). XWindowChanges is used with XConfigureWindow(). The GC and GContext data types are two ways to refer to a graphics context. You almost always want to use the GC, not GContext. The Screen structure and screen number (integer) are two ways to refer to a display screen. The screen number is more commonly used in Xlib; the Screen structure in the X Toolkit. The manual will specify which to use in a particular function. The display string and Display structure are two ways to refer to a display. The Display structure is used in almost every Xlib function. The display string is only used to open new display connections. XSetBackground() and XSetWindowBackground() are two very different functions with similar names. XSetBackground() changes the background pixel component of a graphics context, while XSetWindowBackground() changes the background pixel of a window. ERROR 6. Exceeding data set length limits. Several X functions, e.g., XFillPolygon(), accept a variable amount of data, but they do have limits. X guarantees that these functions will work with data sets of up to approximately 16K bytes. Some implementations have higher limits and some Xlib implementations automatically break up some, but probably not all, of the requests to fit within the size limits, but you still should be careful with large requests. If you exceed the size limits and your Xlib doesn't break up the requests, your program will generate BadLength errors. The XMaxRequestSize() function will tell you the real maximum length supported by the current X server. XMaxRequestSize() returns the size in bytes of the maximum request, so you'll probably want to convert this to a unit more appropriate to your function, such as to a number of points for XFillPolygon(). Some conversion examples are given in Figure 6. Note that XMaxRequestSize() first appeared in X11R4. ------------------------------------------------------------------------ XDrawLines() points: XMaxRequestSize(dpy) - 3 XFillPolygon() points: XMaxRequestSize(dpy) - 4 XDrawSegments() segments: (XMaxRequestSize(dpy) - 3) / 2 XDrawRectangles() rectangles: (XMaxRequestSize(dpy) - 3) / 2 XFillRectangles() rectangles: (XMaxRequestSize(dpy) - 3) / 2 XDrawArcs() or XFillArcs() arcs: (XMaxRequestSize(dpy) - 3) / 3 Figure 6: Maximum data set sizes for common variable length requests ------------------------------------------------------------------------ ERROR 7. Boundary conditions. The X coordinate space is not infinite. Most drawing functions limit position, width, and height to 16 bit integers (sometimes signed, sometimes unsigned) of accuracy. Because most C compilers use 32 bit integers, Xlib will not complain if you exceed the 16 bit limit, but your results will usually not be what you expected. You should be especially careful of this if you are implementing higher level scalable graphics packages. Note that as some coordinates are treated as signed and some as unsigned: you can potentially create windows or pixmaps with regions that cannot be reached by X drawing functions. X will not protect you from this so you should be aware of this limitation if you are creating very large windows. ERROR 8. Zero window sizes. If a program attempts to create a window with a width or height of zero, it will receive a BadValue error. Many widgets use zero as their default width and height, assuming that the user will override these with meaningful values before the widget realizes its window. When writing widgets, you must check the size before creating the window and report a user friendly error when the user does not override the zero size. ERROR 9. Invalid event masks. Many X functions have event bit masks arguments. Often, these functions require that the bits in the event masks represent members of a particular subset of all events. You should be careful to set only the bits in these masks that are valid for the function, otherwise you may get BadMatch errors. For example the event mask in XGrabPointer() should specify only pointer events. An event mask with the KeyPress event bit set is invalid. Older X servers are often much less strict about event masks than are newer X servers. Some older public domain clients are sloppy about their event masks and worked with the older X servers, but generate BadMatch errors with newer X servers. To help users with buggy older clients, some newer X servers have a "bug compatibility" mode, but programmers should, of course, not rely on this. ERROR 10. Using XGetWindowAttributes() with pixmaps. One popular X programming book says that XGetWindowAttributes() works on pixmaps as well as on windows. They are wrong. The Xlib specification does not require this and, with almost all implementations, XGetWindowAttributes() only works on windows. To request the size and depth of a pixmap, you should use XGetGeometry(). USAGE ERRORS X is a very powerful window system. As with any powerful system, several aspects of its functionality are frequently misunderstood, leading to unexpected behavior. This section and the next review some common misunderstandings and how to avoid them. This section covers general X usage problems. The following section covers common usage problems specific to the X Toolkit. ERROR 11. Expecting synchronous behavior. For efficiency reasons, the X Window System usually operates asynchronously, meaning that a client's X requests are buffered by Xlib and processed in groups. You only need to worry about this in unusual cases. One side effect of the buffering is that X protocol errors will not be reported until the Xlib buffer is flushed. You can still correlate the errors with your requests by temporarily running X in the synchronous mode. You can enable the synchronous mode with either the X Toolkit -synchronize command line option or the Xlib XSynchronize() function. Another side effect is that your drawings will sometimes, though rarely, not be updated when you think they should. If you find that this happens, you can explicitly flush the Xlib request buffer with XFlush(). You should only use XFlush() when absolutely necessary, however, as unnecessary flushing can significantly affect your client's performance. ERROR 12. Backing store expectations. Many X clients use the backing store feature for improved performance. Backing store is, however, not guaranteed. Some X servers do not support it at all and most will drop it if memory becomes limited. Your program must be able to deal with these two cases. Since the X server will not send you Expose events if backing store is working, the X Toolkit event loop or the Xlib event loop in Figure 2b will work fine even if you are using backing store. ERROR 13. Default GC expectations. Creating excessive numbers of graphics contexts (GCs) can be expensive, so your client may want to use the default GC or share GCs between windows when you can. Be careful when using the colors and fonts in the default GC, however. The colors may not be visible on your window background and the font may be the wrong size. Create your own GC with XCreateGC() if these are potential problems. ERROR 14. GC Root and depth. While graphics contexts can often be used for windows other than the ones for which they were created, they will not work on windows with different roots or depths. You will get a BadMatch error if you try to do this. Be especially careful of this limitation when writing programs that use more than one screen or visual class. ERROR 15. GC cache. Most Xlib implementations cache graphics contexts to improve performance. The major side effect of the cache is that your GC values are usually not checked until the GC is actually used. In some cases, this makes debugging a little harder, so be aware of it if you get CreateGC protocol errors in unexpected places. A second side effect is that separate clients cannot reliably share GCs. While cooperating client programs can profitably share X server resources such as windows and pixmaps, they should not attempt to share GCs. ERROR 16. Window background. X automatically maintains a window's background if the window's background pixel or background pixmap attributes are set. If you change these attributes after the window is created, however, the change may not be immediately drawn on your screen. X only updates the window's background when an exposure occurs. If you need to force the window's background to be redrawn, you can force an exposure with Xlib functions like XClearArea() and XClearWindow(). ERROR 17. Pixmap backgrounds. Most Xlib drawing functions can be used both on windows and on pixmaps, but XClearArea() and XClearWindow() are exceptions. Because these functions use the window's background attributes and pixmaps do not have background attributes, using these functions on pixmaps will generate BadWindow errors. You must use XFillRectangle() on pixmaps, specifying the new background attributes in the graphics context. ERROR 18. Drawing on window backgrounds. Some programs attempt to assign window background pixmaps with XSetWindowAttributes(), then draw on the pixmaps, assuming that the drawing will show up in the drawn window. This only works with some X implementations. Other implementations copy the background pixmap when it is set, so changing the pixmap later will have no effect. Instead, you should use the event loop as shown in Figure 2b, requesting expose events. The example in Figure 18 shows how pixmap copying (sometimes called BITBLT'ing) can be used with the event loop. ------------------------------------------------------------------------ expose_event_handler(xev, pix) XExposeEvent *xev; /* expose event */ Pixmap pix; /* pixmap with drawing */ { Display *dpy = xev->display; Window win = xev->window; int x = xev->x int y = xev->y; int width = xev->width; int height = xev->height; GC gc = DefaultGC(dpy, DefaultScreen(dpy)); XCopyArea(dpy, pix, win, gc, x, y, width, height, x, y); } Figure 18. Expose handling by copying from a pixmap. ------------------------------------------------------------------------ ERROR 19. Top level windows and the window manager. All of the popular X window managers will reparent your top level windows to add various decorations such as a title bar or resize handles. You should account for this when inquiring about your windows' position and ancestors. For example, XGetGeometry() will report position relative to the window manager window, not relative to the root window, as you might expect. Use XTranslateCoordinates(), as shown in Figure 19, to convert these coordinates to the root window's coordinate space. ------------------------------------------------------------------------ XGetGeometry(dpy, win, &root, &oldx, &oldy, &w, &h, &bw, &depth); XTranslateCoordinates(dpy, win, root, oldx, oldy, &newx, &newy, &c); Figure 19. Converting window position to root coordinate space ------------------------------------------------------------------------ ERROR 20. Input hints. The window manager is in charge of managing keyboard input focus. Many window managers will only assign input focus to windows that request it. If your client asks for keyboard events but does not receive them, you probably have not set your window manager input hint properly. If you're using the X Toolkit, the input hint may be set by setting your shell widget's XtNinput resources to TRUE. If you're not using the X Toolkit, see the ICCCM[3] for instructions. ERROR 21. Multi-screen errors. Workstations supporting several screens are starting to become popular. X supports multiple screens, with a few limitations. In particular, most X server resources can only be used with the screen (and other resources created for the screen) for which they were created. For example, you cannot use a pixmap created for screen 0 in a graphics context created for screen 1. Another example is that you cannot move a window from one screen to another screen. Also, clients should take care not to hard code assumptions about screen numbers. The default screen can be set by the user, so the client should use the DefaultScreen() macro rather than assume that the screen number is 0. X TOOLKIT USAGE ERRORS The previous section discussed general X usage errors. Many common usage errors are specific to X Toolkit programming. These are described in this section. ERROR 22. Realizing widgets. An X Toolkit widget does not have an associated window until it is realized. Before that, the widget's window is usually set to an invalid value, such as 0x0, and you will get BadValue or BadWindow errors if you try to use it with X functions. This is often a problem with programs that violate the X Toolkit model, as in ERROR 4. It can also be a problem with improperly written widgets. Remember that a widget's initialize class method is called before its realize class method. Data structures requiring the widget's window should be initialized in the realize method or when used, but not in the initialize method. ERROR 23. XtApp* vs. non-App functions. Many X Toolkit functions have both "App" (e.g., XtAppMainLoop()) and "non-App" (e.g., XtMainLoop()) versions. Always use the App versions, as the non-App versions are obsolete. Non-App functions do not support some X Toolkit functionality and are not always compatible with the App functions. ERROR 24. XtAppAddInput() and regular files. The X Toolkit XtAppAddInput() function is very useful for processing input on UNIX-style file descriptors. Many programmers, however, misunderstand the semantics of this function. Registering a source and condition with XtAppAddInput() causes your callback function to be called whenever the source is ready for that condition, for example when a socket is ready for writing. If you use XtAppAddInput() on a source that is already ready for your condition, you callback will be called repeatedly, wasting your CPU cycles. In particular, you should not use XtAppAddInput() to read from regular UNIX files, as they are almost always ready for reading, regardless of whether or not there is new data to be read. If you really need to read from regular files, one solution is to create a separate process, such as tail -f, that checks the end of the file and sends you updates over a UNIX pipe or socket. You can then use XtAppAddInput() on the pipe or socket. ERROR 25. XtSetValues() and type converters. The X Toolkit automatically calls type converters when you set resources through the client command line or through resource files. The converters are not called, however, when you set resources with XtSetValues(). When using XtSetValues(), you must convert the data types yourself or call the converters manually. XtConvertAndStore() calls the X Toolkit type converters. The example in Figure 25, taken from [1], converts a color name to a pixel value, appropriate for specifying a widget foreground or background color. Alternatively, you can use the XtVaSetValues() function with the XtVaTypedArg token, though this method offers less opportunity for error checking. ------------------------------------------------------------------------ XrmValue source, dest; Pixel bluePixel; source.size = strlen("blue") + 1; source.addr = "blue"; dest.size = sizeof(Pixel); dest.addr = &bluePixel; status = XtConvertAndStore(w, XtRString, &source, XtRPixel, &dest); if (status == False) { /* unknown color, do appropriate thing */ } else { Arg warg[2]; Cardinal n = 0; XtSetArg(warg[n], XtNforeground, bluePixel); n++; XtSetValues(widget, warg, n); } Figure 25. Converting resources in X Toolkit programs. ------------------------------------------------------------------------ Note that, in practice, you rarely have to manually convert resources as most clients read their resources from resource files and those that are set in programs are usually already the correct type (integers or widget pointers). ERROR 26. X Toolkit resource pointers. Most X Toolkit widgets are controlled by setting and getting resource values. When setting resource values, you should sometimes specify them directly and sometimes specify them indirectly through pointers. In general, the only values set directly are integers and characters (including unsigned, short, and long); all others values should be set as pointers. (Note that some old widget sets also set floating point numbers directly, but this doesn't work properly with many compilers, so should be avoided.) When getting resource values, you should always supply a pointer to the correct data type. Be especially careful with string pointers: you must specify a pointer to a string (char **), not a pointer to a character (char *). ERROR 27. X Toolkit data types. You should be careful about interchanging integer-based X Toolkit types. For example, the Dimension data type is a 16 bit unsigned integer and the Position data type is a 16 bit signed integer. When you mix the two, the C language's type promotion rules apply, which may not be what you were expecting. Also, when getting Position and Dimension resource values, be sure to pass addresses of variables of the correct types to XtGetValues(). In some implementations, these are 16 bit integers. Passing the address of a 32 bit integer may cause the remaining 16 bits to be filled with invalid data, thus producing incorrect results in your program. ERROR 28. Top level shell widget resizing. Occasionally, your X Toolkit application will want to resize its top level shell widget, possibly to add newly created child widgets. The shell widget will does not resize itself by default, however. This usually causes the new widgets to be hidden outside the edge of the shell widget. To avoid this problem, set the XtNallowShellResize resource of the shell widget to TRUE. The default value of FALSE requests that the shell widget not resize itself when its children resize themselves. ERROR 29. Not all X Toolkit functions apply to application programs. The X Toolkit intrinsics are used both for writing new widgets and for manipulating existing widgets from application programs. Most intrinsics functions can be used for either task, but some should only be used for one or the other. Reference [1] is very clear about which functions are appropriate for application programmers, but, unfortunately, other X Toolkit books are not. For example, the XtMoveWidget() function should be used only within widgets. Application programs desiring this functionality should use the XtSetValues() on XtNx and XtNy instead. ERROR 30. Invalid pointers to application callback data. X Toolkit callback functions are a powerful mechanism for event handling. For the programmer's convenience, X Toolkit callback functions generally support a client data parameter that the application may supply when registering the callback. This client data is passed back to the client when the callback is executed. You should be careful to supply only client data that will be valid when the callback is executed. In particular, pointers to local variables will generally not be valid. If you want to pass a pointer to a variable or to a structure, you should declare it globally or dynamically allocate it with XtNew() or XtMalloc(). INTEROPERABILITY ERRORS X supports a networked client-server model. Because of this, your X client does not know at compile time with which X server it will be interacting at run time. X programmers frequently forget this and write programs that fail with X servers or hardware that is even slightly different from their own. This section reviews some common interoperability errors. ERROR 31. Hardware characteristics. The X visual type facility allows an X client to work properly with a wide variety of X servers. A client that relies on color models, screen depths, etc. should check and set the visual type properly.[5] Clients should also be careful not to rely on other hardware characteristics, such as the number of buttons on the mouse, the size of the screen, the maximum size for cursors, etc. Various Xlib macros and functions allow you to query and/or manage most of these values. ERROR 32. Bitmaps vs. pixmaps in windows. An X pixmap is an off-screen drawable with any depth supported by the screen. An X bitmap is a pixmap with a depth of exactly one. X provides several functions, such as XReadBitmapFile() and XCreateBitmapFromData() to simplify the creation of bitmaps. Pixmaps can be created with functions like XCreatePixmapFromBitmapData() or the popular, but non-standard, XPM library. Programmers should be careful not to use bitmaps where pixmaps with the depth of a particular window are required. One common error is creating bitmaps with XReadBitmapFile() and using these bitmaps as window backgrounds attributes or copying them to windows with XCopyArea(). These techniques will only work if the window in question always has a depth of one, i.e., monochrome windows. Since windows are usually created with the same depth as the screen, programmers should use algorithms that work for all windows. ERROR 33. Bitmaps vs. pixmaps in widgets. Many X Toolkit widgets use bitmaps and pixmaps as resources. Unfortunately, the manuals don't always do a good job of telling you exactly what is needed. For example, shell widgets have a XtNiconPixmap resource that must be a bitmap, not a pixmap with a depth of other than 1. On the other hand, label widgets in most widget sets have a label pixmap resource that must be a pixmap with the same depth as the widget's window. If your documentation is not clear on what pixmap depth is needed, you may want to try both to see which works. ERROR 34. PseudoColor vs. StaticColor. Many X clients automatically assume that the default visual type of a color X server is PseudoColor. This is usually true, but at least one major vendor ships color X servers with a default visual type of StaticColor. On StaticColor visuals, any request to allocate new colors will be denied. If your client requires a writable colormap, it should make sure its windows are created with writable visual types, such as PseudoColor. ERROR 35. Fonts. Different X servers support different sets of fonts and there is no guarantee that a given X server will support a particular named font. X clients should use XQueryFont() to see if the font exists before trying to load it. If a client tries to load a font that does not exist, it will get a BadName error. ERROR 36. Colors names. Many X clients use names, rather than RGB values, to specify colors. This is convenient and most X servers support similar color names, but clients should at least consider the case where XLookupColor() reports that a given color name is not found. Also, be aware that different X servers (and different monitors) may interpret color names differently; the same color name often displays differently on different hardware. ERROR 37. Simultaneous colors. Due to hardware limitations, X servers can only support a certain number of simultaneous colors. X requests such as XAllocColor() will report a failure if no more colors can be allocated. Programs should be able to recover from this, possibly by reusing colors or creating a new colormap. To avoid this problem, designers should also consider using shared, read-only color cells (XAllocColor() and XAllocNamedColor()) instead of private, read-write color cells (XAllocColorCell() and XAllocColorPlanes()). ERROR 38. Pixmap and property sizes. Pixmaps and window properties are created by allocating memory in the X server at the request of X clients. Clients should be careful when using them because memory may be limited in the server. There are two cases of which you should be especially wary. First, the X specification does not specify the maximum possible sizes of pixmaps and window properties. Many X servers using graphics accelerators will limit the size of pixmaps to the size of the screen. Applications should avoid using pixmaps larger than this. The X display macros DisplayHeight() and DisplayWidth() tell you the size of the screen. Allowable window property sizes are even more variable. In general, clients should avoid problems with property sizes by not using properties as a general inter-process communication mechanism. Properties should be used for storing small amounts of window-specific data, such as is described in the ICCCM[3]. ERROR 39. X Protocol Extensions. X protocol extensions such as Display PostScript and PEX provide powerful graphics functionality which can greatly improve the performance and simplify the development of clients. There is no guarantee, however, that a particular X server will support a given extension. Use XListExtensions() to make sure the server supports the extensions you need. If the extension you request is not available, you can try to fallback to a client-side emulation or you may simply print an error message and exit. If you choose the later method, make sure your extension requirements are clearly documented. ERROR 40. Other ICCCM issues. David Rosenthal did the X community a great service by writing the Inter-Client Communication Conventions Manual (ICCCM) [3]. It covers some of the interoperability issues mentioned in previous sections, plus others like selections and managing limited resources in a shared access environment. Many programmers use the phrase RTFM to answer X questions. The M in RTFM is often the ICCCM. CONCLUSION Those of you who are experienced X programmers will probably remember having made many of these errors. Hopefully, I've shown you some that you have not yet made and now will not make. If you already knew about all of these, send me your resume. REFERENCES There are many books available on X programming. Only a few, however, contain good practical information on how to avoid programming errors and write robust programs. In particular, I recommend: 1. Paul Asente and Ralph Swick, X Window System Toolkit, Digital Press, 1989. This book contains an excellent tutorial on X Toolkit programming as well as the definitive specification for the X Toolkit. 2. Oliver Jones, Introduction to the X Window System, Prentice-Hall, 1989. Even if you use the X Toolkit, you will have to use Xlib within your widgets. This book is an excellent tutorial on Xlib programming, but is not as complete as [3]. 3. Robert Scheifler and James Gettys, X Window System (Third Edition), Digital Press, 1992. This book is the definitive specification for Xlib and the X protocol. It also contains a copy of the very important Inter-Client Communication Conventions Manual (ICCCM). It is not a tutorial, so beginners should get [2], too. 4. David Rosenthal, "A Simple X11 Client Program," Proceedings of the Winter, 1988 USENIX Conference, 1988. 5. David Lemke And David Rosenthal, "Visualizing X11 Clients," Proceedings of the Winter, 1989 USENIX Conference, 1989. 6. David Rosenthal, "Window Exchange," UNIX Review, Vol. 7, No. 12, January, 1990. ------------------------------------------------------------------------ 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/. ------------------------------------------------------------------------ For more information on the X Window System, please visit my home page.. ------------------------------------------------------------------------ Please send me your comments on this paper: Name: E-mail: ------------------------------------------------------------------------