This was a talk given at the X Technical Conference, 1990 . It was relevant for X11R2, and some portions are still relevant today.

Affiliations and addresses should be current. The books and articles recommended are still among the best, though most have newer editions!


Pitfalls In Widget Writing ...

And

In Using Widgets In Applications

Susan Liebeskind

Engineering Sciences Laboratory
Georgia Tech Research Institute
Atlanta, GA, 30332
USA
(sl11@prism.gatech.edu)

Miles O'Neal

Pencom Software
9050 Capital of Texas Highway North, Suite 300
Austin, TX, 78759
USA
(meo@pencom.com)

August, 1990

Abstract

Having beat ourselves nearly senseless developing one of the first commercial X11 products, we decided we ought to offer some of the wisdom we picked up along the way to our fellow X developers. In particular, we learned quite a bit about widgets, and about the dangers lurking therein to destroy the schedules of the unwary.

This is not by any means a proper introduction to writing widgets, although it may prove helpful in that context. We assume the reader has some familiarity with at least the concept of either writing or using widgets.

An earlier version of this paper was presented at the 4th Annual X Technical Conference held in Boston, Massachusetts (USA) in January of 1990.

Prelude

During a good part of 1988 and 1989, we were involved in the development of what turned out to be, as near as we can tell, the first commercial (non-development) product based on X11. As a result, we had to do a good bit of groping in the dark.

We investigated extensively the few toolkits and widget sets that were available at the time, and decided upon the Xt intrinsics and the Athena widget set (Xaw) that came with the standard distribution.

There were no books on X11 out at the time we started the project; Usenet and some materials from a pre-release DECwindows training course were our resources beyond the distribution tape.

By the time we were done, we were amazed at just how much we had learned during the project. The questions we have seen in the comp.windows.x newsgroup imply that others are struggling with the same sorts of problems we had. Thus, we decided to share what we have learned about developing and using widgets.

We were developing on Sun 386i systems, under SunOS 4.0.2, with X11R2 (and later X11R3) using the C language, so everything we say is directly applicable to this and similar environments. However, as X11 is pretty much X11 no matter what the environment, most of the information should transfer to other situations pretty much intact.

Details, Details

The work was performed at Sales Technologies, Inc., (ST) in Atlanta.

The product is an application generator, running under UNIX and X11, which produces DOS and VMS files which drive other proprietary products. It is fairly complex, as are many of the interactions between its widgets.

At any given time, two hundred or more widgets may be active, and any given run of the program may easily involve over a thousand widgets. This does not include duplication of widgets created and destroyed on the fly, of which there may be many more.

Later we will reference a field. This is an emulation of a data entry field in a PC-based windowing program. Each field contains numerous data structures, one of which is a widget. The widget window is the only part of the field the user actually sees. When a user selects a field with a mouse button the field window inverts.

Making Things Happen

There are several ways to "make things happen", i.e. to take action in response to an X event; some of these are available at the basic toolkit level, while others are built into the widgets themselves.

The O'Reilly X Window System Series Volume 4 X Toolkit Intrinsics programming Manual and Doug Young's book X Window Systems Programming and Applications with Xt (see Books to Take on a Desert Island) both contain an excellent discussion of the first three items mentioned here.

Event Handlers

An event handler is a routine registered by a client (or by a widget itself) which handles events of a particular type when they occur on that widget's window. Once an event handler is registered, the Xt intrinsics take care of invoking it when the associated type of event occurs on that widget.

Callbacks

Callbacks are routines provided by either the widget programmer or the application programmer, which may be invoked any time either programmer deems necessary. They are placed in arrays known as callback lists. The callbacks on a given list are normally invoked by calling XtCallCallbacks(), and passing in the name of the list.

Additional callbacks may be registered on an existing list by the application programmer. As an example, "button" widgets typically execute a callback list when pressed or released. Adding to the callback list is an easy way to bind application-dependent behavior to a button.

A widget may contain as many callback lists as its developer deems necessary. Likewise each list may contain as many callbacks as needed. All widgets contain a Destroy callback list, which is called prior to a widget being destroyed.

Translations & Actions

