home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1996 May / PCOnline_05_1996.bin / linux / source / xap / xfm / xfm-1.000 / xfm-1 / xfm-1.3.2 / src / FmUtils.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-24  |  20.0 KB  |  579 lines

  1. /*-----------------------------------------------------------------------------
  2.   Module FmUtils.c
  3.  
  4.   (c) Simon Marlow 1990-1993
  5.   (c) Albert Graef 1994
  6.  
  7.   - default values for parameters added in varPopup() by Brian King
  8.     (ender@ee.WPI.EDU), integrated Mar 24 1995, AG
  9.  
  10.   General utility functions for creating menus, buttons, questions,
  11.   and functions for desensetising and 'ticking' menu entries.
  12. -----------------------------------------------------------------------------*/
  13.  
  14. #include <X11/Intrinsic.h>
  15. #include <X11/StringDefs.h>
  16. #include <X11/Shell.h>
  17. #include <X11/Xaw/MenuButton.h>
  18. #include <X11/Xaw/SimpleMenu.h>
  19. #include <X11/Xaw/SmeLine.h>
  20. #include <X11/Xaw/SmeBSB.h>
  21. #include <X11/Xaw/Command.h>
  22. #include <X11/Xaw/Form.h>
  23. #include <X11/Xaw/Label.h>
  24. #include <X11/Xaw/Box.h>
  25. #include <X11/Xaw/AsciiText.h>
  26.  
  27. #include "Am.h"
  28. #include "Fm.h"
  29.  
  30. #define PADDING 20
  31. #define TEXT_WIDTH 350
  32.  
  33. #define kDefaultValueMarker "--" /* Marker to denote default value */
  34. #define kDefaultValue ""         /* Default Value to use if none specified */
  35.  
  36. /*-----------------------------------------------------------------------------
  37.   STATIC DATA
  38. -----------------------------------------------------------------------------*/
  39.  
  40. /*-----------------------------------------------------------------------------
  41.   Widget Argument Lists
  42. -----------------------------------------------------------------------------*/
  43.  
  44. static Arg shell_args[] = {
  45.   { XtNtitle, (XtArgVal) NULL }
  46. };
  47.  
  48. static Arg form_args[] = {
  49.   { XtNdefaultDistance, PADDING }
  50. };
  51.  
  52. static Arg bitmap_args[]  = {
  53.   { XtNfromHoriz, (XtArgVal) NULL },
  54.   { XtNfromVert, (XtArgVal) NULL },
  55.   { XtNbitmap, (XtArgVal) NULL },
  56.   { XtNtop, (XtArgVal) XtChainTop },
  57.   { XtNbottom, (XtArgVal) XtChainTop },
  58.   { XtNleft, (XtArgVal) XtChainLeft },
  59.   { XtNright, (XtArgVal) XtChainLeft }
  60. };
  61.  
  62. static Arg label_args[] = {
  63.   { XtNfromHoriz, (XtArgVal) NULL },
  64.   { XtNfromVert, (XtArgVal) NULL },
  65.   { XtNlabel, (XtArgVal) NULL },
  66.   { XtNwidth, (XtArgVal) 0 },
  67.   { XtNfont, (XtArgVal) NULL },
  68.   { XtNjustify, XtJustifyRight },
  69.   { XtNinternalWidth, (XtArgVal) 0 },
  70.   { XtNinternalHeight, (XtArgVal) 0 },
  71.   { XtNtop, XtChainTop },
  72.   { XtNbottom, XtChainTop },
  73.   { XtNleft, XtChainLeft },
  74.   { XtNright, XtChainLeft }
  75. };
  76.  
  77. static Arg text_args[] = {
  78.   { XtNfromHoriz, (XtArgVal) NULL },
  79.   { XtNfromVert, (XtArgVal) NULL },
  80.   { XtNstring, (XtArgVal) NULL },
  81.   { XtNlength, (XtArgVal) NULL },
  82.   { XtNwidth, (XtArgVal) TEXT_WIDTH },
  83.   { XtNfont, (XtArgVal) NULL },
  84.   { XtNtop, XtChainTop },
  85.   { XtNbottom, XtChainTop },
  86.   { XtNleft, XtChainLeft },
  87.   { XtNright, XtChainRight },
  88.   { XtNeditType, XawtextEdit },
  89.   { XtNtype, XawAsciiString },
  90.   { XtNuseStringInPlace, (XtArgVal) True },
  91. };
  92.  
  93. static Arg button_box_args[] = {
  94.   { XtNfromHoriz, (XtArgVal) NULL },
  95.   { XtNfromVert, (XtArgVal) NULL },
  96.   { XtNtop, XtChainTop },
  97.   { XtNbottom, XtChainTop },
  98.   { XtNleft, XtChainLeft },
  99.   { XtNright, XtChainLeft }
  100. };
  101.  
  102. static Arg button_args[] = {
  103.   { XtNlabel, (XtArgVal) NULL },
  104.   { XtNfont, (XtArgVal) NULL }
  105. };
  106.  
  107. static Arg menu_button_args[] = {
  108.   { XtNlabel, (XtArgVal) NULL },
  109.   { XtNfont, (XtArgVal) NULL }
  110. };
  111.  
  112. static Arg menu_item_args[] = {
  113.   { XtNlabel, (XtArgVal) NULL },
  114.   { XtNfont, (XtArgVal) NULL },
  115.   { XtNleftMargin , (XtArgVal) 0 }
  116. };
  117.  
  118. /*-----------------------------------------------------------------------------
  119.   PUBLIC FUNCTIONS
  120. -----------------------------------------------------------------------------*/
  121.  
  122. void initUtils()
  123. {
  124.   button_args[1].value = (XtArgVal) resources.button_font;
  125.   menu_button_args[1].value = (XtArgVal) resources.button_font;
  126.   menu_item_args[1].value = (XtArgVal) resources.menu_font;
  127.   label_args[4].value = (XtArgVal) resources.label_font;
  128.   text_args[5].value = (XtArgVal) resources.cell_font;
  129. }
  130.  
  131. /*****************************************************************************/
  132. /* Function: createFloatingMenu                                              */
  133. /* Arguments: menu_name   :  The menu widget name                            */
  134. /*            items       :  Items to put in menu                            */
  135. /*            n_items     :  Number of items                                 */
  136. /*            left_margin :  left_margin in pixels (in case ticks are needed */
  137. /*            parent      :  The parent widget to use                        */
  138. /*            client_data :  Client data to be returned by any callback      */
  139. /*            menu_widget :  returns the menu widget                         */
  140. /*                                                                           */
  141. /* Create a popup menu with the specified attributes and place in it the     */
  142. /* specifed items; return the list of item widgets                           */
  143. /*****************************************************************************/
  144.  
  145. Widget *createFloatingMenu(String menu_name,
  146.                MenuItemRec *items, Cardinal n_items, 
  147.                Dimension left_margin, Widget parent, 
  148.                XtPointer client_data,
  149.                Widget *menu_widget)
  150. {
  151.   int i;
  152.   Widget *item_widgets;
  153.   
  154.   item_widgets = (Widget *) XtMalloc(n_items * sizeof(Widget));
  155.  
  156.   *menu_widget = XtCreatePopupShell(menu_name, simpleMenuWidgetClass,
  157.                     parent, NULL, 0 );
  158.     
  159.   menu_item_args[2].value = (XtArgVal) left_margin;
  160.  
  161.   for (i = 0; i < n_items; i++) {
  162.     if (items[i].callback == NULL)
  163.       XtCreateManagedWidget(items[i].item_name, smeLineObjectClass,
  164.                 *menu_widget, NULL, 0 );
  165.     else {
  166.       menu_item_args[0].value = (XtArgVal) items[i].item_label;
  167.       item_widgets[i] = XtCreateManagedWidget(items[i].item_name,
  168.                           smeBSBObjectClass, *menu_widget,
  169.                           menu_item_args, 
  170.                           XtNumber(menu_item_args));
  171.       XtAddCallback(item_widgets[i], XtNcallback,
  172.             (XtCallbackProc) items[i].callback, client_data );
  173.     }
  174.   }
  175.  
  176.   return item_widgets;
  177. }
  178.  
  179. /*****************************************************************************/
  180. /* Function: createMenu                                                      */
  181. /* Arguments: menu_name   :  The menu widget name                            */
  182. /*            menu_label  :  The label for the menu button                   */
  183. /*            items       :  Items to put in menu                            */
  184. /*            n_items     :  Number of items                                 */
  185. /*            left_margin :  left_margin in pixels (in case ticks are needed */
  186. /*            parent      :  The parent widget to use                        */
  187. /*            client_data :  Client data to be returned by any callback      */
  188. /*                                                                           */
  189. /* Create a menu with the specified attributes and place in it the           */
  190. /* specifed items                                                            */
  191. /*****************************************************************************/
  192.  
  193. Widget *createMenu(String menu_name, String menu_label, MenuItemList items,
  194.            Cardinal n_items, Dimension left_margin,
  195.            Widget parent, XtPointer client_data)
  196. {
  197.   int i;
  198.   Widget menu_widget, button_widget, *item_widgets;
  199.   
  200.   item_widgets = (Widget *) XtMalloc(n_items * sizeof(Widget));
  201.  
  202.   menu_button_args[0].value = (XtArgVal) menu_label;
  203.   button_widget = XtCreateManagedWidget(menu_name, menuButtonWidgetClass,
  204.     parent, menu_button_args, XtNumber(menu_button_args));
  205.   menu_widget = XtCreatePopupShell( "menu", simpleMenuWidgetClass,
  206.       button_widget, NULL, 0 );
  207.     
  208.   menu_item_args[2].value = (XtArgVal) left_margin;
  209.  
  210.   for (i = 0; i < n_items; i++) {
  211.     if (items[i].callback == NULL)
  212.       XtCreateManagedWidget(items[i].item_name, smeLineObjectClass,
  213.                 menu_widget, NULL, 0 );
  214.     else {
  215.       menu_item_args[0].value = (XtArgVal) items[i].item_label;
  216.       item_widgets[i] = XtCreateManagedWidget(items[i].item_name,
  217.                           smeBSBObjectClass, menu_widget,
  218.                           menu_item_args, 
  219.                           XtNumber(menu_item_args));
  220.       XtAddCallback(item_widgets[i], XtNcallback, 
  221.             (XtCallbackProc) items[i].callback, client_data );
  222.     }
  223.   }
  224.  
  225.   return item_widgets;
  226. }
  227.  
  228. /*****************************************************************************/
  229. /* Function: createButtons                                                   */
  230. /* Arguments: buttons     :  The list of buttons to create                   */
  231. /*            n_buttons   :  Number of buttons                               */
  232. /*            parent      : The parent widget to use                         */
  233. /*            client data :  Client data returned by all buttons             */
  234. /*                                                                           */
  235. /* Create a set of buttons (usually in a box) with the attributes specified  */
  236. /*****************************************************************************/
  237.  
  238.  
  239. Widget *createButtons(ButtonList buttons, Cardinal n_buttons, Widget parent,
  240.            XtPointer client_data)
  241. {
  242.   int i;
  243.   Widget *button_widgets;
  244.   
  245.   button_widgets = (Widget *) XtMalloc(n_buttons * sizeof(Widget));
  246.  
  247.   for (i = 0; i < n_buttons; i++) {
  248.     button_args[0].value = (XtArgVal) buttons[i].button_label;
  249.     button_widgets[i] = XtCreateManagedWidget(buttons[i].button_name,
  250.       commandWidgetClass, parent, button_args, XtNumber(button_args));
  251.     XtAddCallback(button_widgets[i], XtNcallback, 
  252.           (XtCallbackProc) buttons[i].callback, client_data );
  253.   }
  254.  
  255.   return button_widgets;
  256. }
  257.  
  258. /*****************************************************************************/
  259. /* Function: createPopupQuestions                                            */
  260. /* Arguments: name        :  The widget name for the shell                   */
  261. /*            title       :  The title of the popup window                   */
  262. /*            bitmap      :  A bitmap to display to the left of the box      */
  263. /*            questions   :  A list of questions to use                      */
  264. /*            n_questions :  Number of questions                             */
  265. /*            buttons     :  A set of buttons to put at the bottom           */
  266. /*            n_buttons   :  Number of buttons                               */
  267. /*                                                                           */
  268. /* Create a popup questionaire with a bitmap to the left (or none), several  */
  269. /* questions (each consisting of a label and a text area) to the right of    */
  270. /* the bitmap, and a set of buttons underneath all this.                     */
  271. /*****************************************************************************/
  272.  
  273. Widget createPopupQuestions(String name, String title, Pixmap bitmap,
  274.                 QuestionList questions, Cardinal n_questions,
  275.                 ButtonList buttons, Cardinal n_buttons)
  276. {
  277.   int i, l;
  278.   Widget form_widget, box_widget, bitmap_widget = NULL, shell,
  279.     vert = NULL, horiz = NULL;
  280.  
  281.   /* create popup shell */
  282.   shell_args[0].value = (XtArgVal) title;
  283.   shell = XtCreatePopupShell(name, transientShellWidgetClass, aw.shell,
  284.                  shell_args, XtNumber(shell_args) );
  285.  
  286.   /* create form */
  287.   form_widget = XtCreateManagedWidget("popup form", formWidgetClass, shell, 
  288.                       form_args, XtNumber(form_args) );
  289.  
  290.   /* create bitmap */
  291.   if (bitmap != None) {
  292.     bitmap_args[2].value = (XtArgVal) bitmap;
  293.     bitmap_widget = XtCreateManagedWidget("bitmap", labelWidgetClass,
  294.       form_widget, bitmap_args, XtNumber(bitmap_args));
  295.   }
  296.  
  297.   /* Find width of label */
  298.   label_args[3].value = (XtArgVal) 0;
  299.   for (i=0; i<n_questions; i++) {
  300.     l = XTextWidth(resources.label_font, questions[i].label, 
  301.            strlen(questions[i].label));
  302.     if (l > label_args[3].value)
  303.       label_args[3].value = l;
  304.   }
  305.  
  306.   for (i = 0; i<n_questions; i++) {
  307.     label_args[0].value = (XtArgVal) bitmap_widget;
  308.     label_args[1].value = (XtArgVal) vert;
  309.     label_args[2].value = (XtArgVal) questions[i].label;
  310.     horiz = XtCreateManagedWidget("label", labelWidgetClass, form_widget,
  311.                      label_args, XtNumber(label_args));
  312.     if (n_questions == 1) {
  313.       text_args[0].value = (XtArgVal) bitmap_widget;
  314.       text_args[1].value = (XtArgVal) horiz;
  315.     }
  316.     else {
  317.       text_args[0].value = (XtArgVal) horiz;
  318.       text_args[1].value = (XtArgVal) vert;
  319.     }      
  320.     text_args[2].value = (XtArgVal) questions[i].value;
  321.     text_args[3].value = (XtArgVal) questions[i].length;
  322.     vert = questions[i].widget = XtCreateManagedWidget("text", 
  323.        asciiTextWidgetClass, form_widget, text_args, XtNumber(text_args));
  324.   }
  325.  
  326.   if (buttons != NULL) {
  327.     button_box_args[0].value = (XtArgVal) NULL;
  328.     button_box_args[1].value = (XtArgVal) vert;
  329.     box_widget = XtCreateManagedWidget("button box", boxWidgetClass, 
  330.             form_widget, button_box_args, XtNumber(button_box_args));
  331.     createButtons(buttons, n_buttons, box_widget, NULL);
  332.   }
  333.  
  334.   XtRealizeWidget(shell);
  335.  
  336.   return shell;
  337. }
  338.  
  339. /*****************************************************************************/
  340. /* Function: fillIn                                                          */
  341. /* Arguments: w : The widget to fill in                                      */
  342. /*                                                                           */
  343. /* sensitize a menu entry                                                    */
  344. /*****************************************************************************/
  345.  
  346. void fillIn(Widget w)
  347. {
  348.   XtVaSetValues(w, XtNsensitive, (XtArgVal) True, NULL);
  349. }
  350.  
  351. /*****************************************************************************/
  352. /* Function: grayOut                                                         */
  353. /* Arguments: w : the widget to gray out                                     */
  354. /*                                                                           */
  355. /* desensitises a menu entry                                                 */
  356. /*****************************************************************************/
  357.  
  358. void grayOut(Widget w)
  359. {
  360.   XtVaSetValues(w, XtNsensitive, (XtArgVal) False, NULL);
  361. }
  362.  
  363. /*****************************************************************************/
  364. /* Function: tick                                                            */
  365. /* Arguments: w : the widget to tick                                         */
  366. /*                                                                           */
  367. /* place a tick to the left of the specifed menu entry                       */
  368. /*****************************************************************************/
  369.  
  370. void tick(Widget w)
  371. {
  372.   XtVaSetValues(w, XtNleftBitmap, (XtArgVal) bm[TICK_BM], NULL);
  373. }
  374.  
  375. /*****************************************************************************/
  376. /* Function: notick                                                          */
  377. /* Arguments: w : the widget                                                 */
  378. /*                                                                           */
  379. /* remove a tick from a menu entry                                           */
  380. /*****************************************************************************/
  381.  
  382. void noTick(Widget w)
  383. {
  384.   XtVaSetValues(w, XtNleftBitmap, (XtArgVal) bm[NOTICK_BM], NULL);
  385. }
  386.  
  387. /*****************************************************************************/
  388. /* Function: popupByCursor                                                   */
  389. /* Arguments: shell       :  the shell to popup                              */
  390. /*            grab_kind   :  parameter passed to XtPopup                     */
  391. /*                                                                           */
  392. /* Try to popup a shell by the cursor, make sure it fits on the screen       */
  393. /*****************************************************************************/
  394.  
  395. void popupByCursor(Widget shell, XtGrabKind grab_kind)
  396. {
  397.   char *geom;
  398.   Display *dpy;
  399.   Screen *scr;
  400.   Window root, child;
  401.   int x, y, x_win, y_win, scr_width, scr_height;
  402.   Dimension width, height;
  403.   unsigned int mask;
  404.  
  405.   XtVaGetValues(shell, XtNgeometry, &geom, NULL);
  406.  
  407.   if (!geom || !(strchr(geom, '+') || strchr(geom, '-'))) {
  408.     dpy = XtDisplay(aw.shell);
  409.     scr = XtScreen(aw.shell);
  410.     scr_width = WidthOfScreen(scr);
  411.     scr_height = HeightOfScreen(scr);
  412.   
  413.     XQueryPointer(dpy, DefaultRootWindow(dpy), &root, &child, &x, &y, 
  414.           &x_win, &y_win, &mask);
  415.  
  416.     XtVaGetValues(shell, XtNwidth, &width, XtNheight, &height, NULL);
  417.  
  418.     x -= width/2;
  419.     y -= height/2;
  420.  
  421.     if (x + width > scr_width)
  422.       x = scr_width - width;
  423.     else if (x < 0)
  424.       x = 0;
  425.  
  426.     if (y + height > scr_height)
  427.       y = scr_height - height;
  428.     else if (y < 0)
  429.       y = 0;
  430.  
  431.     XtVaSetValues(shell, XtNx, (XtArgVal) x, XtNy, (XtArgVal) y, NULL);
  432.   }
  433.  
  434.   XtPopup(shell, grab_kind);
  435. }
  436.  
  437. /*---------------------------------------------------------------------------*/
  438.  
  439. void zzz(void)
  440. {
  441.   FileWindowRec *fw;
  442.   Display *dpy = XtDisplay(aw.shell);
  443.  
  444.   for (fw = file_windows; fw; fw = fw->next)
  445.     XDefineCursor(dpy, XtWindow(fw->viewport), curs[WATCH_CUR]);
  446.  
  447.   if (resources.appmgr)
  448.     XDefineCursor(dpy, XtWindow(aw.shell), curs[WATCH_CUR]);
  449.  
  450.   XFlush(dpy);
  451. }
  452.  
  453. /*---------------------------------------------------------------------------*/
  454.  
  455. void wakeUp(void)
  456. {
  457.   FileWindowRec *fw;
  458.   Display *dpy = XtDisplay(aw.shell);
  459.  
  460.   for (fw = file_windows; fw; fw = fw->next)
  461.     XUndefineCursor(dpy, XtWindow(fw->viewport));
  462.  
  463.   if (resources.appmgr)
  464.     XUndefineCursor(dpy, XtWindow(aw.shell));
  465. }
  466.  
  467. /*---------------------------------------------------------------------------*/
  468.  
  469. #define MAXVARSTRINGLEN MAXPATHLEN
  470.  
  471. static enum { DontKnow, Ok, Cancel } dialog_flag;
  472. static Widget dialog;
  473.  
  474. static void dialogOkCb(Widget w, XtPointer client_data, XtPointer call_data)
  475. {
  476.   XtPopdown(dialog);
  477.   dialog_flag = Ok;
  478. }
  479.  
  480. /*---------------------------------------------------------------------------*/
  481.  
  482. static void dialogCancelCb(Widget w, XtPointer client_data, 
  483.                XtPointer call_data)
  484. {
  485.   XtPopdown(dialog);
  486.   dialog_flag = Cancel;
  487. }
  488.  
  489. /*---------------------------------------------------------------------------*/
  490.  
  491. static ButtonRec dialog_buttons[] = {
  492.   { "ok", "Ok", (FmCallbackProc *) dialogOkCb },
  493.   { "cancel", "Cancel", (FmCallbackProc *) dialogCancelCb }
  494. };
  495.  
  496. char *varPopup(Pixmap icon_bm, char *action)
  497. {
  498.   static char *act = NULL;
  499.   char *act1 = (char *)alloca(strlen(action)+1), *s, *t;
  500.   char *str = (char *)alloca(strlen(action)+1);
  501.   char **acts = NULL, **vars = NULL;
  502.   int n_acts = 0, n_vars = 0;
  503.   char *def_val;
  504.   char **vals = NULL;
  505.  
  506.   if (act) XTFREE(act);
  507.   act = NULL;
  508.   strcpy(act1, action);
  509.  
  510.   for (s = split(act1, '%'); s; s = split(NULL, '%')) {
  511.     acts = (char **)XTREALLOC(acts, (n_acts+1)*sizeof(char *));
  512.     acts[n_acts++] = XtNewString(strparse(str, s, "\\%"));
  513.     if (t = split(NULL, '%')) {
  514.       vars = (char **)XTREALLOC(vars, (n_vars+1)*sizeof(char *));
  515.       vars[n_vars] = XtNewString(strparse(str, t, "\\%"));
  516.       /* Check string for default value character */
  517.       vals = (char **)XTREALLOC(vals, (n_vars+1)*sizeof(char *));
  518.       vals[n_vars] = (char *)XtMalloc(MAXVARSTRINGLEN);
  519.       if ((def_val = strstr(vars[n_vars], kDefaultValueMarker)) == NULL) {
  520.     strcpy(vals[n_vars++], kDefaultValue);
  521.       } else {
  522.     def_val[0] = '\0'; /* Separate label and default value */
  523.     strcpy(vals[n_vars++], def_val + strlen(kDefaultValueMarker));
  524.       }
  525.     } else
  526.       break;
  527.   }
  528.  
  529.   if (n_vars) {
  530.     QuestionRec *dialog_questions;
  531.     int i, l;
  532.     XEvent e;
  533.  
  534.     dialog_questions = (QuestionRec *)XtMalloc(n_vars*sizeof(QuestionRec));
  535.     for (i = 0; i < n_vars; i++) {
  536.       dialog_questions[i].label = vars[i];
  537.       dialog_questions[i].value = vals[i];
  538.       dialog_questions[i].length = MAXVARSTRINGLEN;
  539.       dialog_questions[i].widget = NULL;
  540.     }
  541.  
  542.     dialog = createPopupQuestions("dialog", "Parameter Dialog", icon_bm,
  543.                   dialog_questions, n_vars, dialog_buttons,
  544.                   XtNumber(dialog_buttons));
  545.     popupByCursor(dialog, XtGrabExclusive);
  546.  
  547.     dialog_flag = DontKnow;
  548.  
  549.     do {
  550.       XtAppNextEvent(app_context, &e);
  551.       XtDispatchEvent(&e);
  552.     } while (dialog_flag == DontKnow);
  553.  
  554.     if (dialog_flag == Ok)
  555.       for (l = i = 0; i < n_acts; i++) {
  556.     int l1 = strlen(acts[i]), l2 = i<n_vars?strlen(vals[i]):0;
  557.     act = (char *)XTREALLOC(act, l+l1+l2+1);
  558.     strcpy(act+l, acts[i]);
  559.     if (l2) strcpy(act+l+l1, vals[i]);
  560.     l += l1+l2;
  561.       }
  562.  
  563.     XTFREE(dialog_questions);
  564.     for (i = 0; i < n_acts; i++)
  565.       XTFREE(acts[i]);
  566.     for (i = 0; i < n_vars; i++)
  567.       XTFREE(vars[i]);
  568.     for (i = 0; i < n_vars; i++)
  569.       XTFREE(vals[i]);
  570.     XTFREE(acts); XTFREE(vars); XTFREE(vals);
  571.     XtDestroyWidget(dialog);
  572.     return act;
  573.   } else {
  574.     if (n_acts) XTFREE(acts);
  575.     return action;
  576.   }
  577. }
  578.  
  579.