-fpermissive to allow GCC to compile old C++
[oweals/cde.git] / cde / programs / dtmail / dtmail / dtb_utils.C
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $TOG: dtb_utils.C /main/8 1998/10/26 17:19:11 mgreess $ */
24 /*
25  * $TOG: dtb_utils.C /main/8 1998/10/26 17:19:11 mgreess $
26  *
27  * File: dtb_utils.c
28  * CDE Application Builder General Utility Functions
29  *
30  * This file was generated by dtcodegen, from project dtmailopts
31  *
32  *    ** DO NOT MODIFY BY HAND - ALL MODIFICATIONS WILL BE LOST **
33  */
34
35 #include <unistd.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <sys/param.h>
39 #include <sys/stat.h>
40 #include <Xm/Xm.h>
41 #include <Xm/Form.h>
42 #include <Xm/Frame.h>
43 #include <Xm/MessageB.h>
44 #include <Xm/PushB.h>
45 #include <Xm/Label.h>
46 #include <Dt/Help.h>
47 #include <Dt/HelpDialog.h>
48 #include <Dt/HelpQuickD.h>
49 #include <Dt/Session.h>
50 #include "dtb_utils.h"
51
52 #ifndef min
53 #define min(a,b) ((a) < (b)? (a):(b))
54 #endif
55
56 #ifndef max
57 #define max(a,b) ((a) > (b)? (a):(b))
58 #endif
59
60 /*
61  * Private functions used for dynamic centering of objects
62  */
63 static void  center_widget(
64     Widget              form_child,
65     DTB_CENTERING_TYPES type
66 );
67 static void  uncenter_widget(
68     Widget              form_child,
69     DTB_CENTERING_TYPES type
70 );
71 static void centering_handler(
72     Widget      widget,
73     XtPointer   client_data,
74     XEvent      *event,
75     Boolean     *cont_dispatch
76 );
77 /*
78  * Static functions used for dynamic aligning of group objects
79  */
80 static Widget get_label_widget(
81     Widget      widget
82 );
83 static Position get_offset_from_ancestor(
84     Widget      ancestor,
85     Widget      w
86 );
87 static Dimension get_label_width(
88     Widget      widget
89 );
90 static void get_widest_label(
91     WidgetList  list,
92     int         count,
93     Widget      *child_widget,
94     Dimension   *label_width
95 );
96 static void get_widest_value(
97     WidgetList  list,
98     int         count,
99     Widget      *child_widget,
100     Dimension   *value_width
101 );
102 static void get_widget_rect(
103     Widget widget,
104     XRectangle *rect
105 );
106 static void get_greatest_size(
107     Widget      *list,
108     int         count,
109     int         *width,
110     int         *height,
111     Widget      *tallest,
112     Widget      *widest
113 );
114 static void get_group_cell_size(
115     Widget              parent,
116     DtbGroupInfo        *group_info,
117     int                 *cell_width,
118     int                 *cell_height
119 );
120 static void get_group_row_col(
121     Widget              parent,
122     DtbGroupInfo        *group_info,
123     int                 *rows,
124     int                 *cols
125 );
126 static Widget get_group_child(
127     Widget              parent,
128     DtbGroupInfo        *group_info,
129     int                 x_pos,
130     int                 y_pos
131 );
132 static void align_children(
133     Widget              parent,
134     DtbGroupInfo        *group_info,
135     Bool                init
136 );
137 static void align_handler(
138     Widget      widget,
139     XtPointer   client_data,
140     XEvent      *event,
141     Boolean     *cont_dispatch
142 );
143 static void              free_group_info(
144     Widget      widget,
145     XtPointer   client_data,
146     XtPointer   call_data
147 );
148 static void align_rows(
149     Widget              parent,
150     DtbGroupInfo        *group_info,
151     Bool                init
152 );
153 static void align_cols(
154     Widget              parent,
155     DtbGroupInfo        *group_info,
156     Bool                init
157 );
158 static void align_left(
159     Widget              parent,
160     DtbGroupInfo        *group_info
161 );
162 static void align_right(
163     Widget              parent,
164     DtbGroupInfo        *group_info
165 );
166 static void align_labels(
167     Widget              parent,
168     DtbGroupInfo        *group_info
169 );
170 static void align_vcenter(
171     Widget              parent,
172     DtbGroupInfo        *group_info,
173     Bool                init
174 );
175 static void align_top(
176     Widget              parent,
177     DtbGroupInfo        *group_info
178 );
179 static void align_bottom(
180     Widget              parent,
181     DtbGroupInfo        *group_info
182 );
183 static void align_hcenter(
184     Widget              parent,
185     DtbGroupInfo        *group_info,
186     Bool                init
187 );
188
189 /*
190  * Private functions used for finding paths
191  */
192 static int  determine_exe_dir(
193     char        *argv0,
194     char        *buf,
195     int         bufSize
196 );
197 static int determine_exe_dir_from_argv(
198     char        *argv0,
199     char        *buf,
200     int         bufSize
201 );
202 static int determine_exe_dir_from_path (
203     char        *argv0,
204     char        *buf,
205     int         bufSize
206 );
207 static Boolean path_is_executable(
208     char        *path,
209     uid_t       euid,
210     gid_t       egid
211 );
212
213 /*
214  * Variable for storing client session save callback
215  */
216 static DtbClientSessionSaveCB           dtb_client_session_saveCB = NULL;
217
218 /*
219  * Variable for storing top level widget
220  */
221 static Widget           dtb_project_toplevel_widget = (Widget)NULL;
222
223 /*
224  * Variable for storing command used to invoke application
225  */
226 static char                             *dtb_save_command_str = (char *)NULL;
227
228 /*
229  * Directory where the binary for this process whate loaded from
230  */
231 static char                             *dtb_exe_dir = (char *)NULL;
232
233 /*
234  * Application Builder utility funcs
235  */
236 /*
237  * Create/load a Pixmap given an XPM or Bitmap files
238  * NOTE: this allocates a server Pixmap;  it is the responsibility
239  * of the caller to free the Pixmap
240  */
241 int
242 dtb_cvt_file_to_pixmap(
243     String      fileName,
244     Widget      widget,
245     Pixmap      *pixmapReturnPtr
246 )
247 {
248 #define pixmapReturn (*pixmapReturnPtr)
249     Pixmap      pixmap = 0;
250     Screen      *screen = NULL;
251     Pixel       fgPixel = 0;
252     Pixel       bgPixel = 0;
253     char        *image_path = new char[MAXPATHLEN+1];
254     Boolean     pixmap_found = FALSE;
255
256     /*
257      * Get default values
258      */
259     screen = XtScreen(widget);
260     fgPixel = WhitePixelOfScreen(screen);
261     bgPixel = BlackPixelOfScreen(screen);
262
263     /*
264      * Get proper colors for widget
265      */
266     XtVaGetValues(widget,
267         XmNforeground, &fgPixel,
268         XmNbackground, &bgPixel,
269         NULL);
270
271     /*
272      * In CDE, XmGetPixmap handles .xpm files, as well.
273      */
274     if (!pixmap_found)
275     {
276         pixmap = XmGetPixmap(screen, fileName, fgPixel, bgPixel);
277     }
278     pixmap_found = ((pixmap != 0) && (pixmap != XmUNSPECIFIED_PIXMAP));
279
280     if (!pixmap_found)
281     {
282         sprintf(image_path, "%s/%s", dtb_get_exe_dir(), fileName);
283         pixmap = XmGetPixmap(screen, image_path, fgPixel, bgPixel);
284     }
285     pixmap_found = ((pixmap != 0) && (pixmap != XmUNSPECIFIED_PIXMAP));
286
287     if (!pixmap_found)
288     {
289         sprintf(image_path, "%s/bitmaps/%s", dtb_get_exe_dir(), fileName);
290         pixmap = XmGetPixmap(screen, image_path, fgPixel, bgPixel);
291     }
292     pixmap_found = ((pixmap != 0) && (pixmap != XmUNSPECIFIED_PIXMAP));
293
294     if (!pixmap_found)
295     {
296         delete [] image_path;
297         return -1;
298     }
299
300     pixmapReturn = pixmap;
301     pixmapReturn = pixmap;
302     delete [] image_path;
303     return 0;
304 #undef pixmapReturn
305 }
306
307
308 /*
309  * Sets both the sensitive and insensitve pixmaps
310  */
311 int
312 dtb_set_label_from_bitmap_data(
313     Widget              widget,
314     int                 width,
315     int                 height,
316     unsigned char       *bitmapData
317 )
318 {
319     Display             *display = NULL;
320     Screen              *screen = NULL;
321     Drawable            window = 0;
322     long                bgPixel = 0;
323     long                fgPixel = 0;
324     unsigned int        depth = 0;
325     Pixmap              labelPixmap = 0;
326
327     if (   (widget == NULL)
328         || (width < 1)
329         || (height < 1)
330         || (bitmapData == NULL) )
331     {
332         return -1;
333     }
334
335     /*
336      * Get a whole slew of information X needs
337      */
338     {
339         Pixel           widgetBg = 0;
340         Pixel           widgetFg = 0;
341         int             widgetDepth = 0;
342
343         display = XtDisplay(widget);
344         screen = XtScreen(widget);
345         window = XtWindow(widget);
346         if (window == 0)
347         {
348             /* Widget has not been realized, yet */
349             window = RootWindowOfScreen(screen);
350         }
351
352         XtVaGetValues(widget,
353                 XmNbackground,  &widgetBg,
354                 XmNforeground,  &widgetFg,
355                 XmNdepth,       &widgetDepth,
356                 NULL);
357         bgPixel = widgetBg;
358         fgPixel = widgetFg;
359         depth = widgetDepth;
360     }
361
362     /*
363      * Create the pixmap
364      */
365     labelPixmap = XCreatePixmapFromBitmapData(
366                 display,
367                 window,
368                 (char *) bitmapData,
369                 width, height,
370                 fgPixel, bgPixel,
371                 depth);
372     if (labelPixmap == 0)
373     {
374         return -1;
375     }
376
377     dtb_set_label_pixmaps(widget, labelPixmap, 0);
378
379     return 0;
380 }
381
382
383 /*
384  * Sets the label and insensitive label pixmaps of the widget.  
385  *
386  * If either (or both) pixmap is NULL, it is ignored.
387  */
388 int
389 dtb_set_label_pixmaps(
390     Widget      widget,
391     Pixmap      labelPixmap,
392     Pixmap      labelInsensitivePixmap
393 )
394 {
395     if (   (widget == NULL)
396         || ((labelPixmap == 0) && (labelInsensitivePixmap == 0)) )
397     {
398         return -1;
399     }
400
401     /*
402      * Set the approriate resources.
403      */
404     XtVaSetValues(widget, XmNlabelType, XmPIXMAP, NULL);
405     if (labelPixmap != 0)
406     {
407         XtVaSetValues(widget, XmNlabelPixmap, labelPixmap, NULL);
408     }
409     if (labelInsensitivePixmap != 0)
410     {
411         XtVaSetValues(widget, XmNlabelInsensitivePixmap, 
412                                 labelInsensitivePixmap, NULL);
413     }
414
415     return 0;
416 }
417
418
419 /*
420  * Returns TRUE if the fileName has the extension
421  */
422 Boolean
423 dtb_file_has_extension(
424     String      fileName, 
425     String      extension
426 )
427 {
428     Boolean        hasExt = FALSE;
429
430     if (extension == NULL)
431     {
432         hasExt = ( (fileName == NULL) || (strlen(fileName) == 0) );
433     }   
434     else
435     {   
436         if (fileName == NULL)
437             hasExt = FALSE;
438         else
439         {
440             char *dotPtr= strrchr(fileName, '.');
441             if (dotPtr == NULL)
442                 hasExt= FALSE;
443             else if (strcmp(dotPtr+1, extension) == 0)
444                 hasExt = TRUE;
445         }
446     }
447     return hasExt;
448 }
449
450
451 /*
452  * Appends the extension to fileBase and attempts to load in
453  * the Pixmap 
454  */
455 int
456 dtb_cvt_filebase_to_pixmap(
457     Widget      widget,
458     String      fileBase,
459     String      extension,
460     Pixmap      *pixmap_ptr
461 )
462 {
463     char        *fileName = new char[512];  
464     int         rc = 0;
465
466     strcpy(fileName, fileBase);
467     strcat(fileName, extension);
468     rc = dtb_cvt_file_to_pixmap(fileName, widget, pixmap_ptr);
469     delete [] fileName;
470     return rc;
471 }
472
473
474 int
475 dtb_cvt_image_file_to_pixmap(
476                 Widget  widget,
477                 String  fileName,
478                 Pixmap  *pixmap
479 )
480 {
481     int         rc = 0;         /* return code */
482     Pixmap      tmpPixmap = 0;
483     int         depth;
484
485     if (dtb_file_has_extension(fileName, "pm") ||
486         dtb_file_has_extension(fileName, "xpm") ||      
487         dtb_file_has_extension(fileName, "bm") ||       
488         dtb_file_has_extension(fileName, "xbm"))
489     {
490         /* If explicit filename requested, use it directly */
491         rc = dtb_cvt_file_to_pixmap(fileName, widget, &tmpPixmap);
492     }
493     else /* Append extensions to locate best graphic match */
494     {
495         XtVaGetValues(widget, XmNdepth, &depth, NULL);
496
497         if (depth > 1) /* Look for Color Graphics First */
498         {
499             rc = dtb_cvt_filebase_to_pixmap(widget, fileName, ".pm", &tmpPixmap);
500             if (rc < 0)
501                 rc = dtb_cvt_filebase_to_pixmap(widget, fileName, ".xpm", &tmpPixmap);
502             if (rc < 0)
503                 rc = dtb_cvt_filebase_to_pixmap(widget, fileName, ".bm", &tmpPixmap);
504             if (rc < 0) 
505                 rc = dtb_cvt_filebase_to_pixmap(widget, fileName, ".xbm", &tmpPixmap); 
506         }
507         else /* Look for Monochrome First */
508         {
509             rc = dtb_cvt_filebase_to_pixmap(widget, fileName, ".bm", &tmpPixmap);
510             if (rc < 0)
511                 rc = dtb_cvt_filebase_to_pixmap(widget, fileName, ".xbm", &tmpPixmap);
512             if (rc < 0) 
513                 rc = dtb_cvt_filebase_to_pixmap(widget, fileName, ".pm", &tmpPixmap); 
514             if (rc < 0) 
515                 rc = dtb_cvt_filebase_to_pixmap(widget, fileName, ".xpm", &tmpPixmap);  
516         }
517     }
518
519     if (rc < 0)
520     {
521         fprintf(stderr,"dtb_cvt_image_file_to_pixmap: %s :unable to load %s\n",
522                 XtName(widget), fileName);
523         *pixmap = 0;
524         return -1;
525     }
526
527     *pixmap = tmpPixmap;
528     return 0;
529 }
530
531
532 /* 
533  * Sets the XmNlabel from the image file (either xbitmap or xpixmap format).
534  *
535  * returns negative on error.
536  */
537 int
538 dtb_set_label_from_image_file(
539                 Widget  widget,
540                 String  fileName
541 )
542 {
543     int         rc = 0;         /* return code */
544     Pixmap      labelPixmap = 0;
545     Pixmap      insensitivePixmap = 0;
546
547     rc = dtb_cvt_image_file_to_pixmap(widget, fileName, &labelPixmap);
548
549     if (rc < 0)
550     {
551         fprintf(stderr,"dtb_set_label_from_image_file: %s :unable to load %s\n",
552                 XtName(widget), fileName);
553         return -1;
554     }
555     insensitivePixmap = dtb_create_greyed_pixmap(widget,labelPixmap);
556     rc = dtb_set_label_pixmaps(widget, labelPixmap, insensitivePixmap);
557
558     return 0;
559 }
560
561
562 unsigned long
563 dtb_cvt_resource_from_string(
564     Widget              parent,
565     String              res_type,
566     unsigned int        size_of_type,
567     String              res_str_value,
568     unsigned long       error_value
569 )
570 {
571     unsigned long       cvt_value_return = error_value;
572     unsigned char       cvt_value1 = 0;
573     unsigned short      cvt_value2 = 0;
574     unsigned int        cvt_value3 = 0;
575     unsigned long       cvt_value4 = 0;
576     XtPointer           cvt_value_ptr = NULL;
577     int                 which_cvt_value = -1;
578     XrmValue            source;
579     XrmValue            dest;
580
581     if (size_of_type > sizeof(cvt_value_return))
582     {
583         /* Type we are converting to is too large */
584         return cvt_value_return;
585     }
586
587     /*
588      * Get a data object of the appropriate size
589      */
590     if (size_of_type == sizeof(cvt_value1))
591     {
592         which_cvt_value = 1;
593         cvt_value_ptr = (XtPointer)&cvt_value1;
594     }
595     else if (size_of_type == sizeof(cvt_value2))
596     {
597         which_cvt_value = 2;
598         cvt_value_ptr = (XtPointer)&cvt_value2;
599     }
600     else if (size_of_type == sizeof(cvt_value3))
601     {
602         which_cvt_value = 3;
603         cvt_value_ptr = (XtPointer)&cvt_value3;
604     }
605     else if (size_of_type == sizeof(cvt_value4))
606     {
607         which_cvt_value = 4;
608         cvt_value_ptr = (XtPointer)&cvt_value4;
609     }
610     else
611     {
612         return cvt_value_return;
613     }
614
615     /*
616      * Actually do the conversion
617      */
618     source.size = strlen(res_str_value) + 1;
619     source.addr = res_str_value;
620
621     dest.size   = size_of_type;
622     dest.addr   = (char *)cvt_value_ptr;
623
624     if (XtConvertAndStore(parent, XtRString, &source,
625                 res_type, &dest) != 0)
626     {
627         switch (which_cvt_value)
628         {
629             case 1:
630                 cvt_value_return = (unsigned long)cvt_value1;
631             break;
632
633             case 2:
634                 cvt_value_return = (unsigned long)cvt_value2;
635             break;
636
637             case 3:
638                 cvt_value_return = (unsigned long)cvt_value3;
639             break;
640
641             case 4:
642                 cvt_value_return = (unsigned long)cvt_value4;
643             break;
644         }
645     }
646
647     return cvt_value_return;
648 }
649
650
651 /*
652  * For a given pixmap, create a 50% greyed version.  Most likely this will
653  * be used where the source pixmap is the labelPixmap for a widget and an 
654  * insensitivePixmap is needed so the widget will look right when it is 
655  * "not sensitive" ("greyed out" or "inactive").
656  * 
657  * NOTE: This routine creates a Pixmap, which is an X server resource.  The
658  *       created pixmap must be freed by the caller when it is no longer
659  *       needed.
660  */
661 Pixmap
662 dtb_create_greyed_pixmap(
663     Widget      widget,
664     Pixmap      pixmap
665 )
666 {
667     Display      *dpy;
668     Window       root;
669     Pixmap       insensitive_pixmap;
670     Pixel        background;
671     unsigned int width, height, depth, bw;
672     int          x,y;
673     XGCValues    gcv;
674     XtGCMask     gcm;
675     GC           gc;
676
677
678     dpy = XtDisplay(widget);
679
680     if(pixmap == XmUNSPECIFIED_PIXMAP || pixmap == (Pixmap)NULL) {
681         fprintf(stderr,"dtb_create_greyed_pixmap: Invalid source pixmap\n");
682         return((Pixmap)NULL);
683     }
684
685     XtVaGetValues(widget,
686         XmNbackground, &background,
687         NULL);
688
689     /* Get width/height of source pixmap */
690     if (!XGetGeometry(dpy,pixmap,&root,&x,&y,&width,&height,&bw,&depth)) {
691         fprintf(stderr,"dtb_create_greyed_pixmap: Invalid source pixmap\n");
692             return((Pixmap)NULL);
693     }
694     gcv.foreground = background;
695     gcv.fill_style = FillStippled;
696     gcv.stipple = XmGetPixmapByDepth(XtScreen(widget),
697                         "50_foreground", 1, 0, 1);
698     gcm = GCForeground | GCFillStyle | GCStipple;
699     gc = XtGetGC(widget, gcm, &gcv);
700
701     /* Create insensitive pixmap */
702     insensitive_pixmap = XCreatePixmap(dpy, pixmap, width, height, depth);
703     XCopyArea(dpy, pixmap, insensitive_pixmap, gc, 0, 0, width, height, 0, 0);
704     XFillRectangle(dpy, insensitive_pixmap, gc, 0, 0, width, height);
705
706     XtReleaseGC(widget, gc);
707     return(insensitive_pixmap);
708 }
709
710
711 /*
712 ** Routines to save and access the toplevel widget for an application.
713 ** This is useful in dtb_ convenience functions, and also probably by
714 ** developers in routines they provide in their _stubs.c files.
715 ** static Widget dtb_project_toplevel_widget = (Widget) NULL;
716 */
717 void
718 dtb_save_toplevel_widget(
719     Widget      toplevel
720 )
721 {
722         dtb_project_toplevel_widget = toplevel;
723 }
724
725
726 Widget
727 dtb_get_toplevel_widget()
728 {
729         return(dtb_project_toplevel_widget);
730 }
731
732
733 /*
734  ** Routines to save and access the command used to invoke the application. 
735  */
736 void
737 dtb_save_command(
738     char        *argv0
739 )
740 {
741     char        exe_dir[MAXPATHLEN+1];
742     dtb_save_command_str = argv0; 
743
744     /*
745      * Save the path to the executable
746      */
747     if (determine_exe_dir(argv0, exe_dir, MAXPATHLEN+1) >= 0)
748     {
749         dtb_exe_dir = (char *)malloc(strlen(exe_dir)+1);
750         if (dtb_exe_dir != NULL)
751         {
752             strcpy(dtb_exe_dir, exe_dir);
753         }
754     }
755 }
756
757
758 char * 
759 dtb_get_command() 
760 {
761     return(dtb_save_command_str); 
762 }
763
764
765 #ifdef DEAD_WOOD
766 /* 
767 ** Generic callback function to be attached as XmNhelpCallback and
768 ** provide support for on-object and Help-key help.  The help text to
769 ** be displayed is provided via a specialized data structure passed in
770 ** as client data.
771 */
772
773 void
774 dtb_help_dispatch(
775     Widget      widget,
776     XtPointer   clientData,
777     XtPointer   callData
778 )
779 {
780     DtbObjectHelpData   help_data = (DtbObjectHelpData)clientData;
781     int                 i;
782     Arg                 wargs[10];
783     char                *buffer = new char[100];
784     Widget              back_button;
785     static Widget       Quick_help_dialog = (Widget)NULL;
786     static Widget       MoreButton;
787
788     /* 
789     ** In order to save the more-help info (help volume & location ID) as part
790     ** of the quick help dialog's backtrack mechanism, we have to splice the 
791     ** volume & ID strings together and save them as the help volume field.
792     ** If there isn't supplemental help information, we save a null string.
793     **
794     ** Checking the status of the more-help info also lets us decide whether
795     ** the "More..." button should be enabled on the dialog.
796     */
797     if( help_data->help_volume     ==0 || *(help_data->help_volume) == NULL ||
798         help_data->help_locationID ==0 || *(help_data->help_locationID)== NULL){
799                 buffer[0] = '\0';
800     }
801     else {
802         sprintf(buffer,"%s/%s",help_data->help_volume,help_data->help_locationID);
803     }
804
805     /* 
806     ** If this is our first time to post help, create the proper dialog and
807     ** set its attributes to suit the current object.  If not, then just
808     ** update the attributes.
809     **
810     ** (You have to be careful about gratuitous SetValues on the dialog because
811     ** its internal stack mechanism takes repeated settings as separate items
812     ** and updates the stack for each.)
813     */
814     if(Quick_help_dialog == (Widget)NULL) {
815         /* Create shared help dialog */
816         i = 0;
817         XtSetArg(wargs[i],XmNtitle, "Application Help");            i++;
818         XtSetArg(wargs[i],DtNhelpType, DtHELP_TYPE_DYNAMIC_STRING); i++;
819         XtSetArg(wargs[i],DtNstringData,help_data->help_text);      i++;
820         XtSetArg(wargs[i],DtNhelpVolume,buffer);                    i++;
821         Quick_help_dialog = DtCreateHelpQuickDialog(dtb_get_toplevel_widget(),
822                 "Help",wargs,i);
823
824         /* 
825         ** Fetch out the Dialog's More button child and hook the 'more help'
826         ** handler to its activateCallback.  Set it's current status to
827         ** indicate whether this object has supplemental help data. 
828         */
829         MoreButton = DtHelpQuickDialogGetChild(Quick_help_dialog,
830                 DtHELP_QUICK_MORE_BUTTON);
831         XtManageChild(MoreButton);
832         XtAddCallback(MoreButton,XmNactivateCallback,dtb_more_help_dispatch,
833                 (XtPointer)Quick_help_dialog);
834         if(buffer[0] == '\0') XtSetSensitive(MoreButton,False);
835
836         /* 
837         ** Fetch out the Dialog's Backtrack button child & hook a callback
838         ** that will control button sensitivity based on the presence of more
839         ** help data.
840         */
841         back_button = DtHelpQuickDialogGetChild(Quick_help_dialog,
842                 DtHELP_QUICK_BACK_BUTTON);
843         XtAddCallback(back_button,XmNactivateCallback,dtb_help_back_hdlr,
844                 (XtPointer)Quick_help_dialog);
845     }
846     /* Otherwise the dialog already exists so we just set the attributes. */
847     else {
848         /* 
849         ** If we have supplemental help info, enable the more button.
850         ** Also save this info for later use in the backtrack handler.
851         */
852         if(buffer[0] == '\0') {
853             XtSetSensitive(MoreButton,False);
854         }
855         else {
856             XtSetSensitive(MoreButton,True);
857         }
858
859         XtVaSetValues(Quick_help_dialog,
860             DtNhelpType, DtHELP_TYPE_DYNAMIC_STRING,
861             DtNhelpVolume,buffer,
862             DtNstringData,help_data->help_text,
863             NULL);
864     }
865
866     /* Now display the help dialog */
867     XtManageChild(Quick_help_dialog);
868     delete [] buffer;
869 }
870 #endif /* DEAD_WOOD */
871
872
873 /*
874 ** This callback is invoked when the user presses "More..." on the
875 ** QuickHelpDialog.  It figures out whether a help volume entry is associated
876 ** with the displayed help text, and if so it brings up a GeneralHelpDialog
877 ** to display the appropriate help volume information.
878 */
879 void
880 dtb_more_help_dispatch(
881     Widget,
882     XtPointer   clientData,
883     XtPointer
884 )
885 {
886     int                 i;
887     Arg                 wargs[10];
888     String              buffer, vol, loc;
889     char                *cp;
890     static Widget       GeneralHelpDialog = (Widget) NULL;
891     Widget              help_dialog = (Widget)clientData;
892
893     /* Fetch the saved volume/locationID information from the dialog widget */
894     XtVaGetValues(help_dialog,
895         DtNhelpVolume,&buffer,
896         NULL);
897
898     /* 
899     ** Parse the combined volume/locationID string.  If that fails there
900     ** must be no data, so don't bother displaying the GeneralHelpDialog.
901     ** (We shouldn't be in this callback routine if that happens, though...)
902     */
903     if( (cp=strrchr(buffer,'/')) != (char *)NULL) {
904         *cp++ = 0;
905         vol = buffer;
906         loc = cp; 
907     }
908
909     if(GeneralHelpDialog == (Widget)NULL) {
910         /* Create General Help Dialog */
911         i = 0;
912         XtSetArg(wargs[i],XmNtitle, "Application Help");        i++;
913         XtSetArg(wargs[i],DtNhelpType, DtHELP_TYPE_TOPIC);      i++;
914         XtSetArg(wargs[i],DtNhelpVolume, vol);                  i++;
915         XtSetArg(wargs[i],DtNlocationId,loc);                   i++;
916
917         GeneralHelpDialog = DtCreateHelpDialog(dtb_get_toplevel_widget(),
918                 "GeneralHelp",wargs,i);
919     }
920     else {
921         i = 0;
922         XtSetArg(wargs[i],DtNhelpType, DtHELP_TYPE_TOPIC);      i++;
923         XtSetArg(wargs[i],DtNhelpVolume,vol);                   i++;
924         XtSetArg(wargs[i],DtNlocationId,loc);                   i++;
925         XtSetValues(GeneralHelpDialog,wargs,i);
926     }
927
928     /* Now take down the quick help dialog and display the full help one */
929     XtManageChild(GeneralHelpDialog);
930     XtUnmanageChild(help_dialog);
931 }
932
933
934 /*
935 ** Callback that is added to the QuickHelpDialog widget's "Backtrack" button
936 ** and is used to control the "More.." button.  At each step in the backtrack,
937 ** this routine checks to see if there is help volume & location info stored
938 ** in the dialog's helpVolume resource.  If so, then the "More..." button is
939 ** enabled.  If not, then it is disabled.
940 */
941 void
942 dtb_help_back_hdlr(
943     Widget,
944     XtPointer   clientData,
945     XtPointer
946 )
947 {
948     String              buffer, text;
949     char                *cp;
950     Widget              more_button;
951     Widget              help_dialog = (Widget)clientData;
952
953     /* Fetch the saved volume/locationID information from the dialog widget */
954     XtVaGetValues(help_dialog,
955         DtNhelpVolume,&buffer,
956         DtNstringData,&text,
957         NULL);
958
959     /* Get a handle to the "More..." button */
960     more_button = DtHelpQuickDialogGetChild(help_dialog,
961                 DtHELP_QUICK_MORE_BUTTON);
962     /* 
963     ** Parse the combined volume/locationID string.  Disable the "More..."
964     ** button if there isn't any help info, and enable it if there is.
965     */
966     if( buffer == 0 || (*buffer == '/0') ||
967         (cp=strrchr(buffer,'/')) == (char *)NULL) {
968                 XtSetSensitive(more_button,False);
969     }
970     else {
971                 XtSetSensitive(more_button,True);
972     }
973 }
974
975
976 #ifdef DEAD_WOOD
977 /*
978 ** Utility function used to provide support for on-item help.
979 ** It is typically invoked via a callback on the "On Item" item in the
980 ** main menubar's "Help" menu.
981 */
982 void
983 dtb_do_onitem_help()
984 {
985     Widget      target;
986
987     /* Call the DtHelp routine that supports interactive on-item help. */
988     if(DtHelpReturnSelectedWidgetId(dtb_get_toplevel_widget(),
989         (Cursor)NULL,&target) != DtHELP_SELECT_VALID) return;
990         
991     /*
992     ** Starting at the target widget, wander up the widget tree looking
993     ** for one that has an XmNhelpCallback, and call the first one we
994     ** find.
995     */
996     while(target != (Widget)NULL) {
997         if( XtHasCallbacks(target,XmNhelpCallback) == XtCallbackHasSome) {
998             XtCallCallbacks(target,XmNhelpCallback,(XtPointer)NULL);
999             return;
1000         }
1001         else {
1002             target = XtParent(target);
1003         }
1004     }
1005     return;
1006 }
1007 #endif /* DEAD_WOOD */
1008
1009
1010 /*
1011 ** Utility function called to display help volume information.
1012 ** It needs the name of the help volume and the location ID (both as
1013 ** strings) so it can configure the full help dialog widget properly.
1014 */
1015 int
1016 dtb_show_help_volume_info(
1017     char        *volume_name,
1018     char        *location_id
1019 )
1020 {
1021     int                 i;
1022     Arg                 wargs[10];
1023     static Widget       GeneralHelpDialog = (Widget) NULL;
1024     
1025     if(GeneralHelpDialog == (Widget)NULL) {
1026         /* Create General Help Dialog */
1027         i = 0;
1028         XtSetArg(wargs[i],XmNtitle, "Application Help");        i++;
1029         XtSetArg(wargs[i],DtNhelpType, DtHELP_TYPE_TOPIC);      i++;
1030         XtSetArg(wargs[i],DtNhelpVolume, volume_name);          i++;
1031         XtSetArg(wargs[i],DtNlocationId,location_id);           i++;
1032
1033         GeneralHelpDialog = DtCreateHelpDialog(dtb_get_toplevel_widget(),
1034                 "GeneralHelp",wargs,i);
1035     }
1036     else {
1037         i = 0;
1038         XtSetArg(wargs[i],DtNhelpType, DtHELP_TYPE_TOPIC);      i++;
1039         XtSetArg(wargs[i],DtNhelpVolume,volume_name);           i++;
1040         XtSetArg(wargs[i],DtNlocationId,location_id);           i++;
1041         XtSetValues(GeneralHelpDialog,wargs,i);
1042     }
1043
1044     /* Now display the full help dialog */
1045     XtManageChild(GeneralHelpDialog);
1046
1047     return(0);
1048 }
1049
1050
1051 #ifdef DEAD_WOOD
1052 /* 
1053 ** dtb_call_help_callback()
1054 ** Utility routine to call the help callbacks on a target widget.  This
1055 ** is predominantly used to display help data on a dialog by having this
1056 ** function as the activate callback on the dialog's help button.
1057 */
1058 void 
1059 dtb_call_help_callback(
1060     Widget widget,
1061     XtPointer clientData,
1062     XtPointer callData
1063 )
1064 {
1065         Widget target = (Widget)clientData;
1066
1067         XtCallCallbacks(target,XmNhelpCallback,(XtPointer)NULL);
1068 }
1069 #endif /* DEAD_WOOD */
1070
1071
1072 /*
1073  * dtb_session_save()
1074  * Callback that is called when the application (top level
1075  * widget of application) gets a WM_SAVE_YOURSELF ClientMessage
1076  * This callback will call the client/application's session
1077  * save callback.
1078  */
1079 void
1080 dtb_session_save(
1081     Widget      widget,
1082     XtPointer,
1083     XtPointer
1084 )
1085 {
1086     int                         new_argc,
1087                                 client_argc = 0,
1088                                 new_argc_counter,
1089                                 i;
1090     char                        **new_argv,
1091                                 **client_argv = NULL,
1092                                 *session_file_path,
1093                                 *session_file_name,
1094                                 *app_name = NULL;
1095     Boolean                     status = False;
1096     DtbClientSessionSaveCB      session_saveCB;
1097
1098     /*
1099      * Return if no widget passed in.
1100      */
1101     if (!widget)
1102         return;
1103
1104     /*
1105      * Get session file path/name to store application's state
1106      */
1107     if (DtSessionSavePath(widget, &session_file_path, &session_file_name) == False)
1108         return;
1109
1110     /*
1111      * Get client session save callback
1112      */
1113     session_saveCB = dtb_get_client_session_saveCB();
1114
1115     /*
1116      * Call client session save callback
1117      */
1118     if (session_saveCB)
1119         /*
1120          * client_argv and client_argc are the variables that
1121          * will contain any extra command line options
1122          * that need to be used when invoking the application
1123          * to bring it to the current state.
1124          */
1125         status = session_saveCB(widget, session_file_path,
1126                                 &client_argv, &client_argc);
1127
1128     /*
1129      * Generate the reinvoking command and add it as the property value
1130      */
1131
1132     /*  
1133      * Fetch command used to invoke application
1134      */
1135     app_name = dtb_get_command();
1136
1137     /*
1138      * new_argc and new_argc are the variables used to reconstruct
1139      * the command to re-invoke the application
1140      */
1141
1142     /*
1143      * Start new_argc with:
1144      *  1       for argv[0], normally the application
1145      *  client_argc     any extra command line options as
1146      *          returned from client session save
1147      *          callback
1148      */
1149     new_argc = 1 + client_argc;
1150
1151     /*
1152      * If the status returned from session save callback is 'True',
1153      * the session file was actually used. This means we need to
1154      * add:
1155      *  -session <session file name>
1156      * to the command saved, which is 2 more strings.
1157      */
1158     if (status)
1159         new_argc += 2;
1160
1161     /*
1162      * Allocate vector
1163      */
1164     new_argv = (char **)XtMalloc((sizeof(char **) * new_argc));
1165
1166     /*
1167      * Set new_argv[0] to be the application name
1168      */
1169     new_argc_counter = 0;
1170     new_argv[new_argc_counter] = app_name;
1171     new_argc_counter++;
1172
1173     /*
1174      * Proceed to copy every command line option from
1175      * client_argv. Skip -session, if found.
1176      */
1177     for (i=0; i < client_argc;)
1178     {
1179         if (strcmp(client_argv[i], "-session"))
1180         {
1181             new_argv[new_argc_counter] = client_argv[i];
1182             new_argc_counter++;
1183         }
1184         else
1185         {
1186             /*
1187              * Skip "-session"
1188              * The next increment below will skip the session file.
1189              */
1190             ++i;
1191         }
1192
1193         ++i;
1194         
1195     }
1196
1197     /*
1198      * If session file used, add
1199      *  -session <session file name>
1200      */
1201     if (status)
1202     {
1203         new_argv[new_argc_counter] = "-session";
1204         new_argc_counter++;
1205         new_argv[new_argc_counter] = session_file_name;
1206     }
1207     else
1208     {
1209         /*
1210          * otherwise, destroy session file
1211          */
1212         (void)unlink(session_file_path);
1213     }
1214
1215     /*
1216      * Set WM_COMMAND property with vector constructed
1217      */
1218     XSetCommand(XtDisplay(widget), XtWindow(widget),
1219                 new_argv, new_argc);
1220
1221     /*
1222      * Free argument vector
1223      */
1224     XtFree ((char *)new_argv);
1225
1226     /*
1227      * CDE Sessioning API states that the path/name
1228      * strings have to be free'd by the application.
1229      */
1230     XtFree ((char *)session_file_path);
1231     XtFree ((char *)session_file_name);
1232 }
1233
1234
1235 /*
1236  * dtb_get_client_session_saveCB()
1237  */
1238 DtbClientSessionSaveCB
1239 dtb_get_client_session_saveCB()
1240 {
1241     return(dtb_client_session_saveCB);
1242
1243 }
1244
1245
1246 #ifdef DEAD_WOOD
1247 /*
1248  * This function will center all the passed form's children.
1249  * The type of centering depends on what 'type' is.
1250  */
1251 void
1252 dtb_children_center(
1253     Widget              form,
1254     DTB_CENTERING_TYPES type
1255 )
1256 {
1257     WidgetList          children_list;
1258     int                 i, 
1259                         num_children;
1260
1261     if (!form || (type == DTB_CENTER_NONE))
1262         return;
1263
1264     /*
1265      * Get children list
1266      */
1267     XtVaGetValues(form,
1268             XmNnumChildren, &num_children,
1269             XmNchildren, &children_list,
1270             NULL);
1271
1272     /*
1273      * Center all children
1274      */
1275     for (i=0; i < num_children; ++i)
1276     {
1277         dtb_center(children_list[i], type);
1278     }
1279 }
1280
1281
1282 /*
1283  * This function 'uncenters' the children of the passed
1284  * form widget.
1285  */
1286 void
1287 dtb_children_uncenter(
1288     Widget              form,
1289     DTB_CENTERING_TYPES type
1290 )
1291 {
1292     WidgetList          children_list;
1293     int                 i;
1294     int                 num_children;
1295
1296     if (!form || (type == DTB_CENTER_NONE))
1297         return;
1298
1299     /*
1300      * Get children list
1301      */
1302     XtVaGetValues(form,
1303             XmNnumChildren, &num_children,
1304             XmNchildren, &children_list,
1305             NULL);
1306
1307     /*
1308      * Center all children
1309      */
1310     for (i=0; i < num_children; ++i)
1311     {
1312         dtb_uncenter(children_list[i], type);
1313     }
1314 }
1315 #endif /* DEAD_WOOD */
1316
1317
1318 /*
1319  * This function centers the passed widget.
1320  * This is done by setting the proper offsets.
1321  * Dynamic centering is accomplished by attaching an event handler
1322  * which detect resizes and recomputes and sets the appropriate offset.
1323  */
1324 void
1325 dtb_center(
1326     Widget              form_child,
1327     DTB_CENTERING_TYPES type
1328 )
1329 {
1330     if (!form_child || (type == DTB_CENTER_NONE))
1331         return;
1332
1333    center_widget(form_child, type);
1334
1335    XtAddEventHandler(form_child,
1336             StructureNotifyMask, False,
1337             centering_handler, (XtPointer)type);
1338 }
1339
1340
1341 /*
1342  * This function 'uncenters' the passed widget.
1343  * This involves resetting the attachment offsets
1344  * and removing the resize event handler.
1345  */
1346 void
1347 dtb_uncenter(
1348     Widget              form_child,
1349     DTB_CENTERING_TYPES type
1350 )
1351 {
1352     if (!form_child || (type == DTB_CENTER_NONE))
1353         return;
1354
1355    uncenter_widget(form_child, type);
1356
1357    XtRemoveEventHandler(form_child,
1358             StructureNotifyMask, False,
1359             centering_handler, (XtPointer)type);
1360 }
1361
1362
1363 /*
1364  * This function centers the passed widget.
1365  * This is done by making the appropriate offset equal 
1366  * to the negative half of it's width/height (depending
1367  * on whether horizontal or vertical centering was chosen.
1368  */
1369 static void 
1370 center_widget(
1371     Widget              form_child,
1372     DTB_CENTERING_TYPES type
1373 )
1374 {
1375     Widget              parent;
1376     Dimension           width = 0,
1377                         height = 0;
1378     int                 center_offset;
1379     unsigned char       left_attach = XmATTACH_NONE,
1380                         top_attach = XmATTACH_NONE;
1381
1382     if (!form_child || !XtIsManaged(form_child) || !XtIsRealized(form_child))
1383         return;
1384
1385     parent = XtParent(form_child);
1386
1387     if (!parent || !XtIsSubclass(parent, xmFormWidgetClass))
1388         return;
1389
1390     XtVaGetValues(form_child,
1391                 XmNwidth, &width,
1392                 XmNheight, &height,
1393                 XmNleftAttachment, &left_attach,
1394                 XmNtopAttachment, &top_attach,
1395                 NULL);
1396
1397     switch (type) {
1398         case DTB_CENTER_POSITION_VERT:
1399
1400             if (left_attach != XmATTACH_POSITION)
1401                 return;
1402
1403             center_offset = -(width/2);
1404
1405             XtVaSetValues(form_child,
1406                 XmNleftOffset, center_offset,
1407                 NULL);
1408
1409         break;
1410
1411         case DTB_CENTER_POSITION_HORIZ:
1412
1413             if (top_attach != XmATTACH_POSITION)
1414                 return;
1415
1416             center_offset = -(height/2);
1417
1418             XtVaSetValues(form_child,
1419                 XmNtopOffset, center_offset,
1420                 NULL);
1421         break;
1422
1423         case DTB_CENTER_POSITION_BOTH:
1424         {
1425             int         left_offset,
1426                         top_offset;
1427
1428             if ((left_attach != XmATTACH_POSITION) &&
1429                 (top_attach != XmATTACH_POSITION))
1430                 return;
1431             
1432             left_offset = -(width/2);
1433             top_offset = -(height/2);
1434
1435             XtVaSetValues(form_child,
1436                 XmNleftOffset, left_offset,
1437                 XmNtopOffset, top_offset,
1438                 NULL);
1439         }
1440         break;
1441
1442         default:
1443         break;
1444     }
1445 }
1446
1447
1448 /*
1449  * This function 'uncenters' the passed widget.
1450  * It merely resets the offsets of the top/left attachments to 0.
1451  */
1452 static void 
1453 uncenter_widget(
1454     Widget              form_child,
1455     DTB_CENTERING_TYPES type
1456 )
1457 {
1458     Widget              parent;
1459     unsigned char       left_attach = XmATTACH_NONE,
1460                         top_attach = XmATTACH_NONE;
1461
1462     if (!form_child || !XtIsManaged(form_child) || !XtIsRealized(form_child))
1463         return;
1464
1465     parent = XtParent(form_child);
1466
1467     if (!parent || !XtIsSubclass(parent, xmFormWidgetClass))
1468         return;
1469
1470     XtVaGetValues(form_child,
1471                 XmNleftAttachment, &left_attach,
1472                 XmNtopAttachment, &top_attach,
1473                 NULL);
1474
1475     switch (type) {
1476         case DTB_CENTER_POSITION_VERT:
1477
1478             if (left_attach != XmATTACH_POSITION)
1479                 return;
1480
1481             XtVaSetValues(form_child,
1482                 XmNleftOffset, 0,
1483                 NULL);
1484
1485         break;
1486
1487         case DTB_CENTER_POSITION_HORIZ:
1488
1489             if (top_attach != XmATTACH_POSITION)
1490                 return;
1491
1492             XtVaSetValues(form_child,
1493                 XmNtopOffset, 0,
1494                 NULL);
1495         break;
1496
1497         case DTB_CENTER_POSITION_BOTH:
1498
1499             if ((left_attach != XmATTACH_POSITION) &&
1500                 (top_attach != XmATTACH_POSITION))
1501                 return;
1502
1503             XtVaSetValues(form_child,
1504                 XmNleftOffset, 0,
1505                 XmNtopOffset, 0,
1506                 NULL);
1507         break;
1508
1509         default:
1510         break;
1511     }
1512 }
1513
1514
1515 /*
1516  * Event handler to center a widget
1517  * The type of centering needed is passed in as client_data
1518  */
1519 static void
1520 centering_handler(
1521     Widget      widget,
1522     XtPointer   client_data,
1523     XEvent      *event,
1524     Boolean     *
1525 )
1526 {
1527     XConfigureEvent     *xcon = &event->xconfigure;
1528     Widget              resized_child;
1529     DTB_CENTERING_TYPES type = (DTB_CENTERING_TYPES)((long)client_data);
1530
1531
1532     if ((event->type != ConfigureNotify) && (event->type != MapNotify))
1533         return;
1534
1535     resized_child = XtWindowToWidget(XtDisplay(widget), xcon->window);
1536
1537     if (!resized_child)
1538         return;
1539
1540     center_widget(resized_child, type);
1541 }
1542
1543
1544 /*
1545  * Given a widget, return it's label widget.
1546  */
1547 static Widget
1548 get_label_widget(
1549     Widget      widget
1550 )
1551 {
1552     WidgetList  children_list;
1553     Widget      label_widget = NULL;
1554     int         num_children = 0;
1555     char        *subobj_name = NULL,
1556                 *label_name = NULL;
1557
1558     if (XtIsSubclass(widget, xmLabelWidgetClass))  {
1559         return(widget);
1560     }
1561
1562     subobj_name = XtName(widget);
1563     label_name = (char *)XtMalloc(1 + strlen(subobj_name) + strlen("_label") + 1);
1564     sprintf(label_name, "*%s_label", subobj_name);
1565
1566     label_widget = XtNameToWidget(widget, label_name);
1567
1568     XtFree((char *)label_name);
1569
1570     if (label_widget)
1571         return(label_widget);
1572
1573     /*
1574      * How to look for 1st child of group object ??
1575      * How do we know if 'widget' is a group object ??
1576      * For now, just check if it is a form
1577      */
1578     if (XtIsSubclass(widget, xmFormWidgetClass) || 
1579         XtIsSubclass(widget, xmFrameWidgetClass))
1580         XtVaGetValues(widget,
1581             XmNnumChildren, &num_children,
1582             XmNchildren, &children_list,
1583             NULL);
1584
1585     if (num_children > 0)
1586         return(get_label_widget(children_list[0]));
1587
1588     return (NULL);
1589 }
1590
1591
1592 static Position
1593 get_offset_from_ancestor(
1594     Widget      ancestor,
1595     Widget      w
1596 )
1597 {
1598     Widget      cur = w;
1599     Widget      cur_parent = NULL;
1600     Position    offset = 0;
1601
1602     if (!ancestor || !w || (w == ancestor))
1603         return (0);
1604
1605     XtVaGetValues(cur, XmNx, &offset, NULL);
1606
1607     cur_parent = XtParent(cur);
1608
1609     while (cur_parent != ancestor)
1610     {
1611         Position        tmp_offset = 0;
1612
1613         cur = cur_parent;
1614         XtVaGetValues(cur, XmNx, &tmp_offset, NULL);
1615         
1616         offset += tmp_offset;
1617         cur_parent = XtParent(cur);
1618     }
1619
1620     return (offset);
1621 }
1622
1623
1624 static Dimension
1625 get_label_width(
1626     Widget      widget
1627 )
1628 {
1629     Widget      lbl_widget = NULL;
1630     Dimension   lbl_width = 0;
1631
1632     lbl_widget = get_label_widget(widget);
1633
1634     if (lbl_widget)
1635     {
1636         Position        offset = 0;
1637
1638         XtVaGetValues(lbl_widget,
1639             XmNwidth, &lbl_width,
1640             NULL);
1641
1642         offset = get_offset_from_ancestor(widget, lbl_widget);
1643
1644         lbl_width += (Dimension)offset;
1645     }
1646     
1647     return (lbl_width);
1648 }
1649
1650
1651 static void
1652 get_widest_label(
1653     WidgetList  list,
1654     int         count,
1655     Widget      *child_widget,
1656     Dimension   *label_width
1657 )
1658 {
1659     Widget      cur_widest = NULL;
1660     Dimension   cur_width = 0;
1661     int         i;
1662
1663     for (i = 0; i < count; ++i)
1664     {
1665         Dimension       tmp;
1666
1667         tmp = get_label_width(list[i]);
1668
1669         if (tmp > cur_width)
1670         {
1671             cur_width = tmp;
1672             cur_widest = list[i];
1673         }
1674     }
1675     
1676     *child_widget = cur_widest;
1677     *label_width = cur_width;
1678 }
1679
1680
1681 static void
1682 get_widest_value(
1683     WidgetList  list,
1684     int         count,
1685     Widget      *child_widget,
1686     Dimension   *value_width
1687 )
1688 {
1689     Widget      cur_widest = NULL;
1690     Dimension   cur_width = 0;
1691     int         i;
1692
1693     for (i = 0; i < count; ++i)
1694     {
1695         Dimension       tmp, label_width, obj_width = 0;
1696
1697         label_width = get_label_width(list[i]);
1698         XtVaGetValues(list[i], XmNwidth, &obj_width, NULL);
1699
1700         tmp = obj_width - label_width;
1701
1702         if (tmp > cur_width)
1703         {
1704             cur_width = tmp;
1705             cur_widest = list[i];
1706         }
1707     }
1708     
1709     *child_widget = cur_widest;
1710     *value_width = cur_width;
1711 }
1712
1713
1714 static void
1715 get_widget_rect(
1716     Widget widget,
1717     XRectangle *rect
1718 )
1719 {
1720     if (!rect)
1721         return;
1722
1723     XtVaGetValues(widget,
1724         XtNwidth,       (XtArgVal)&(rect->width),
1725         XtNheight,      (XtArgVal)&(rect->height),
1726         XtNx,           (XtArgVal)&(rect->x),
1727         XtNy,           (XtArgVal)&(rect->y),
1728         NULL);
1729 }
1730
1731
1732 static void
1733 get_greatest_size(
1734     Widget      *list,
1735     int         count,
1736     int         *width,
1737     int         *height,
1738     Widget      *tallest,
1739     Widget      *widest
1740 )
1741 {
1742     XRectangle  w_rect;
1743     int         i;
1744     int         previous_width, previous_height;
1745
1746     if (!list || (count < 0))
1747         return;
1748
1749     get_widget_rect(list[0], &w_rect);
1750
1751     *width = w_rect.width;
1752     previous_width = *width;
1753
1754     *height = w_rect.height;
1755     previous_height = *height;
1756
1757     if (tallest != NULL)
1758         *tallest = list[0];
1759
1760     if (widest != NULL)
1761         *widest = list[0];
1762
1763     for (i=0; i < count; i++)
1764     {
1765         get_widget_rect(list[i], &w_rect);
1766
1767         *width = max((int) w_rect.width, (int) *width); 
1768         if (widest != NULL && *width > previous_width)
1769                 *widest = list[i];
1770
1771         *height = max((int) w_rect.height, (int)*height);
1772         if (tallest != NULL && *height > previous_height)
1773                 *tallest = list[i];
1774     }
1775 }
1776
1777
1778 static void
1779 get_group_cell_size(
1780     Widget              parent,
1781     DtbGroupInfo        *,
1782     int                 *cell_width,
1783     int                 *cell_height
1784 )
1785 {
1786     WidgetList  children_list = NULL;
1787     int         num_children = 0;
1788
1789     /*
1790      * Get children list
1791      */
1792     XtVaGetValues(parent,
1793             XmNnumChildren, &num_children,
1794             XmNchildren, &children_list,
1795             NULL);
1796
1797     get_greatest_size(children_list, num_children,
1798                 cell_width, cell_height,
1799                 (Widget *)NULL, (Widget *)NULL);
1800 }
1801
1802
1803 static void
1804 get_group_row_col(
1805     Widget              parent,
1806     DtbGroupInfo        *group_info,
1807     int                 *rows,
1808     int                 *cols
1809 )
1810 {
1811     WidgetList  children_list = NULL;
1812     int         num_rows,
1813                 num_cols,
1814                 num_children;
1815
1816     if (!parent || !group_info)
1817     {
1818         *rows = *cols = -1;
1819
1820         return;
1821     }
1822
1823     /*
1824      * Get children list
1825      */
1826     XtVaGetValues(parent,
1827             XmNnumChildren, &num_children,
1828             XmNchildren, &children_list,
1829             NULL);
1830
1831     num_rows = group_info->num_rows;
1832     num_cols = group_info->num_cols;
1833
1834     if ((num_rows <= 0) && (num_cols <= 0))
1835     {
1836         *rows = *cols = -1;
1837
1838         return;
1839     }
1840
1841     if (num_cols <= 0)
1842         num_cols = (num_children/num_rows) + ((num_children % num_rows) ? 1 : 0);
1843
1844     if (num_rows <= 0)
1845         num_rows = (num_children/num_cols) + ((num_children % num_cols) ? 1 : 0);
1846
1847     *rows = num_rows;
1848     *cols = num_cols;
1849 }
1850
1851
1852 static Widget
1853 get_group_child(
1854     Widget              parent,
1855     DtbGroupInfo        *group_info,
1856     int                 x_pos,
1857     int                 y_pos
1858 )
1859 {
1860     DTB_GROUP_TYPES     group_type;
1861     WidgetList          children_list = NULL;
1862     Widget              ret_child = NULL;
1863     int                 num_children = 0,
1864                         num_rows,
1865                         num_columns,
1866                         i = -1;
1867
1868     if (!parent || !group_info || 
1869        (x_pos < 0) || (y_pos < 0))
1870         return (NULL);
1871
1872     group_type = group_info->group_type;
1873     num_rows = group_info->num_rows;
1874     num_columns = group_info->num_cols;
1875
1876     /*
1877      * Get number of children
1878      */
1879     XtVaGetValues(parent,
1880             XmNnumChildren, &num_children,
1881             XmNchildren, &children_list,
1882             NULL);
1883
1884     if (num_children <= 0)
1885         return (NULL);
1886
1887     switch (group_type)
1888     {
1889         case DTB_GROUP_NONE:
1890         break;
1891
1892         case DTB_GROUP_ROWS:
1893             /*
1894              * num_rows = 1
1895              * y_pos is ignored
1896              */
1897             i = x_pos;
1898         break;
1899
1900         case DTB_GROUP_COLUMNS:
1901             /*
1902              * num_columns = 1
1903              * x_pos is ignored
1904              */
1905             i = y_pos;
1906         break;
1907
1908         case DTB_GROUP_ROWSCOLUMNS:
1909             if (!num_rows && !num_columns)
1910                 break;
1911
1912             if (num_rows > 0)
1913             {
1914                 /*
1915                  * ROWFIRST
1916                  */
1917                 if (y_pos < num_rows)
1918                     i = (x_pos * num_rows) + y_pos;
1919             }
1920             else
1921             {
1922                 /*
1923                  * COLFIRST
1924                  */
1925                 if (x_pos < num_columns)
1926                     i = x_pos + (y_pos * num_columns);
1927             }
1928         break;
1929
1930         default:
1931         break;
1932     }
1933
1934     if ((i >= 0) && (i < num_children))
1935     {
1936         ret_child = children_list[i];
1937     }
1938
1939     return (ret_child);
1940 }
1941
1942
1943 void
1944 dtb_children_align(
1945     Widget              parent,
1946     DTB_GROUP_TYPES     group_type,
1947     DTB_ALIGN_TYPES     row_align,
1948     DTB_ALIGN_TYPES     col_align,
1949     int                 margin,
1950     int                 num_rows,
1951     int                 num_cols,
1952     int                 hoffset,
1953     int                 voffset
1954 )
1955 {
1956     DtbGroupInfo                *group_info;
1957
1958     switch (group_type)
1959     {
1960         case DTB_GROUP_COLUMNS:
1961             num_rows = 0;
1962             num_cols = 1;
1963         break;
1964
1965         case DTB_GROUP_ROWS:
1966             num_rows = 1;
1967             num_cols = 0;
1968         break;
1969
1970     }
1971
1972 #ifdef DTB_GROUP_USERDATA
1973     XtVaGetValues(parent, XmNuserData, (XtPointer)&group_info, NULL);
1974
1975     if (group_info)
1976     {
1977         XtRemoveEventHandler(parent,
1978                 SubstructureNotifyMask, False,
1979                 align_handler, (XtPointer)group_info);
1980
1981         XtRemoveCallback(parent, XtNdestroyCallback, 
1982                 free_group_info, (XtPointer)group_info);
1983
1984         XtFree((char *)group_info);
1985     }
1986 #endif
1987
1988     group_info = (DtbGroupInfo *)XtMalloc(sizeof(DtbGroupInfo));
1989
1990     group_info->group_type = group_type;
1991     group_info->row_align = row_align;
1992     group_info->col_align = col_align;
1993     group_info->margin = margin;
1994     group_info->num_rows = num_rows;
1995     group_info->num_cols = num_cols;
1996     group_info->hoffset = hoffset;
1997     group_info->voffset = voffset;
1998     group_info->ref_widget = NULL;
1999
2000 #ifdef DTB_GROUP_USERDATA
2001     XtVaSetValues(parent, XmNuserData, (XtPointer)group_info, NULL);
2002 #endif
2003
2004     align_children(parent, group_info, True);
2005
2006     switch(group_info->group_type)
2007     {
2008         case DTB_GROUP_NONE:
2009         break;
2010
2011         case DTB_GROUP_ROWS:
2012             if (group_info->row_align == DTB_ALIGN_HCENTER)
2013                 XtAddEventHandler(parent,
2014                         SubstructureNotifyMask, False,
2015                         align_handler, (XtPointer)group_info);
2016         break;
2017
2018         case DTB_GROUP_COLUMNS:
2019             if ((group_info->col_align == DTB_ALIGN_LABELS) || 
2020                 (group_info->col_align == DTB_ALIGN_VCENTER))
2021                 XtAddEventHandler(parent,
2022                         SubstructureNotifyMask, False,
2023                         align_handler, (XtPointer)group_info);
2024         break;
2025
2026         case DTB_GROUP_ROWSCOLUMNS:
2027             if ((group_info->row_align == DTB_ALIGN_HCENTER) ||
2028                 (group_info->col_align == DTB_ALIGN_LABELS) || 
2029                 (group_info->col_align == DTB_ALIGN_VCENTER))
2030                 XtAddEventHandler(parent,
2031                         SubstructureNotifyMask, False,
2032                         align_handler, (XtPointer)group_info);
2033         break;
2034
2035     }
2036
2037     XtAddCallback(parent, XtNdestroyCallback, 
2038                 free_group_info, (XtPointer)group_info);
2039 }
2040
2041
2042 static void
2043 align_children(
2044     Widget              parent,
2045     DtbGroupInfo        *group_info,
2046     Bool                init
2047 )
2048 {
2049     WidgetList  children_list = NULL;
2050     int         num_children = 0;
2051
2052     if (!parent || !group_info)
2053         return;
2054
2055     if (group_info->group_type != DTB_GROUP_NONE)
2056     {
2057         XtVaGetValues(parent,
2058             XmNnumChildren, &num_children,
2059             XmNchildren, &children_list,
2060             NULL);
2061
2062         XtUnmanageChildren(children_list, num_children);
2063     }
2064
2065     switch(group_info->group_type)
2066     {
2067         case DTB_GROUP_NONE:
2068         break;
2069
2070         case DTB_GROUP_ROWS:
2071             align_rows(parent, group_info, init);
2072             align_left(parent, group_info);
2073         break;
2074
2075         case DTB_GROUP_COLUMNS:
2076             align_cols(parent, group_info, init);
2077             align_top(parent, group_info);
2078         break;
2079
2080         case DTB_GROUP_ROWSCOLUMNS:
2081             align_rows(parent, group_info, init);
2082             align_cols(parent, group_info, init);
2083         break;
2084
2085     }
2086
2087     if (group_info->group_type != DTB_GROUP_NONE)
2088     {
2089         XtManageChildren(children_list, num_children);
2090     }
2091 }
2092
2093
2094 static void
2095 align_handler(
2096     Widget      widget,
2097     XtPointer   client_data,
2098     XEvent      *event,
2099     Boolean     *
2100 )
2101 {
2102     DtbGroupInfo        *group_info = (DtbGroupInfo *)client_data;
2103     WidgetList  children_list;
2104     int         num_children = 0;
2105     Boolean     relayout_all = False;
2106
2107
2108     /*
2109      * Get children list
2110      */
2111     XtVaGetValues(widget,
2112             XmNnumChildren, &num_children,
2113             XmNchildren, &children_list,
2114             NULL);
2115
2116     if (num_children <= 0)
2117         return;
2118
2119     XtRemoveEventHandler(widget,
2120                 SubstructureNotifyMask, False,
2121                 align_handler, (XtPointer)client_data);
2122
2123     if (event->type == ConfigureNotify) {
2124         XConfigureEvent *xcon = &event->xconfigure;
2125         Widget          resized_child;
2126
2127         if (xcon->window != xcon->event)
2128         {
2129             resized_child = XtWindowToWidget(XtDisplay(widget), xcon->window);
2130
2131             switch(group_info->group_type)
2132             {
2133                 case DTB_GROUP_NONE:
2134                 break;
2135
2136                 case DTB_GROUP_ROWS:
2137                     if (group_info->row_align == DTB_ALIGN_HCENTER)
2138                         relayout_all = True;
2139                 break;
2140
2141                 case DTB_GROUP_COLUMNS:
2142                     if ((group_info->col_align == DTB_ALIGN_LABELS) ||
2143                         (group_info->col_align == DTB_ALIGN_VCENTER))
2144                             relayout_all = True;
2145                 break;
2146
2147                 case DTB_GROUP_ROWSCOLUMNS:
2148                     if ((group_info->row_align == DTB_ALIGN_HCENTER) ||
2149                         (group_info->col_align == DTB_ALIGN_LABELS) ||
2150                         (group_info->col_align == DTB_ALIGN_VCENTER))
2151                         relayout_all = True;
2152                 break;
2153
2154             }
2155         }
2156     }
2157
2158     /*
2159      * Comment out for now
2160      * This is causing way too many calls to align_children()
2161     if (event->type == CreateNotify) {
2162         XCreateWindowEvent      *xcreate = &event->xcreatewindow;
2163         Widget                  new_child;
2164
2165         new_child = XtWindowToWidget(XtDisplay(widget), xcreate->window);
2166
2167         fprintf(stderr, "align_handler(%s) - child %s created\n",
2168                         XtName(widget),
2169                         XtName(new_child));
2170
2171
2172         relayout_all = True;
2173     }
2174     */
2175
2176     if (event->type == DestroyNotify) {
2177         XDestroyWindowEvent     *xdestroy = &event->xdestroywindow;
2178         Widget                  destroyed_child;
2179
2180         destroyed_child = XtWindowToWidget(XtDisplay(widget), 
2181                         xdestroy->window);
2182
2183         relayout_all = True;
2184     }
2185
2186     if (relayout_all)
2187     {
2188         align_children(widget, group_info, False);
2189     }
2190
2191     XtAddEventHandler(widget,
2192                 SubstructureNotifyMask, False,
2193                 align_handler, (XtPointer)client_data);
2194 }
2195
2196
2197 static void             
2198 free_group_info(
2199     Widget      ,
2200     XtPointer   client_data,
2201     XtPointer   
2202 )
2203 {
2204     DtbGroupInfo        *group_info = (DtbGroupInfo *)client_data;;
2205
2206     XtFree((char *)group_info);
2207 }
2208
2209
2210 static void
2211 align_rows(
2212     Widget              parent,
2213     DtbGroupInfo        *group_info,
2214     Bool                init
2215 )
2216 {
2217     if (!parent || !group_info || (group_info->group_type == DTB_GROUP_COLUMNS))
2218         return;
2219
2220     switch (group_info->row_align)
2221     {
2222         case DTB_ALIGN_TOP:
2223             align_top(parent, group_info);
2224         break;
2225
2226         case DTB_ALIGN_HCENTER:
2227             align_hcenter(parent, group_info, init);
2228         break;
2229
2230         case DTB_ALIGN_BOTTOM:
2231             align_bottom(parent, group_info);
2232         break;
2233
2234         default:
2235         break;
2236     }
2237 }
2238
2239
2240 static void
2241 align_cols(
2242     Widget              parent,
2243     DtbGroupInfo        *group_info,
2244     Bool                init
2245 )
2246 {
2247     if (!parent || !group_info || (group_info->group_type == DTB_GROUP_ROWS))
2248         return;
2249
2250     switch (group_info->col_align)
2251     {
2252         case DTB_ALIGN_LEFT:
2253             align_left(parent, group_info);
2254         break;
2255
2256         case DTB_ALIGN_LABELS:
2257             align_labels(parent, group_info);
2258         break;
2259
2260         case DTB_ALIGN_VCENTER:
2261             align_vcenter(parent, group_info, init);
2262         break;
2263
2264         case DTB_ALIGN_RIGHT:
2265             align_right(parent, group_info);
2266         break;
2267
2268         default:
2269         break;
2270     }
2271 }
2272
2273
2274 static void
2275 align_left(
2276     Widget              parent,
2277     DtbGroupInfo        *group_info
2278 )
2279 {
2280     WidgetList  children_list;
2281     Widget      child, 
2282                 previous_child;
2283     int         num_children = 0,
2284                 num_columns,
2285                 num_rows,
2286                 cell_width,
2287                 cell_height,
2288                 i,
2289                 j;
2290   
2291     if (!parent || !group_info)
2292         return;
2293
2294     /*
2295      * Get children list
2296      */
2297     XtVaGetValues(parent,
2298             XmNnumChildren, &num_children,
2299             XmNchildren, &children_list,
2300             NULL);
2301
2302     if (num_children <= 0)
2303         return;
2304     
2305     get_group_cell_size(parent, group_info, &cell_width, &cell_height);
2306     get_group_row_col(parent, group_info, &num_rows, &num_columns);
2307
2308     for (j = 0; j < num_rows; j++)
2309     {
2310         for (i = 0; i < num_columns; i++)
2311         {
2312             Arg         args[12];
2313             int         n = 0;
2314
2315             child = get_group_child(parent, group_info, i, j);
2316
2317             if (!child)
2318                 continue;
2319
2320             if ((i == 0) && (j == 0))
2321             {
2322                 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM);    n++;
2323                 XtSetArg(args[n], XmNleftOffset, 0);                    n++;
2324                 XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE);   n++;
2325
2326                 XtSetValues(child, args, n);
2327
2328                 continue;
2329             }
2330
2331             if (j == 0)
2332             {
2333                 int                     offset = group_info->hoffset;
2334                 DTB_GROUP_TYPES         group_type = group_info->group_type;
2335
2336                 previous_child = get_group_child(parent, group_info, i-1, j);
2337
2338                 if (!previous_child)
2339                     continue;
2340
2341                 if (group_type == DTB_GROUP_ROWSCOLUMNS)
2342                 {
2343                     Dimension   width = 0;
2344
2345                     XtVaGetValues(previous_child, XmNwidth, &width, NULL);
2346                     offset += (cell_width - (int)(width));
2347                 }
2348
2349                 XtSetArg(args[n], XmNleftAttachment, 
2350                                 XmATTACH_WIDGET);                       n++;
2351                 XtSetArg(args[n], XmNleftWidget, previous_child);       n++;
2352                 XtSetArg(args[n], XmNleftOffset, offset);               n++;
2353                 XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE);   n++;
2354
2355                 XtSetValues(child, args, n);
2356
2357                 continue;
2358             }
2359
2360             previous_child = get_group_child(parent, group_info, i, j-1);
2361
2362             if (previous_child)
2363             {
2364                 XtSetArg(args[n], XmNleftAttachment, 
2365                                     XmATTACH_OPPOSITE_WIDGET);          n++;
2366                 XtSetArg(args[n], XmNleftWidget, previous_child);       n++;
2367                 XtSetArg(args[n], XmNleftOffset, 0);                    n++;
2368                 XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE);   n++;
2369
2370                 XtSetValues(child, args, n);
2371             }
2372         }
2373     }
2374 }
2375
2376
2377 static void
2378 align_right(
2379     Widget              parent,
2380     DtbGroupInfo        *group_info
2381 )
2382 {
2383     WidgetList  children_list;
2384     Widget      child, 
2385                 previous_child;
2386     int         num_children = 0,
2387                 num_columns,
2388                 num_rows,
2389                 cell_width,
2390                 cell_height,
2391                 offset,
2392                 i,
2393                 j;
2394
2395     if (!parent || !group_info)
2396         return;
2397
2398     /*
2399      * Get children list
2400      */
2401     XtVaGetValues(parent,
2402             XmNnumChildren, &num_children,
2403             XmNchildren, &children_list,
2404             NULL);
2405
2406     if (num_children <= 0)
2407         return;
2408     
2409     get_group_cell_size(parent, group_info, &cell_width, &cell_height);
2410     get_group_row_col(parent, group_info, &num_rows, &num_columns);
2411
2412     for (j = 0; j < num_rows; j++)
2413     {
2414         for (i = 0; i < num_columns; i++)
2415         {
2416             Arg         args[12];
2417             int         n = 0;
2418
2419             child = get_group_child(parent, group_info, i, j);
2420
2421             if (!child)
2422                 continue;
2423
2424             if ((i == 0) && (j == 0))
2425             {
2426                 Dimension       width = 0;
2427
2428                 XtVaGetValues(child, XmNwidth, &width, NULL);
2429
2430                 offset = (cell_width - width);
2431
2432                 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM);    n++;
2433                 XtSetArg(args[n], XmNleftOffset, offset);               n++;
2434                 XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE);   n++;
2435
2436                 XtSetValues(child, args, n);
2437
2438                 continue;
2439             }
2440
2441             if (j == 0)
2442             {
2443                 previous_child = get_group_child(parent, group_info, i-1, j);
2444
2445                 if (!previous_child)
2446                     continue;
2447
2448                 offset = group_info->hoffset;
2449
2450                 if (group_info->group_type == DTB_GROUP_ROWSCOLUMNS)
2451                 {
2452                     Dimension   width = 0;
2453
2454                     XtVaGetValues(child, XmNwidth, &width, NULL);
2455                     offset += (cell_width - width);
2456                 }
2457
2458                 XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET);  n++;
2459                 XtSetArg(args[n], XmNleftWidget, previous_child);       n++;
2460                 XtSetArg(args[n], XmNleftOffset, offset);               n++;
2461                 XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE);   n++;
2462
2463                 XtSetValues(child, args, n);
2464
2465                 continue;
2466             }
2467
2468             previous_child = get_group_child(parent, group_info, i, j-1);
2469
2470             if (previous_child)
2471             {
2472                 XtSetArg(args[n], XmNrightAttachment, 
2473                                 XmATTACH_OPPOSITE_WIDGET);              n++;
2474                 XtSetArg(args[n], XmNrightWidget, previous_child);      n++;
2475                 XtSetArg(args[n], XmNrightOffset, 0);                   n++;
2476                 XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE);    n++;
2477
2478                 XtSetValues(child, args, n);
2479             }
2480         }
2481     }
2482 }
2483
2484
2485 static void
2486 align_labels(
2487     Widget              parent,
2488     DtbGroupInfo        *group_info
2489 )
2490 {
2491     WidgetList  children_list = NULL,
2492                 one_col;
2493     Widget      previous_child = NULL,
2494                 child,
2495                 previous_ref_widget = NULL;
2496     Dimension   ref_lbl_width = 0,
2497                 max_label_width = 0,
2498                 max_value_width = 0;
2499     int         num_children = 0,
2500                 num_rows,
2501                 num_columns,
2502                 cell_width,
2503                 cell_height,
2504                 offset,
2505                 i,
2506                 j;
2507
2508     if (!parent || !group_info)
2509         return;
2510
2511     /*
2512      * Get children list
2513      */
2514     XtVaGetValues(parent,
2515             XmNnumChildren, &num_children,
2516             XmNchildren, &children_list,
2517             NULL);
2518
2519     if (num_children <= 0)
2520         return;
2521     
2522     get_group_cell_size(parent, group_info, &cell_width, &cell_height);
2523
2524     get_widest_label(children_list, num_children, &child, &max_label_width);
2525     get_widest_value(children_list, num_children, &child, &max_value_width);
2526
2527     if (cell_width < (int)(max_label_width + max_value_width))
2528         cell_width = (int)(max_label_width + max_value_width);
2529
2530     get_group_row_col(parent, group_info, &num_rows, &num_columns);
2531
2532     if (num_rows > 0)
2533         one_col = (WidgetList)XtMalloc(num_rows * sizeof(WidgetList));
2534
2535     for (i = 0; i < num_columns; i++)
2536     {
2537         Widget          ref_widget;
2538         Dimension       ref_width;
2539         Arg             args[12];
2540         int             n = 0;
2541
2542         for (j = 0; j < num_rows; j++)
2543             one_col[j] = get_group_child(parent, group_info, i, j);
2544
2545         get_widest_label(one_col, num_rows, &ref_widget, &ref_width);
2546
2547         if (!ref_widget)
2548             continue;
2549
2550         if (previous_ref_widget)
2551             offset = (i * (group_info->hoffset + cell_width));
2552         else
2553             offset = 0;
2554
2555         XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM);    n++;
2556         XtSetArg(args[n], XmNleftOffset, offset);               n++;
2557         XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE);   n++;
2558
2559         XtSetValues(ref_widget, args, n);
2560
2561         for (j = 0; j < num_rows; j++)
2562         {
2563             child = get_group_child(parent, group_info, i, j);
2564
2565             if (!child || (child == ref_widget))
2566                 continue;
2567
2568             offset = (i * (group_info->hoffset + cell_width));
2569             offset += (int)(ref_width - get_label_width(child));
2570
2571             n = 0;
2572             XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM);        n++;
2573             XtSetArg(args[n], XmNleftOffset, offset);                   n++;
2574             XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE);       n++;
2575
2576             XtSetValues(child, args, n);
2577         }
2578
2579         previous_ref_widget = ref_widget;
2580     }
2581 }
2582
2583
2584 static void
2585 align_vcenter(
2586     Widget              parent,
2587     DtbGroupInfo        *group_info,
2588     Bool                init
2589 )
2590 {
2591     WidgetList  children_list;
2592     Widget      child;
2593     DTB_GROUP_TYPES group_type;
2594     int         num_children = 0,
2595                 num_columns,
2596                 num_rows,
2597                 cell_width,
2598                 cell_height,
2599                 group_width,
2600                 offset,
2601                 gridline,
2602                 i,
2603                 j;
2604
2605     if (!parent || !group_info)
2606         return;
2607
2608     /*
2609      * Get children list
2610      */
2611     XtVaGetValues(parent,
2612             XmNnumChildren, &num_children,
2613             XmNchildren, &children_list,
2614             NULL);
2615
2616     if (num_children <= 0)
2617         return;
2618     
2619     get_group_cell_size(parent, group_info, &cell_width, &cell_height);
2620          
2621     get_group_row_col(parent, group_info, &num_rows, &num_columns);
2622               
2623     offset = group_info->hoffset;
2624                    
2625     group_type = group_info->group_type;
2626
2627     if (group_type == DTB_GROUP_ROWSCOLUMNS)
2628     {
2629         group_width = (num_columns * cell_width) + ((num_columns-1) * offset);
2630     }
2631
2632     for (i = 0; i < num_columns; i++)
2633     {
2634         if (group_type == DTB_GROUP_ROWSCOLUMNS)
2635             gridline = (((i * (cell_width + offset)) + (cell_width/2)) * 100)/group_width;
2636         else
2637             gridline = 50;
2638
2639         for (j = 0; j < num_rows; j++)
2640         {
2641             Arg         args[12];
2642             int         n = 0;
2643             Dimension   width = 0;
2644
2645             child = get_group_child(parent, group_info, i, j);
2646
2647             if (!child)
2648                 continue;
2649
2650             XtVaGetValues(child, XmNwidth, &width, NULL);
2651
2652             if (init)
2653             {
2654                 int     offset = 0;
2655
2656                 if (!XtIsSubclass(child, compositeWidgetClass))
2657                 {
2658                     offset = (cell_width - (int)width)/2;
2659
2660                     if (group_type == DTB_GROUP_ROWSCOLUMNS)
2661                         offset += (i * (cell_width + group_info->hoffset));
2662                 }
2663
2664                 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM);    n++;
2665                 XtSetArg(args[n], XmNleftOffset, offset);               n++;
2666                 XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE);   n++;
2667             }
2668             else
2669             {
2670                 XtSetArg(args[n], XmNleftAttachment, 
2671                                 XmATTACH_POSITION);                     n++;
2672                 XtSetArg(args[n], XmNleftPosition, gridline);           n++;
2673                 XtSetArg(args[n], XmNleftOffset, (int)(-(width/2)));    n++;
2674                 XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE);   n++;
2675             }
2676
2677             XtSetValues(child, args, n);
2678         }
2679     }
2680 }
2681
2682
2683 static void
2684 align_top(
2685     Widget              parent,
2686     DtbGroupInfo        *group_info
2687 )
2688 {
2689     WidgetList  children_list;
2690     Widget      previous_child = NULL,
2691                 child;
2692     int         num_children = 0,
2693                 num_columns,
2694                 num_rows,
2695                 cell_width,
2696                 cell_height,
2697                 i,
2698                 j;
2699
2700     if (!parent || !group_info)
2701         return;
2702
2703     /*
2704      * Get children list
2705      */
2706     XtVaGetValues(parent,
2707             XmNnumChildren, &num_children,
2708             XmNchildren, &children_list,
2709             NULL);
2710
2711     if (num_children <= 0)
2712         return;
2713     
2714     get_group_cell_size(parent, group_info, &cell_width, &cell_height);
2715     get_group_row_col(parent, group_info, &num_rows, &num_columns);
2716
2717     for (j = 0; j < num_rows; j++)
2718     {
2719         for (i = 0; i < num_columns; i++)
2720         {
2721             Arg args[12];
2722             int n = 0;
2723
2724             child = get_group_child(parent, group_info, i, j);
2725
2726             if (!child)
2727                 continue;
2728
2729             if ((i == 0) && (j == 0))
2730             {
2731                 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM);     n++;
2732                 XtSetArg(args[n], XmNtopOffset, 0);                     n++;
2733                 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE);  n++;
2734
2735                 XtSetValues(child, args, n);
2736
2737                 continue;
2738             }
2739
2740             if (i == 0)
2741             {
2742                 previous_child = get_group_child(parent, group_info, 0, j-1);
2743
2744                 if (previous_child)
2745                 {
2746                     DTB_GROUP_TYPES     group_type = group_info->group_type;
2747                     int                 offset = group_info->voffset;
2748     
2749                     if (group_type == DTB_GROUP_ROWSCOLUMNS)
2750                     {
2751                         Dimension       height = 0;
2752
2753                         XtVaGetValues(previous_child, XmNheight, &height, NULL);
2754
2755                         offset += (cell_height - (int)(height));
2756                     }
2757
2758                     XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET);       n++;
2759                     XtSetArg(args[n], XmNtopWidget, previous_child);            n++;
2760                     XtSetArg(args[n], XmNtopOffset, offset);                    n++;
2761                     XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE);      n++;
2762
2763                     XtSetValues(child, args, n);
2764                 }
2765                 continue;
2766             }
2767
2768             previous_child = get_group_child(parent, group_info, i-1, j);
2769
2770             if (previous_child)
2771             {
2772                 XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET);  n++;
2773                 XtSetArg(args[n], XmNtopWidget, previous_child);                n++;
2774                 XtSetArg(args[n], XmNtopOffset, 0);                             n++;
2775                 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE);          n++;
2776
2777                 XtSetValues(child, args, n);
2778             }
2779
2780         }
2781     }
2782 }
2783
2784
2785 static void
2786 align_bottom(
2787     Widget              parent,
2788     DtbGroupInfo        *group_info
2789 )
2790 {
2791     WidgetList  children_list;
2792     Widget      child, 
2793                 previous_child;
2794     int         num_children = 0,
2795                 num_columns,
2796                 num_rows,
2797                 cell_height,
2798                 cell_width,
2799                 offset,
2800                 i,
2801                 j;
2802   
2803     if (!parent || !group_info)
2804         return;
2805
2806     /*
2807      * Get children list
2808      */
2809     XtVaGetValues(parent,
2810             XmNnumChildren, &num_children,
2811             XmNchildren, &children_list,
2812             NULL);
2813
2814     if (num_children <= 0)
2815         return;
2816     
2817     get_group_cell_size(parent, group_info, &cell_width, &cell_height);
2818     get_group_row_col(parent, group_info, &num_rows, &num_columns);
2819
2820     for (j = 0; j < num_rows; j++)
2821     {
2822         for (i = 0; i < num_columns; i++)
2823         {
2824             Arg         args[12];
2825             int         n = 0;
2826
2827             child = get_group_child(parent, group_info, i, j);
2828
2829             if (!child)
2830                 continue;
2831
2832             if ((i == 0) && (j == 0))
2833             {
2834                 Dimension       height = 0;
2835
2836                 XtVaGetValues(child, XmNheight, &height, NULL);
2837
2838                 offset = cell_height - height;
2839
2840                 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM);     n++;
2841                 XtSetArg(args[n], XmNtopOffset, offset);                n++;
2842                 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE);  n++;
2843
2844                 XtSetValues(child, args, n);
2845
2846                 continue;
2847             }
2848
2849             if (i == 0)
2850             {
2851                 previous_child = get_group_child(parent, group_info, 0, j-1);
2852
2853                 if (previous_child)
2854                 {
2855                     Dimension   height = 0;
2856
2857                     XtVaGetValues(child, XmNheight, &height, NULL);
2858
2859                     offset = group_info->voffset;
2860
2861                     if (group_info->group_type == DTB_GROUP_ROWSCOLUMNS)
2862                         offset += (cell_height - height);
2863
2864                     XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET);       n++;
2865                     XtSetArg(args[n], XmNtopWidget, previous_child);            n++;
2866                     XtSetArg(args[n], XmNtopOffset, offset);                    n++;
2867                     XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE);      n++;
2868
2869                     XtSetValues(child, args, n);
2870                 }
2871                 continue;
2872             }
2873
2874             previous_child = get_group_child(parent, group_info, i-1, j);
2875
2876             if (child && previous_child)
2877             {
2878                 XtSetArg(args[n], XmNbottomAttachment, 
2879                                 XmATTACH_OPPOSITE_WIDGET);              n++;
2880                 XtSetArg(args[n], XmNbottomWidget, previous_child);     n++;
2881                 XtSetArg(args[n], XmNbottomOffset, 0);                  n++;
2882                 XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE);     n++;
2883
2884                 XtSetValues(child, args, n);
2885             }
2886         }
2887     }
2888 }
2889
2890
2891 static void
2892 align_hcenter(
2893     Widget              parent,
2894     DtbGroupInfo        *group_info,
2895     Bool                init
2896 )
2897 {
2898     WidgetList  children_list = NULL;
2899     Widget      child;
2900     DTB_GROUP_TYPES group_type;
2901     int         num_children = 0,
2902                 num_columns,
2903                 num_rows,
2904                 cell_width,
2905                 cell_height,
2906                 group_height,
2907                 offset,
2908                 gridline,
2909                 i,
2910                 j;
2911   
2912     if (!parent || !group_info)
2913         return;
2914
2915     /*
2916      * Get children list
2917      */
2918     XtVaGetValues(parent,
2919             XmNnumChildren, &num_children,
2920             XmNchildren, &children_list,
2921             NULL);
2922
2923     if (num_children <= 0)
2924         return;
2925     
2926     group_type = group_info->group_type;
2927
2928     get_group_cell_size(parent, group_info, &cell_width, &cell_height);
2929     get_group_row_col(parent, group_info, &num_rows, &num_columns);
2930
2931     offset = group_info->voffset;
2932
2933     if (group_type == DTB_GROUP_ROWSCOLUMNS)
2934     {
2935         group_height = (num_rows * cell_height) + ((num_rows-1) * offset);
2936     }
2937
2938     for (j = 0; j < num_rows; j++)
2939     {
2940         if (group_type == DTB_GROUP_ROWSCOLUMNS)
2941             gridline = 
2942                 (((j * (cell_height + offset)) + (cell_height/2)) * 100)/group_height;
2943         else
2944             gridline = 50;
2945
2946         for (i = 0; i < num_columns; i++)
2947         {
2948             Arg         args[12];
2949             int         n = 0;
2950             Dimension   height = 0;
2951
2952             child = get_group_child(parent, group_info, i, j);
2953
2954             if (!child)
2955                 continue;
2956
2957             XtVaGetValues(child, XmNheight, &height, NULL);
2958
2959             if (init)
2960             {
2961                 int     init_offset = 0;
2962
2963                 if (!XtIsSubclass(child, compositeWidgetClass))
2964                 {
2965                     init_offset = (cell_height - (int)height)/2;
2966
2967                     if (group_type == DTB_GROUP_ROWSCOLUMNS)
2968                     init_offset += (j * (cell_height + group_info->voffset));
2969                 }
2970
2971                 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM);     n++;
2972                 XtSetArg(args[n], XmNtopOffset, init_offset);           n++;
2973                 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE);  n++;
2974             }
2975             else
2976             {
2977                 XtSetArg(args[n], XmNtopAttachment, 
2978                                 XmATTACH_POSITION);                     n++;
2979                 XtSetArg(args[n], XmNtopPosition, gridline);            n++;
2980                 XtSetArg(args[n], XmNtopOffset, (int)(-(height/2)));    n++;
2981                 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE);  n++;
2982             }
2983
2984             XtSetValues(child, args, n);
2985         }
2986     }
2987 }
2988
2989
2990 /*
2991  * Returns the directory that the executable for this process was loaded 
2992  * from.
2993  */
2994 String
2995 dtb_get_exe_dir(void)
2996 {
2997     return dtb_exe_dir;
2998 }
2999
3000
3001 /*
3002  * Determines the directory the executable for this process was loaded from.
3003  */
3004 static int 
3005 determine_exe_dir(
3006     char        *argv0,
3007     char        *buf,
3008     int         bufSize
3009 )
3010 {
3011     Boolean     foundDir= False;
3012
3013     if ((buf == NULL) || (bufSize < 1))
3014     {
3015         return -1;
3016     }
3017     
3018     if (determine_exe_dir_from_argv(argv0, buf, bufSize) >= 0)
3019     {
3020         foundDir = True;
3021     }
3022
3023     if (!foundDir)
3024     {
3025         if (determine_exe_dir_from_path(argv0, buf, bufSize) >= 0)
3026         {
3027             foundDir = True;
3028         }
3029     }
3030
3031     /*
3032      * Convert relative path to absolute, so that directory changes will
3033      * not affect us.
3034      */
3035     if (foundDir && (buf[0] != '/'))
3036     {
3037         char    cwd[MAXPATHLEN+1];
3038         char    *env_pwd = NULL;
3039         char    *path_prefix = NULL;
3040
3041         if (getcwd(cwd, MAXPATHLEN+1) != NULL)
3042         {
3043             path_prefix = cwd;
3044         }
3045         else
3046         {
3047             env_pwd = getenv("PWD");
3048             if (env_pwd != NULL)
3049             {
3050                 path_prefix = env_pwd;
3051             }
3052         }
3053
3054         if (path_prefix != NULL)
3055         {
3056             char *abs_exe_dir = new char[MAXPATHLEN+1];
3057             strcpy(abs_exe_dir, path_prefix);
3058             if (strcmp(buf, ".") != 0)
3059             {
3060                 strcat(abs_exe_dir, "/");
3061                 strcat(abs_exe_dir, buf);
3062             }
3063             strcpy(buf, abs_exe_dir);
3064             delete [] abs_exe_dir;
3065         }
3066     }
3067
3068     return foundDir? 0:-1;
3069 }
3070
3071
3072 /*
3073  *  Looks for absolute path in arv[0].
3074  */
3075 static int
3076 determine_exe_dir_from_argv(
3077     char        *argv0,
3078     char        *buf,
3079     int         bufSize
3080 )
3081 {
3082     int         i= 0;
3083     Boolean     foundit= False;
3084
3085     for (i= strlen(argv0)-1; (i >= 0) && (argv0[i] != '/'); --i)
3086     {
3087     }
3088
3089     if (i >= 0)
3090     {
3091         int     maxStringSize= min(i, bufSize);
3092         strncpy(buf, argv0, maxStringSize);
3093         buf[min(maxStringSize, bufSize-1)]= 0;
3094         foundit = True;
3095     }
3096
3097     return foundit? 0:-1;
3098 }
3099
3100
3101 /*
3102  * Assumes: bufSize > 0
3103  */
3104 static int
3105 determine_exe_dir_from_path (
3106     char        *argv0,
3107     char        *buf,
3108     int         bufSize
3109 )
3110 {
3111     Boolean     foundDir= False;
3112     Boolean     moreDirs= True;
3113     char        *szExeName= argv0;
3114     int         iExeNameLen= strlen(szExeName);
3115     char        *szTemp= NULL;
3116     char        *szPathVar = new char[MAXPATHLEN+1];
3117     int         iPathVarLen= 0;
3118     char        *szCurrentPath = new char[MAXPATHLEN+1];
3119     int         iCurrentPathLen= 0;
3120     int         iCurrentPathStart= 0;
3121     int         i = 0;
3122     uid_t       euid= geteuid();
3123     uid_t       egid= getegid();
3124
3125     szTemp= getenv("PATH");
3126     if (szTemp == NULL)
3127     {
3128         moreDirs= False;
3129     }
3130     else
3131     {
3132         strncpy(szPathVar, szTemp, MAXPATHLEN);
3133         szPathVar[MAXPATHLEN]= 0;
3134         iPathVarLen= strlen(szPathVar);
3135     }
3136
3137     while ((!foundDir) && (moreDirs))
3138     {
3139         /* find the current directory name */
3140         for (i= iCurrentPathStart; (i < iPathVarLen) && (szPathVar[i] != ':'); 
3141             )
3142         {
3143             ++i;
3144         }
3145         iCurrentPathLen= i - iCurrentPathStart;
3146         if ((iCurrentPathLen + iExeNameLen + 2) > MAXPATHLEN)
3147         {
3148             iCurrentPathLen= MAXPATHLEN - (iExeNameLen + 2);
3149         }
3150
3151         /* create a possible path to the executable */
3152         strncpy(szCurrentPath, &szPathVar[iCurrentPathStart], iCurrentPathLen);
3153         szCurrentPath[iCurrentPathLen]= 0;
3154         strcat(szCurrentPath, "/");
3155         strcat(szCurrentPath, szExeName);
3156
3157         /* see if the executable exists (and we can execute it) */
3158         if (path_is_executable(szCurrentPath, euid, egid))
3159         {
3160             foundDir= True;
3161         }
3162
3163         /* skip past the current directory name */
3164         if (!foundDir)
3165         {
3166             iCurrentPathStart+= iCurrentPathLen;
3167             while (   (iCurrentPathStart < iPathVarLen) 
3168                    && (szPathVar[iCurrentPathStart] != ':') )
3169             {
3170                 ++iCurrentPathStart;    /* find : */
3171             }
3172             if (iCurrentPathStart < iPathVarLen) 
3173             {
3174                 ++iCurrentPathStart;    /* skip : */
3175             }
3176             if (iCurrentPathStart >= iPathVarLen)
3177             {
3178                 moreDirs= False;
3179             }
3180         }
3181     } /* while !foundDir */
3182
3183     if (foundDir)
3184     {
3185         szCurrentPath[iCurrentPathLen]= 0;
3186         strncpy(buf, szCurrentPath, bufSize);
3187         buf[bufSize-1]= 0;
3188     }
3189     delete [] szPathVar;
3190     delete [] szCurrentPath;
3191     return foundDir? 0:-1;
3192 }
3193
3194
3195 /*
3196  * returns False is path does not exist or is not executable
3197  */
3198 static Boolean
3199 path_is_executable(
3200     char        *path,
3201     uid_t       euid,
3202     gid_t       egid
3203 )
3204 {
3205     Boolean     bExecutable= False;
3206     struct stat sStat;
3207
3208     if (stat(path, &sStat) == 0)
3209     {
3210         Boolean bDetermined= False;
3211
3212         if (!bDetermined)
3213         {
3214             if (!S_ISREG(sStat.st_mode))
3215             {
3216                 /* not a regular file */
3217                 bDetermined= True;
3218                 bExecutable= False;
3219             }
3220         }
3221
3222         if (!bDetermined)
3223         {
3224             if (   (euid == 0) 
3225                 && (   ((sStat.st_mode & S_IXOTH) != 0)
3226                     || ((sStat.st_mode & S_IXGRP) != 0)
3227                     || ((sStat.st_mode & S_IXUSR) != 0) )
3228                )
3229             {
3230                 bDetermined= True;
3231                 bExecutable= True;
3232             }
3233         }
3234
3235         if (!bDetermined)
3236         {
3237             if (   (((sStat.st_mode & S_IXOTH) != 0)    )
3238                 || (((sStat.st_mode & S_IXGRP) != 0) && (sStat.st_gid == egid))
3239                 || (((sStat.st_mode & S_IXUSR) != 0) && (sStat.st_gid == euid))
3240                )
3241             {
3242                 bDetermined= True;
3243                 bExecutable= True;
3244             }
3245         }
3246     } /* if stat */
3247
3248     return bExecutable;
3249 }
3250
3251