[comp.windows.x] A bug in the Tree Widget from Young's X book

wong@cathedral.cerc.wvu.wvnet.edu (Dennis Hiulum Wong) (10/24/90)

I have found a bug in the Tree widget from Young's book, 
"The X Window System: Programming and Applications with Xt,
Motif Edition" (I got the source code from expo.lcs.mit.edu).
The Tree widget works fine for a binary tree, but has problem 
with non-binary tree. The following is an example in which I 
create a PushButton and a ScrolledWindow for displaying the 
tree. When I click on the button, the program will destroy the
tree widget (if there is one there)and rebuild the tree. If I 
keep on pressing the button, for the first few times it works 
ok, but eventually it crashes on me.

Does anyone have a fix for it? Where can I report this bug?
Any comments are welcomed.

-- Dennis
   wong@cerc.wvu.wvnet.edu

------- cut here -------------------------------------------

#include <stdio.h>
#include <X11/StringDefs.h>
#include <X11/Intrinsic.h> 
#include <Xm/Xm.h>
#include <Xm/PushBG.h>
#include <Xm/PushB.h>
#include <Xm/Form.h>
#include <Xm/ScrolledW.h>
#include "Tree.h"

/**********************************************************/
char *strtok();
Widget tree_node = NULL;
Widget sw;
static char *list = "a ( bb cc ( ee ( kk oo ) ff ) dd ( gg ) ) ";
char tree_str[300];

/**********************************************************/

button_handler (w, client_data, call_data)
  Widget  w;              
  caddr_t client_data;   
  caddr_t call_data;     
{
  if (tree_node != NULL) {
    XtDestroyWidget (tree_node);
    tree_node = NULL;
  }
}
/**********************************************************/

button_handler2 (w, client_data, call_data)
  Widget  w;              
  caddr_t client_data;   
  caddr_t call_data;    
{
  Arg    wargs[10];
  int i;
  static char *tok;
  char *show_tree();

   /*
    * Create the tree widget.
    */
  if (tree_node == NULL) {
    i = 0;
    XtSetArg(wargs[i], XmNborderWidth, 0); i++;
    tree_node = XtCreateManagedWidget("tree", XstreeWidgetClass, 
                                sw, wargs, i);
 
    strcpy(tree_str, list);
    tok = strtok(tree_str, " ");

   /*
    * Create the widgets representing the tree.
    */
    show_tree(tree_node, NULL, 1, tok);
  }
}

/**********************************************************/

print_name(w, client_data, call_data)
  Widget  w;              
  caddr_t client_data;    
  caddr_t call_data;      
{
  printf("level %d\n", (int)client_data);
}

/**********************************************************/

char *show_tree(parent, s_node, level, token)
  Widget parent;     
  Widget s_node; 
  char *token;
  int    level;
{
  Widget   w;
  Arg      wargs[10];
  int      n = 0;
  XmString str;

  while (token != NULL) {
printf("token:%s|\n", token);
    if (*token == '(') {
      token = strtok(NULL, " ");
        token = show_tree(parent, w, level + 1, token);
    }
    else if (*token == ')') {
      token = strtok(NULL, " ");
        return(token);

    }
    else {
        str = XmStringCreate(token, XmSTRING_DEFAULT_CHARSET);
        n = 0;
        XtSetArg(wargs[n], XtNsuperNode, s_node); n++;
        XtSetArg(wargs[n], XmNlabelString, str); n++;
        w  =  XtCreateManagedWidget(token, xmPushButtonWidgetClass, 
                parent, wargs, n);
        XtAddCallback(w, XmNactivateCallback, print_name, (caddr_t)level); 
        XmStringFree (str);

        token = strtok(NULL, " ");    
    }
  }
}

/**********************************************************/

main(argc, argv)
    int argc;
    char **argv;
{
  Widget toplevel, win, w1;
  int    i, xargc; 
  char   **xargv;
  Arg    wargs[10];


  toplevel = XtInitialize(argv[0], "DisplayTree", NULL, 0, 
                          &argc, argv);

  i = 0;
   XtSetArg(wargs[i], XmNwidth, 300); i++;
   XtSetArg(wargs[i], XmNheight, 240); i++;
  win = XtCreateManagedWidget ("Window", xmFormWidgetClass, 
      toplevel, (ArgList)wargs, i);

  i = 0;
  XtSetArg(wargs[i], XmNtopAttachment,  XmATTACH_FORM); i++;
  XtSetArg(wargs[i], XmNleftAttachment,  XmATTACH_FORM); i++;
  XtSetArg(wargs[i], XmNshadowThickness, 3); i++;
  w1 = XtCreateManagedWidget ("Button", xmPushButtonGadgetClass,
      win, (ArgList)wargs, i);
  XtAddCallback (w1, XmNarmCallback, button_handler, 2);
  XtAddCallback (w1, XmNactivateCallback, button_handler2, 2);

  /*
   * Put the tree in a scrolled window, to handle 
   * large trees.
   */
   i = 0;
  XtSetArg(wargs[i], XmNtopAttachment, XmATTACH_WIDGET); i++;
  XtSetArg(wargs[i], XmNtopWidget, w1); i++;
  XtSetArg(wargs[i], XmNleftAttachment,  XmATTACH_FORM); i++;
  XtSetArg(wargs[i], XmNrightAttachment, XmATTACH_FORM); i++;
  XtSetArg(wargs[i], XmNbottomAttachment, XmATTACH_FORM); i++;
  XtSetArg(wargs[i], XmNscrollingPolicy, XmAUTOMATIC); i++;
  XtSetArg(wargs[i], XmNwidth, 300); i++;
  XtSetArg(wargs[i], XmNheight, 100); i++;
  XtSetArg(wargs[i], XmNborderWidth, 0); i++;
  sw = XtCreateManagedWidget("swindow",
          xmScrolledWindowWidgetClass, win, wargs, i);

   XtRealizeWidget(toplevel);
   XtMainLoop();
}