sort.c: C program for sort GUI example

It's probably a good idea to use the Structure of a Program Using UIL and MRM section of the OSF/Motif documentation as a guide to this program.

Unfortunately we don't seem to have html-ized man pages on-line for some of the Xt functions. I've put in links to all the ones we do have them for, though; where we don't, I've tried to put links to other sources that tell about them.


/*
   program to demonstrate simple Motif/UIL-based GUI.  This program just
   attaches a simple GUI to an insertion sort algorithm.
*/

/* Needed include files */
#include <Xm/Xm.h>          /* Needed for Motif widgets */
#include <Mrm/MrmPublic.h>    /* Needed for Mrm functions */
#include <Xm/Text.h>        /* Needed for XmTextGetString function (could
                               just typecast it */

#define ARR_LEN 10          /* Max number of items in array */
#define STR_MAX 80          /* Max length of string */

/* forward declarations for callbacks and functions */
int insert(char *newentry);
XtCallbackProc quit();
XtCallbackProc enter_item(Widget widget, XtPointer tag, XtPointer data);

/* global declarations for program-related stuff */
char *awry[ARR_LEN];        /* array to insert items into */

/* global declarations for GUI-related stuff */
XtAppContext app;           /* internal Xt variables (ie voodoo) */
Widget app_shell, sort_gui; /* application shell and our GUI     */
MrmHierarchy hierarchy_id;  /* handle for UID definitions after we read them */
MrmType example;            /* completely useless voodoo */

/* names of .uid files containing GUI specification (compiled from .uil
   files) */
String file_names[] = {
    "sortgui"
};

/* mapping from procedure name strings as used in UIL to procedure addresses
   in C program */
MrmRegisterArg callbacks[] = {
    {"enter_item", (XtPointer) enter_item},
    {"quit", (XtPointer) quit}
};

int main(int argc, char **argv)
{
    int i;
    char inbuf[STR_MAX];

    /* initialize program-related stuff */
    for (i = 0; i < ARR_LEN; i++)
        awry[i] = NULL;

    /* initialize Motif resource manager */
    MrmInitialize();

    /* create application shell to interact with window manager */
    if (!(app_shell = XtAppInitialize(&app,
                                      "Sort",
                                      (XrmOptionDescList) NULL, 0,
                                      (Cardinal *) &argc, argv,
                                      (String *) NULL,
                                      (ArgList) NULL, 0)))
        XtError("couldn't initialize application");

    /* read GUI description from .uid file */
    if (MrmOpenHierarchyPerDisplay(XtDisplay(app_shell),
                                   (MrmCount) XtNumber(file_names),
                                   file_names,
                                   (MrmOsOpenParamPtr *) NULL,
                                   &hierarchy_id)
        != MrmSUCCESS)
        XtError("unable to open hierarchy");

    /* map callback procedure names to callbacks */
    if (MrmRegisterNames (callbacks, XtNumber(callbacks)) != MrmSUCCESS)
        XtError("can't register names");

    /* fetch the widget hierarchy and create the widgets */
    if (MrmFetchWidget(hierarchy_id,
                       "mainWindow",
                       app_shell,
                       &sort_gui,
                       &example)
        != MrmSUCCESS)
        XtError("couldn't fetch mainWindow widget");

    /* tell sort_gui's parent (app_shell) to handle it when app_shell
       is realized (without this sort_gui would not be displayed) */
    XtManageChild(sort_gui);

    /* ``turn on'' the application shell */
    XtRealizeWidget(app_shell);

    /* sit back and wait for events */
    XtAppMainLoop(app);

}

/* insertion sort procedure:  creates an entry to put in the array, figures
   out where to put it, and puts it there.  If the array is already full,
   the last element is dumped */
int insert(char inbuf[])
{
    int i, j;
    char *newentry;

    /* create new entry */
    newentry = (char *) malloc(STR_MAX);
    strcpy(newentry, inbuf);

    /* figure out where it goes */
    for (i = 0;
         (i < ARR_LEN) && awry[i] && (strcmp(newentry, awry[i]) > 0);
         i++);

    /* dump the last element in the array if necessary */
    if ((i < ARR_LEN) && awry[ARR_LEN-1])
        free(awry[ARR_LEN-1]);

    /* make space for the new entry */
    for (j = ARR_LEN-1; j >= i; j--)
        awry[j] = awry[j-1];

    /* and put the new entry where it belongs */
    awry[i] = newentry;

    return(i);
}

/* callback for quit() routine.  Just dies */
XtCallbackProc quit()
{
    exit(0);
}

/* callback for carriage returns in text entry window.  Gets the data, puts
   it in the array, and copies it into a scrolled list. */
XtCallbackProc enter_item(Widget widget, XtPointer tag, XtPointer data)
{
    char *inbuf;
    int pos, itemcount;
    Widget list;
    XmString strval;

    /* find the scrolled list widget */
    list = XtNameToWidget(sort_gui, "*.sortedList");
    if (!list)
        XtError("failed to find list widget");

    /* find out how many items are in the scrolled list widget */
    XtVaGetValues(list,
                  XmNitemCount, &itemcount,
                  NULL);

    /* if it's full, dump the last one */
    if (itemcount == ARR_LEN)
        XmListDeletePos(list, ARR_LEN);

    /* get the contents of the text entry window -- notice that this is a
       plain old C string, not a fancy Motif string */
    inbuf = XmTextGetString(widget);

    /* put it in the array and find out where */
    pos = insert(inbuf);

    /* translate the simple C string into a fancy Motif string, using
       all the defaults for the local environment */
    strval = XmStringCreateLocalized(inbuf);

    /* put the string into the scrolled list, remembering that C arrays
       start numbering at 0 and Motif lists start at 1 */
    XmListAddItem(list, strval, pos+1);

    /* try to make two elements of the list visible before the new element,
       so it's in the middle of the scrolled list */
    if (pos < 2)
        XmListSetPos(list, 1);
    else
        XmListSetPos(list, pos-1);

    /* free up all the memory that's been allocated in the callback */
    XtFree(inbuf);
    XmStringFree(strval);

    /* reset the text input field */
    XmTextSetString(widget, NULL);
}