-- Libsx v1.1 -- The Simple X library by Dominic Giamapolo dbg@sgi.com Introduction: --- What is libsx? Libsx (the Simple X library) is a library of code that sits on top of and to the side of the Athena widget set. Its purpose is to make writing X applications *much* easier. To accomplish this, libsx encapsulates a large portion of the uglier details that arise while programming in X and it fills in some gaps that exist with the Athena Widget set (such as a widget for drawing graphics); libsx tries to simplify the common case down to a single function call with only a few arguments. With libsx, writing a simple program that opens a window, has a few buttons and draws some graphics (lines, circles, bitmaps, etc) is a matter of 5-10 lines of code, including the drawing code. Hello World is 2 lines. More complicated programs that respond to mouse clicks, have buttons, scrollbars, etc, can be written in 25-50 lines of code. Some libraries take the approach of completely hiding whatever they are layering on top of. In contrast, libsx doesn't drastically alter the base abstractions of X, it just packages them in the way they get used most of the time, so that with one function call and a few arguments you get the effect of 10-20 lines of pure X code. Access to the underlying X objects (Window id's, Display pointers, etc) is also possible if necessary, but not required. With libsx, the simple things are simple and the complex things are possible (where have I heard that before? :-). --- Building libsx 1. Edit the libsx_defs file in this directory and set the compiler you'd like to use and any necessary compiler flags. It is important that you take a look in this file and edit things as appropriate. By default it builds for an SGI system (gee, I wonder why that is? :-) If you are on a DECstation, their standard compiler will _not_ work as it is not ANSI compliant (gcc works great though). 2. Type make. This builds the libsx library in the src directory and all the demo programs in the other subdirectories. If you're short on disk space, you can go into any particular directory and type make there. For anything else to work, the libsx/src directory must be compiled first. A word of caution. On some suns that have motif installed from a third party, you'll get lots of warnings about symbols being re-defined when compiling libsx. This is because of an incompatibility in the way the X header files get installed for the motif product (not sure who makes the one I encountered problems with). Anyway, the warnings are innocuous but definitely annoying. Unfortunately I can't seem to make them go away. The demo program that shows most of the features of the library is in the src directory (the executable is called `demo'). The other demo programs demonstrate various aspects of the library. Feel free to use them as skeletons for your own programs. The code has been compiled on wide variety of systems and compilers. It should be mostly clean POSIX code, but I would appreciate hearing about any difficulties you have while compiling. I have personally compiled it cleanly on Sun3's and 4's (SunOS 4.1.1 mind you), SGI (Indigo's, PowerSeries, Onyx, etc), and DECstations 3100/5100's. People on the net have told me that they've gotten it to work on HP-UX, Linux, SVR4.2, AIX 3.2, Sequent/ptx, and numerous other systems. A while ago I compiled it cleanly on a DG Aviion running a very strict version of SVR4. I've used gcc to compile it as well as the native compiler on most of the platforms. The code is ANSI C, so if you don't have an ANSI compiler, sorry.... Libsx also requires the Athena widget set, which isn't as omni-present as I once thought. I guess HP doesn't ship it on all of their systems. I can't help you much there. Bitch at your vendor and tell them to ship a version of the Athena widgets if you don't have it. BTW, there's no Imakefile because I don't understand imake (nor have I made much of an attempt to understand it). Imake seems like overkill for libsx. If someone would like to write an Imakefile, I'd gladly include it in future releases, but it's not likely I'll do it myself. --- More details about libsx The reason I wrote libsx was so that I could whip up simple X programs in not much time and not lots of X code. Originally it started because I wanted an easy way to write programs to draw graphics, but libsx also grew to encapsulate most of the other Athena widgets making all sorts of GUI programs possible The essential idea with libsx is that creating the user-interface should be simple and you should spend your time on the code that implements the logic of your program. In libsx, the core functions that control your application are connected to user-interface elements as callback functions. That is, when the user does something interesting with your interface, your callback function gets called. All of the low level management details are handled for you. Each user interface item (buttons, scrollbars, drawing area's, text entry, etc) only requires one function call to create it. One of the arguments to this creation routine is the name of a callback function that will be called each time an interesting event happens to that widget. For example, when a button or menu item is clicked on/chosen, your callback routine gets called. When a drawing area needs to be redrawn, your callback gets called. The intent of libsx was to ease the common case. For example, here is the code to create and manage a single line string entry with libsx: void str_callback(Widget w, char *string, void *data) { printf("You pressed: %s\n", string); } void main() { .... MakeStringEntry("preset text", 200, str_callback, NULL); } The first function is the callback function that gets called when the user presses return in the widget (and it just prints what the user entered). The call to MakeStringEntry() builds the widget and takes care of setting all the necessary resources and translations for everything to work. In comparison, the equivalent code in regular X calls is on the order of 20-25 lines of code (not counting the callback function which would be the same for both). Another example is drawing graphics. The plain Athena widget set does not provide a drawing area widget (like Motif does). Libsx includes David Nedde's Athena drawing area widget and encapsulates it so that a simple program to open a window and draw some graphics is now reduced to only a few lines of code. More complicated programs build upon the simple model and although creating the user interface may involve more lines of code, the basic model is the same. --- What exactly does libsx provide? Libsx encapsulates the following interface components (all based on Athena widgets, except for the DrawingArea widget which belongs to David Nedde): -- labels -- buttons -- radio button groups and toggle buttons -- single line text entry -- multi-line text entry (full text-edit box) -- scrollbars (horizontal or vertical) -- scrolling lists -- menu buttons (buttons with pop-up menus) -- drawing areas (you can draw in these and also receive mouse/keyboard events if you like) -- multiple form widgets (more advanced, not normally used) After creating the interface components you need, you lay-out your display in a logical fashion. The SetWidgetPos() function lets you specify what widgets are next-to or underneath (or both) other widgets. This avoids hard-coding pixel positions and makes setting up a display pretty simple and quick (though to be fair, some more complicated displays involving centering and such can be difficult if not impossible). You can easily change widget attributes and use different fonts. There are some simple dialog box routines (for getting yes/no answers and getting a single string). Libsx can also open multiple windows (even on different screens) and you can build your own dialog boxes (modal windows) if you like. Libsx also supports obtaining, managing and using colors (either individual colors or an entire 8-bit colormap). Getting specific named colors or colors based on RGB values is as simple as calling a single function (no need to worry about colormaps, color cells, or any of the other junk X makes you worry about). Grabbing the entire colormap is also very easy. Effectively, libsx maintains a lot of state for you; it manages all the grungy X details while providing a cleaner set of routines for your program to use. --- Has libsx traded complexity for functionality? I don't think so. While libsx makes it trivial to write simple programs (as mentioned before, hello world is 2 lines of code), it's also been used to write some fairly substantial programs. I've written 3-D object editors and all sorts of wire-frame/shaded graphics previewers. This afternoon I got fed up with XLess and wrote an equivalent replacement with a real file requestor in about an hour. Most of the time was spent working on the logic of how the program should behave, not the user interface. A friend used it to write a complete 3-D modeling/rendering system. I've written tons of small graphics programs with it (reaction-diffusion and iterated function system demos, etc). I've used it for a contract application that required a simulation of a train set on screen (modeled correctly to scale, etc), and I've been kicking around ideas for some sort of word processor/editor. Libsx is not some all-singing all-dancing type of library, but it does make writing common X applications substantially easier. If you do need the extra confusionality, I mean functionality that X offers, all the standard X functions are available and you have access to the Widget id's, Display pointers, etc. The point is that you don't have to worry about that if you don't want to. --- Where did libsx come from? I developed libsx over the course of about 2 years while in graduate school at Worcester Polytech (in good ole Worcester, Mass.) It all started when I took the grad course in Computer Graphics. I wanted a nice library of routines to deal with all the X crap so I could concentrate on my graphics code. Soon the library started evolving into a much more sophisticated thing and when I became the TA for the graphics course, I beefed it up a lot. When you have 65 undergrads beating on a library you've written, it's got to be solid. The next time that I was TA, I polished up some more rough edges in the library (the stuff the students complained about) and it went through the ringer a second time with about 45 more students. Finally, during the summer of 1993 I added a ton of more functionality to the library so a friend of mine could write his 3-D editor the way it should be written and so I could do some stuff I wanted to do. In September of 1993 I was hired at SGI and I've done a little bit more work on libsx since I've been here (mainly little cleanups and the rudimentary OpenGL support). That is effectively what you see today. I've spent a lot of time deciding how to structure libsx so it would be easy to use but still be open ended. Libsx doesn't try to hide all of X, it just tries to make it more digestable. The library has gotten pretty big at this point, but it should be sufficient to write most types of GUI programs without lots of fuss. I've also spent a lot of time deciding what should and shouldn't be in libsx. It's too easy to throw in everything just because it's easy to do so. Unfortunately that's almost never the right reason to include something. I've tried to pare the design down to the essentials needed to write a useful application. Comments and critiques of the design/approach are welcome (I'd like to hear what others have to say about it or how they would have done it). --- Does libsx hurt performance? I've never really noticed any problems and most of this code was developed originally on a Sun3 (so if it ran ok there it's almost guaranteed to run fine on anything else because a Sun3 is a pretty damn slow machine nowadays :-). Seriously though, once you've created the interface and put up the display, there isn't much libsx code that gets in the way of your application. Many calls go direct to your application and a few are routed through libsx code, but nothing fancy happens there. Using libsx I was able to write programs that interactively manipulated three dimensional objects of up to several hundred vertices with the mouse on a Sparc IPC, so I don't consider performance to be a problem. --- What are the drawbacks to using libsx? The single biggest drawback that I can think of is that some layouts of widgets are not possible because of limitations in the Athena Form widget. For example, it's impossible to create a widget that is centered in a window (to the best of my knowledge the Form widget doesn't support this, example code to the contrary would be greatly appreciated). This is a bit of an annoyance, but usually isn't too much of a problem. Libsx also doesn't let you name your widgets individually, so customization through your .Xdefaults file is possible, but not as flexible as it could be. For example, within a single program, all button widgets get called "button", and all label widgets are called "label" which makes it impossible to invdividually identify widgets in your .Xdefaults file. This means you can't use your .Xdefaults to specify that button X has green text with a purple background while button Y has orange text on a chartruse background with blue highlights. Either all your buttons are purple with green text or they are chartruse with orange text, but not both (hopefully none of them are either :-). This could be fixed by adding a name argument to the MakeXXX() functions, but I'd prefer not to add another argument to those routines. It's also possible to add a SetWidgetName() type of function which is a nice way to do it, but then it really starts to make generating an interface a very complicated thing. Maybe I'll add a SetWidgetName(), but for now I don't think so. The customization thing hasn't been too much of a big deal for me (you can still customize, it's just not as infinitely flexible as the underlying X mechanisms). Presently libsx doesn't offer much support for detecting double clicks. This is because of two reasons. First, X doesn't provide any way for a user to get/set their preferred double-click time (at least as far as I know, example code to the contrary is welcomed) Second, getting sub-second timer accuracy in a portable fashion turns out to be rather problematic. I've just learned that the times() function can be used in a roundabout way to get sub-second timing, but POSIX isn't as well and cleanly supported as one might hope. If you'd like to see code that checks for double-clicks, look in the freq directory at freq.c. It uses times() and seems to work well. --- Where do I go from here? If you haven't already done it, compile libsx. This builds the library itself and numerous demo programs. Then take a look at the demo programs and the code behind them. The main demo program is in the libsx/src directory (and is called `demo'). It demonstrates most of the features of libsx. The other directories contain demos of varying complexity and these are your best starting point for building your own applications. The most complicated application would be `bezier' which lets you interactively play with bezier curves. It's a good framework for handling user-interaction and what not, so have a look at the sources. Feel free to use the demo sources as the basis for your own programs (but of course I'd appreciate it if you give credit where credit is due). The directories freq, creq, and multireq contain code written by a friend of mine, Allen Martin (amartin@wpi.wpi.edu). Freq contains a file requestor function based on libsx. Freq provides a single function GetFile() that lets a user select a file while browsing through the directory hierarchy. Creq is a color chooser utility that lets a user select a color using RGB or HSV values (with sliders and all that jazz). Multi-req is a very nice way to do form-fillout dialogs. Take a look at the sample code in these directories and you should be able to figure out how to make use of the functions. The documentation is always a nice thing to read too (especially since I put so much time into it :-). The documentation isn't in man page style format (yet), sorry about that. It was easier to write this way. The documentation tries to cover all the bases, and with the example code, it shouldn't be hard to figure out (heck, if second year college students can do it with little or no help.... :-). If you have comments/criticism on the docs, let me know. If you'd like to convert the docs into a man page format, I'd also like to know :-) The documentation to start reading first is either libsx_intro or general.libsx.doc. Those introduce you to the basics and then you can go look at the more specific doc files for each of the various areas in libsx. Well, that about sums it up. I hope you find libsx handy and that you can make some use of it. Any comments, questions or other communication can be sent to: Dominic Giampaolo dbg@sgi.com Have Fun! p.s. Oh yeah, I need a disclaimer: This code was written by me, Dominic Giampaolo, and should not be taken to represent Silicon Graphics in any way, shape or form. I've written it on my own time, and for my own purposes. SGI has nothing to do with it, so don't bother them about it. (does that sound legal enough? :-)