packages icon
		          -- 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? :-)