The translation manager might be considered the lex and yacc of Xt. Taken together, the translation tables and action tables allow the user to specify any number of action routines to be called upon the occurrence of any sequence of user actions. The translation manager then determines when a given sequence of actions has occurred, and invokes the correct action routines.

A user action is an event directly initiated by a user, such as a mouse button event or a keypress, as opposed to (for example) an expose event.

Each entry in a translation table binds a sequence of user actions to one or more logical action routines. Each entry in an action table binds a logical action to a physical action routine name.

These action routines may be defined within the widget or by the application. An application can add action routines to those provided by a widget. Furthermore, an application may either add to or override the translation list for any widget.

Accelerators

Accelerators appeared in X11R3. An accelerator allows the binding of events within a widget to actions from another widget. An example given in the R3 intrinsics documentation gives the example of invoking menu actions from the keyboard.

An obvious example of an accelerator, at least to us, was a general help popup bound to the HELP key, that would give context-sensitive help (for each particular widget on the display).

A problem we ran into here is that we could only get routines declared in a widget's table to run when the accelerator event occurred. It appears that accelerators are bound to a widget at compile time, whereas we needed to install something from the application. We finally gave up and simply added a help translation to every widget in the tree. This example does not invalidate the accelerator concept; it simply points out a limitation of the implementation.

Translation tables are the preferred method for handling events; they are more flexible in many ways than either event handlers or callbacks, and they may easily be modified through the resource manager.

Callbacks are handy to use when both the application and the widget must pass data into a routine; we used both types of data frequently with command buttons. Keep in mind that the callback lists are predefined - an applications programmer may define callbacks for existing callback lists, but cannot add new callback lists to the widget.

Event handlers are the lowest level of abstraction for event methods. (Actually, when you use the translation manager, the Xt intrinsics implement the translation mechanism as XtEventHandler routines, allowing you to deal with the events/actions on a higher level basis.) Use them only when you have a good reason to hardwire events into the widget. In real life, there aren't many such reasons.

Accelerators make it very easy to write a general-purpose routine to use in more than one widget, without having to specifically add code to each widget to invoke the routine.

A summary table appears below, showing the relative strengths and weaknesses of each approach.

Method               Strengths          Weaknesses
------------------   ----------------   -------------------
translation tables   most flexible   
                     easily modified   

callbacks            data flexibility   lists predefined

event handlers                          lowest level

accelerators         reusability        must be in a widget

Generating Events

Once you have your event methods in place, you should try to avoid calling them directly. Normally, these methods are local to the widget (static routines in C) and clients don't know about them. The proper manner of invocation is by generating the appropriate event. This allows proper partitioning of the tasks within the widget code.

For example, an Expose routine in a widget might be invoked by calling XClearArea(), which generates an Expose event. In the case of the ST BoxTextWidget (a simplified TextWidget), the AddChar() routine simply places the new characters in their buffer locations and calls XClearArea(); the Expose method routine actually draws the text, but does not have to clear the area, which in some cases would be redundant. Furthermore, this eases the task of telling the Expose routine the area exposed, as that data is passed with the event.

If all else fails, XSendEvent() may be used to send the desired event to the widget's window.

Resources

One of the main tenets of X11 is the concept of "mechanism, not policy". It is intended especially that this be applied to X resources. In nearly every case, the application should avoid setting the resources directly, to allow the user as much control as possible.

While some things may suggest themselves as needing to be under programmer control, it's rare that resources fit this category. Button names are a typical example. Using the resource database for button names allows easy translation to other languages, or customization for unexpected environments. Some systems' users may expect "exit" to save work and "quit" to cancel, while others may expect the opposite setup. And if some neanderthal really wants to set their foreground/background combination to taupe/mauve and you don't let them, you have an unhappy customer.(Determining the definitions of taupe and mauve is left as an exercise for the reader.

For those users who don't know or care about resources, you should supply reasonable defaults through resource files. X provides for default system, application and user resource files in standard locations. This is covered in O'Reilly Volume 4.

Pointers vs Objects Themselves

Something that is not obvious from merely reading the code of existing widgets is that the value field for a resource must normally be an address. The documentation is clear on this.

In R2 there was no XtRImmediate type. Early on, in haste due to a deadline, we copied a resource which had a value of 0 to a new resource, which we gave a value of 1. We got some truly strange core dumps. The R3 XtRImmediate resource type makes things much more straightforward.

Setting Up New Ones

Chapter 11 of the O'Reilly Xlib Reference, Volume I, and Doug Young's Xt book both contain explanations of how to set up resources. Unfortunately, there are no standards for querying the client to find out what resources you can set for it. You must depend on the documentation for the program to find out what resources are available.

A somewhat de facto standard for this is to have the client generate a list of available command-line-modifiable resources either when a bad option is entered or when the option "-help" is given.

The R4 release provides a hook for resource querying but the information is not readily available.

Timing Issues

We had a number of timing problems under R2; we had less with R3 and expect them all to go away with R4. We also believe in the Tooth Fairy.

These problems were more exaggerated when running clients and servers on separate systems, and even more so when using a slow X11 terminal instead of a workstation-based server. (Faster X terminals had fewer such problems.) Many problems that occurred in all of the above circumstances were easily fixed on the workstations, but continued to plague the people running the clients on X terminals. Workstation loading often had a detrimental effect as well.

The problems seem to be related primarily to the asynchronous nature of X, and secondarily to time stamps.

Some timing issues are related to the specific server implementation in use. For example, HP/Apollo provides its own version of the X server for its Apollo workstations. This server has the capability of working with Apollo's own window manager, rather than replacing it. Unfortunately, this has resulted in some event delivery problems. (Apollo is not unique in such problems.)

Waiting For Godot

An ongoing problem is getting the user to wait for the client to catch up with event processing. Certain user actions result in quite a bit of processing, including much widget state updating.

The ST application builds PC screens for other software ST sells. Each field (representation of a data entry field . created on the PC screen) has quite a bit of information associated with it. When a user selects a field, one or more database queries occur, and as many as 50 widgets on the screen may be affected. Some of these may need to be mapped, others may have to be created, and the rest will be redrawn. The result, especially over a busy net, with a busy workstation, is that anywhere from 1 to 5 seconds may transpire between the select action and the entire sequence completing. Most of the time this is merely annoying. Later we will explain why this is sometimes a serious problem.

Forcing Events Through

There are cases where the client and server must be in sync. The -sync option provided with X helped in some, but not all, cases. It always made things too slow, so we decided to simply force a sync when we needed one.

We quickly discovered that neither XFlush nor XSync alone would do the trick. We developed a routine that did the trick for us although it was kludgy and still a bit slow (especially the R2 version).

This is not optimal but it works better than anything else we found.

Under R2 we did the following:

Widget desk;  /*a top level widget*/

void StXFlush()
{
   XEvent event;

   XFlush (XtDisplay(desk));
   while (XtPending()) {
      XtNextEvent(&event);
      XtDispatchEvent(&event);
   }
   XSync (XtDisplay(desk), 0);
}
Under R3 this no longer worked, due to changes in the way the event queue is processed, so we explored a bit and came up with the following:
Widget desk;  /*a top level widget*/

void StXFlush()
{
   XFlush (XtDisplay(desk));
   while (XtPending()) {
      XtProcessEvent(XtIMAll);
   }
}

We also revised our recommendations as to the maximum number of users concurrently running the application on a given system, and encouraged heavy users with X terminals to have their own network.

Bad Timing

The following problems were all found to be timing-related, and appear to be directly or indirectly tied to the X server.

Time Stamps (& Lack Thereof)

Some events have no time stamps. This occasionally results in events happening out of order. One place this causes confusion is when a FocusIn event, which has no timestamp, arrives after a keypress, which has one. In this case the keypress gets delivered to the wrong place (if a FocusOut event was also delayed) or discarded altogether.

There is no easy fix for this type of problem.

Events Without Windows

We don't mean the windowless widgets called gadgets here. Sometimes users select a button on a popup window, and when they get no immediate feedback (server/net/whatever lag) they will click the mouse button again, convinced the computer has not registered the event or that they have not clicked yet. Occasionally this event will reach the client after it has destroyed the widget, or at least unmapped the window. The result is a spectacular crash.

MapNotify and UnmapNotify events have no timestamps; this appears to be at least part of the problem.

Windows Without Widgets

The most heinous of the timing problems we have found is when a user gets way ahead of our application in creating fields. We sometimes end up with what we call phantom fields - apparently created fields on the PC screen region of the application which are not part of the widget hierarchy.

A window will be displayed by the server, but one of several strange behaviors will occur. The window cannot be selected; clicking a mouse button on it merely results in a beep from the server. It appears that this window has become disembodied from a widget.

At other times, the window will act normally as far as the mouse is concerned, but does not bring up the expected database information. Moving or resizing the window connected with the displayed database information moves this phantom field window as well. It appears that two windows have become attached to the same widget. This is, of course, theoretically impossible. (See screen shot.)

In each case, we have not been able to isolate the bug. The only theory we have developed and not subsequently disproved is that the problem ultimately lies in the fact that the Xt intrinsics code is generally not reentrant. (This is true for R2 and R3, and somewhat in R4.) Interrupting widget creation/modification routines to create/modify another widget could well be the heart of the problem.

We are currently relying on user training to solve this problem.

Widget Partitioning

When to Write a Widget

Whenever you need reusable functionality that relates to window I/O, you should probably write a widget.

When Not to Write a Widget

There are times when new functionality is required but time does not allow for in-depth analysis of the issues involved in putting that functionality into a widget. In these cases, which become less frequent as expertise in widgets and object-orientedness increases, it may be expedient to write a callable routine which wraps this functionality around an existing widget or widgets, using standard (non-object-oriented) techniques. For lack of a better term, we call these metawidgets.

The other time not to write a widget is when the required functionality involves a complex programming interface. Even these cases may be widgetized, at some loss of widget method orthogonality. A widget with potentially large arrays, whose individual elements must be accessible individually, is a good example.

Nested Event Loops

These can be dangerous, since the R2 and R3 Xt intrinsics are not reentrant. Many of our metawidgets go into an event loop waiting for a particular event (the dreaded modal application!). Attempting to enter another metawidget from one of these loops usually either locks things up, causes core dumps, or corrupts data somewhere.

Death & Destruction

Every widget class has a Destroy callback list inherited from the Core widget class; each widget should have its own Destroy method if it allocates any resources of its own. This method should be invoked to free up the various widget resources whenever the widget is no longer needed. We found that if the widget was not properly destroyed, there were severe memory leaks in both the application and the server.

On the other hand, there are potential problems with using the Destroy callbacks. Most inherited (or chained) methods are called in topdown order beginning with the Core widget class. Destroy methods are called bottomup, so superclass Destroy methods must not refer to any subclass parts.

Always use the appropriate intrinsics calls to create or allocate resources, as well as destroy them. This applies to the widgets themselves as well.

Miscellaneous Widget Performance Considerations

Widget Lifetime

Widget creation and destruction is expensive, as mentioned before. When a lot of widgets are being created and destroyed on the fly, this may become very noticeable to the user. If this is the case, you may want to rethink the lifecycle for some of your widgets.

When similar widgets are frequently created and destroyed (such as top level button boxes or popup informational boxes) it may be better to create each one once, either at startup or first usage as necessary. After that, simply unmap them instead of destroying them. Wherever you would have created a new one, update the appropriate widget component (such as the button label) and remap them.

When varying numbers of similar widgets are used, consider creating a pool of widgets pointed to by an array or linked list. The pool may be expanded or contracted as required using standard array or linked list manipulation routines.

The above approaches are based on the fact that while users want a system to react quickly most of the time, they will accept occasional lapses. What most users do not want is a system that appears to be slow most or all of the time. Many widgets may be created at startup time; after that consider carefully whether to create widgets on the fly, reuse existing widgets, or use widget pools.

Reparenting

At times it would be handy to be able to reparent a widget. This is still not generally a viable option as certain widget resources are inherited from its parent in the instance tree. Reparenting the widget requires quite a bit of mucking about in the instance tree, examining and modifying resources.

Debugging in Xland

X11 -Sync Option

The synchronous option causes the server to interact synchronously with a client. This slows things down, but is occasionally helpful for isolating aberrant behavior.

XSynchronize

When you can identify key areas of code where synchronization is required, you can call XSynchronize() to turn synchronization on and off. You will definitely want to monitor performance to determine whether this is an effective solution. If your code is generating lots of server roundtrip events in these sections, the application will run much slower than it would otherwise.

Printf Problems

In R2, especially without the synchronous option, debugging printf()s sometimes don't complete before a core dump. We sometimes had to use sleep() calls after the printf(). Be sure and use a fflush() after your debugging print statements.

Debuggers

Any standard debugger (such as dbx or gdb) should be usable with X11 programs.

You can debug from your X11 display in a separate xterm if your client doesn't do mouse or keyboard grabs. It is often easier to use a separate physical terminal or display, if possible.

The cleanest way to start a debug session is to start the client normally, and then attach the debugger to it by passing the client's process ID as a command line option. Unfortunately, not all debuggers support this option. As always, RTM for information on your debugger.

It's not a good idea to have the debugger catch the SIGIO signals, or you generate an interrupt for every single mouse event.

Debugging is intrusive by nature. The very act of debugging causes different results than would otherwise occur. This problem can be greatly exaggerated with many X clients.

As an example, if you step past a line that requests the next key pressed, you will probably have to step past at least one more line before the debugger will be able to see the results of the key code request.

To Olkit or not To Olkit

That is the question. Actually, the question is usually when to use a widget set, as only widget writers are usually interested in a toolkit without a widget set. The phrase toolkit here refers to the combination of toolkit intrinsics (Xt or others) and a widget set.

When to Use a Toolkit

Speed Considerations

If you need a really fast client but have a slow system, you may wish to avoid the toolkits, or at least make sure one of the available kits is fast enough. There are a number of areas in the ST application that fairly beg to be dewidgetized, as they are nearly intolerably slow on a Sun 386i/150.

One example of this is dragging the fields around the PC screen region. This is currently handled with the widget drag and resize routines, but should probably be replaced with fast line-drawing and rubberbanding - the widget can then be dropped once the move or resize is finished.

Graphics Orientation

If the application is heavily graphics oriented, a toolkit may well prove too slow, at least for the graphics portion of the application. Also, at this time, there is not much real graphics support in commercially available toolkits.

A fractal drawing program, for instance, could be done using a 1-pixel widget for each point, but would hardly be worth the effort as it would be substantially slower and larger than one built on top of raw Xlib calls.

User Interface Considerations

If the application has a user interface that is the least bit sophisticated, toolkits are definitely the way to go.

A spreadsheet would be much easier to implement with widgets than without them.

If a user interface builder (user interface management system) is available for your system and toolkit, you will find it speeds interface development quite a bit. Evaluate them carefully for size and speed of code produced.

Text Considerations

If the application mixes text fonts or sizes within a work area, current toolkits are not much help.

Resource Usage

Like any software decision, a number of variables go into the choice of a toolkit. These include the audience sophistication, platforms involved, and portability. The application programmer also needs to be aware of the resource issues.

Human

Programming with a toolkit is, within the guidelines above, generally a more productive endeavor from the standpoint of design and implementation time. Also, unless you are writing a toolkit, the learning curve for a toolkit is usually quicker than for Xlib.

Computer

Widgets are for the most part resource hogs. They eat both memory and CPU time. Windowless widgets, such as gadgets, help somewhat in this respect. Some toolkits, such as Motif, take gadgets even farther and eliminate duplication of certain resources within each widget type.

To illustrate these tradeoffs, we offer the following notes about the commercial application mentioned earlier.

In its latest release, the application consisted of about 60,000 lines of source code, and took about 45 person-months to produce (including X11 training). Without using a toolkit, this would have been somewhat larger, taken longer to produce, and would be much more difficult to modify and maintain.

On the other hand, the optimized, stripped executable is about 750KB in size, and requires from 3 to 5 MB of memory at runtime. Without a toolkit, the executable would have required somewhat less runtime memory and executed between 20 and 30 times faster. (This represents our best estimate for the application generator package. Your mileage may vary.) To aid in reducing program size, some sites choose to build the X libraries as sharable. When running a diverse mix of X clients, this is a good idea. For turnkey systems or any time most of the users are running the same client, the client should be linked sharable, especially if it is very large. If in doubt, try both approaches with your expected client mix and load.

R4 runs substantially faster than R3; future versions of the application will benefit greatly from this speedup.

Straddling the Fence

Some types of application benefit from judicious use of a toolkit and the X intrinsics. A drawing editor might use a few widgets for most of the user interface while relying on lower-level graphic routines for the drawing region.

Which Toolkit to Use

If portability is a primary consideration, Xt and Xaw from the MIT tapes, and the "open" commercial products such as Motif and Open Look are good bets. Other user-contributed toolkits from the MIT tapes may work, but examine them carefully and find out what support will be available. We originally had some interest in the HP Xray toolkit on the R2 tape, until we found out support would not continue with R3.

The X11 philosophy of "mechanism, not policy", does not totally extend through the toolkits. Some widgets or toolkits may encourage, if not enforce, certain policies. This may be compared to software engineering. The concepts behind software engineering comprise a mechanism, but selection of a methodology, design tool, or language immediately defines policy to some extent. This is apparent in the Open Look and Motif standard user interface guidelines, for example.

Standard Commercial Toolkits

At this time, the standardization wars between the Open Software Foundation (OSF) and Unix International (UI) continue. Toolkits are only one of the issues being determined.

OSF, consisting of DEC, HP/APollo, IBM and others too numerous to mention, provides the Motif toolkit. UI, guided by AT&T and Sun, backs the Open Look toolkit. Developing portable applications to run across platforms from all these vendors, yet keeping a consistent look and feel, is therefore still a problem.

The current de facto standard in the marketplace is Motif. Last year the European Commission selected Motif as its user interface in the absence of any standard. UNIX vendors are for the most part making the same choice. Most of the current and soon-to-be-released X applications are Motif-based, although many developers are promising Open Look versions at some point.

DEC, committed at one time only to DECwindows, now ships Motif as well. AT&T is considering adding Motif support to future releases of System V. Sun, however, citing the large volume of SparcStations shipping with the Open Look interface and related toolkits, remains adamantly behind Open Look. The official explanation from Sun is that Open Look will become the standard by sheer weight of numbers. Unofficially, higher-ups at Sun have indicated Sun will support Motif only over their dead bodies.

What can you do in the meantime? As with other portability concerns, isolation of toolkit calls is a good idea. This can make toolkit ports relatively painless, assuming you do your homework in determining the subset of operations you need, and how they are supported. An Open Look/Motif subset interface definition is in the works by at least one group.

Note that most commercial toolkits at this point are based on R3.

Object-Orientedness Issues

As much as possible in a C environment, Xt is object-oriented. But much of the client development being done is also in C. (At least two sets of C++ bindings have been posted to comp.sources.x. Ada and FORTRAN bindings are available through many vendors, and others are on the way.) Therefore how object-oriented you should be becomes a major issue.

How OO Should You Be?

The X Consortium stresses object-orientedness, and suggests that all derived toolkits and widgets keep this orientation. Non-OO extensions are fine, but should be in addition to, and not instead of, the current OO-based methods. As an example, all widget data should be accessible via the GetValues and SetValues methods, but convenience routines to access this data are fine, too.

OO in Non-OO Environments

Always write for your environment. This includes the experience of other people on the project team, company standards, and so forth. But be aware of the advantages that object-orientedness can give. These may outweigh the other considerations.

There are always trade-offs, but it is usually best to work within the language at hand. If you attempt to make C look like something else, be sure you are aware of the impacts this has on programmer productivity, project schedules, and the like.

We compromised. The widget code conforms to the guidelines of the Consortium, as do most of the interfaces. The rest of the code usually looks like standard C.

Breaking The Rules

Conformance to the rules is somewhat audience-driven. The decisions are much the same with X11 as with anything else.

When Should You?

Efficiency is the primary "legitimate" reason for breaking the rules, whether this is programmer efficiency, runtime efficiency, or good coding practices.

The other main "legitimate" reason is when following the rules doesn't work. While we had less problems with R3 than with R2, there were still a few cases where following the rules didn't work. (Bear in mind that, by definition, the specification is correct, even if the implementation is not. This can make life very interesting. Fortunately very few such cases have turned up in the released MIT code.)

Remember that quick hacks often turn into production code, or at least widely used code.

Staying Out of Jail

Other than kidnapping the appropriate X Consortium member, we know of no X11 equivalent to a Get Out of Jail Free card. But staying out of trouble in X is not that difficult.

Know What The Rules Are

"Ignorance is no excuse." If you don't know the rules you can't very well play the game. Read the documentation provided with your implementation of X. Get some of the books mentioned in the bibliography. If at all possible, read through some real-world examples.

Know Why The Rules Are

Understanding why decisions were made, and why certain practices are suggested, enables you to make a more intelligent decision.

Know Why You Want To Break The Rules

If you don't have a good reason to break them, you probably ought to stick with the rules. Discipline will pay off in the long run in terms of readability, maintainability, and portability. As an example, the Athena widgets often call methods directly, which is theoretically improper. This was typically done to speed up widget processing.

Realize, also, that many of the rules and guidelines are related to inter-release compatibility. Something that works now, but does not conform to the rules, may well not work with future releases of X11.

Acknowledgements

First and foremost, we wish to thank the members of the X11 community who participate in the discussions on the Usenet in comp.windows.x; we would never have completed the project without their help. In particular, Paul Asente, Donna Converse, Jim Fulton, Ken Lee, Joel McCormack, Chris Peterson and Bob Scheifler have been most helpful.

In addition, Oliver Jones and Doug Young were a great help, both via email and through their books, as were the folks at O'Reilly (in particular Tim O'Reilly and Adrian Nye).

We offer a special thanks to Dany Guindi, for going out of his way to teach us about X, and for all of his help and support.

Finally, we are deeply indebted to Paul Anderson, our former project manager, for giving us the freedom to learn and explore X so thoroughly during the course of the project, and for his valuable insights into X and user interface programming.

Books To Take On A Desert Island

The following references are taken from an X TECHNICAL BIBLIOGRAPHY, compiled by Ken Lee (klee@decwrl.dec.com) and regularly submitted to the comp.windows.x newsgroup. There are other good books and papers as well; these are the ones we personally found to be the most helpful.

Jones, Oliver, Introduction to the X Window System, Prentice-Hall, 1988. ISBN 0-13-499997-5. An excellent introduction to programming with Xlib (Release 2). Written with the programmer in mind, this book includes many practical tips that are not written anywhere else. You'll still need the MIT Xlib manual, as this book does not try to be totally complete. Highly recommended for beginning Xlib programmers.

McCormack, Joel and Paul Asente, "Using the X Toolkit or How to Write a Widget," in Proceedings of the Summer, 1988 USENIX Conference, pp. 1-13. An excellent tutorial on writing basic X Toolkit widgets. Potential widget writers (and maybe users, too) should probably start by reading this paper. Unfortunately, it's based on X11R2, so some of it is out of date.

O'Reilly and Associates, The X Window System Series (7 volumes), O'Reilly and Associates, 1988, 1989, 1990. ISBN 0-937175-26-9, 0-937175-27-7, etc. This is a 7 (and growing) volume set of books. Volume 1 is a new tutorial on Xlib. Volumes 0, 2, and 3 are approximately the same as the MIT manuals (protocol manual, Xlib manual pages, and popular client manual pages). Volumes 4 and 5 cover the Xt toolkit and Athena widget sets. They currently describe R4, or are being rewritten to do so. Differences from R2 and R3 are covered. Future volumes will reportedly cover the X Toolkit intrinsics, XView, and Motif. Written by technical writers, these are probably the most professional looking of the X books.

Rosenthal, David S., "Going for Baroque", in Unix Review June, 1988, pp. 70-79. A version of the "hello, world" paper, presenting and comparing the basics of the X library and the X Toolkit. All potential X programmers (Xlib or X toolkit) should understand everything in this paper before they attempt writing any X programs. Included in the MIT X distribution.

Young, Doug, X Window Systems Programming and Applications With Xt, Prentice-Hall. ISBN 0-13-972167-3. An excellent tutorial on programming with the Xt intrinsics. Examples in this book use the HP widgets, but a Motif edition is available as well (ISBN 0-13-497074-8).


Last updated: 10 July 1996

Copyright 1989, 1990, 1994 Susan Liebeskind and Miles O'Neal, Austin, TX. All rights reserved.

Miles O'Neal <roadkills.r.us@XYZZY.gmail.com> [remove the "XYZZY." to make things work!] c/o RNN / 1705 Oak Forest Dr / Round Rock, TX / 78681-1514