Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtappbuilder / src / ab / ui_util.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
24 /*
25  *      $XConsortium: ui_util.c /main/3 1995/11/06 17:56:30 rswiston $
26  *
27  * @(#)ui_util.c        1.38 14 Feb 1994      cde_app_builder/src/ab
28  *
29  *      RESTRICTED CONFIDENTIAL INFORMATION:
30  *
31  *      The information in this document is subject to special
32  *      restrictions in a confidential disclosure agreement between
33  *      HP, IBM, Sun, USL, SCO and Univel.  Do not distribute this
34  *      document outside HP, IBM, Sun, USL, SCO, or Univel without
35  *      Sun's specific written approval.  This document and all copies
36  *      and derivative works thereof must be returned or destroyed at
37  *      Sun's request.
38  *
39  *      Copyright 1993 Sun Microsystems, Inc.  All rights reserved.
40  *
41  */
42
43
44 /*
45  ***********************************************************************
46  * ui_util.c - User-Interface support functions
47  *      
48  *
49  ***********************************************************************
50  */
51 #ifndef _POSIX_SOURCE   /* POSIX guarantees portability of time functions */
52 #define _POSIX_SOURCE 1
53 #endif
54
55 #include <unistd.h>
56 #include <stdlib.h>
57 #include <stdio.h>
58 #include <time.h>
59 #include <X11/Intrinsic.h>
60 #include <X11/Composite.h>
61 #include <X11/Shell.h>
62 #include <X11/cursorfont.h>
63 #include <Xm/XmAll.h>
64 /*
65 #include <Xm/Protocols.h>
66 #include <Xm/CascadeB.h>
67 #include <Xm/DialogS.h>
68 #include <Xm/Form.h>
69 #include <Xm/List.h>
70 #include <Xm/ScrolledW.h>
71 #include <Xm/RowColumn.h>
72 #include <Xm/TextF.h>
73 #include <Xm/Text.h>
74 #include <Xm/MessageB.h>
75 #include <Xm/PushB.h>
76 */
77 #include <Dt/SpinBox.h>
78 #include <Dt/TermPrim.h>
79 #include <Dt/Term.h>
80 #include <ab_private/XmAll.h>
81 #include <ab_private/x_util.h>
82 #include <ab_private/ui_util.h>
83 #include <ab_private/objxm.h>
84 #include <ab_private/ab.h>
85 #include <Dt/xpm.h>             /* will this be in include/Dt? */
86 #include "dtbuilder.h"
87 #include "dtb_utils.h"
88
89 extern Widget   AB_toplevel;
90
91 typedef struct
92 {
93     XtIntervalId        timerId;
94     BOOL                synced;
95     time_t              start_time;
96     long                timeout_ticks;
97     time_t              last_expose_ticks;
98     Display             *display;
99     Window              window;
100 } SyncDataRec, *SyncData;
101
102
103 /*************************************************************************
104 **                                                                      **
105 **       Private Function Declarations                                  **
106 **                                                                      **
107 **************************************************************************/
108 static void     init_obj_pixmaps();
109
110 static void     rubberband_finish(
111                     Widget      widget,
112                     XEvent      *event,
113                     XtPointer   client_data
114                 );
115
116 static void     rubberband_release(
117                     Widget widget,
118                     XtPointer client_data,
119                     XEvent *event,
120                     Boolean *cont_dispatch
121                 );
122
123 static void     rubberband_draw(
124                     Widget      widget,
125                     XEvent      *event,
126                     XtPointer   client_data
127                 );
128
129 /*************************************************************************
130 **                                                                      **
131 **       Data                                                           **
132 **                                                                      **
133 **************************************************************************/
134
135 static const long sync_notify_value = (long)0x45a55a54;
136
137
138 /*
139  * Array that maps from:
140  *      (obj type, obj subtype) -> pixmap
141  * It contains the data that will be used to create the pixmap.
142  */
143 static UiObjPixmap      object_pixmaps[] = 
144 {
145     /* { (AB_OBJECT_TYPE), (int), (char *), (Pixmap), u_int, u_int } */
146     {AB_TYPE_MODULE, AB_NO_SUBTYPE, "DtABmdl", (Pixmap)NULL, 0, 0},
147
148     {AB_TYPE_BASE_WINDOW, AB_NO_SUBTYPE, "DtABbw2", (Pixmap)NULL, 0, 0},
149
150     {AB_TYPE_DIALOG, AB_NO_SUBTYPE, "DtABpuw2", (Pixmap)NULL, 0, 0},
151
152     {AB_TYPE_FILE_CHOOSER, AB_NO_SUBTYPE, "DtABfsb2", (Pixmap)NULL, 0, 0},
153
154     {AB_TYPE_CONTAINER, AB_CONT_BUTTON_PANEL, "DtABcnt2", (Pixmap)NULL, 0, 0},
155     {AB_TYPE_CONTAINER, AB_CONT_ABSOLUTE, "DtABcnt2", (Pixmap)NULL, 0, 0},
156     {AB_TYPE_CONTAINER, AB_CONT_RELATIVE, "DtABcnt2", (Pixmap)NULL, 0, 0},
157     {AB_TYPE_CONTAINER, AB_CONT_PANED, "DtABpnw", (Pixmap)NULL, 0, 0},
158     {AB_TYPE_CONTAINER, AB_CONT_MENU_BAR, "DtABmbr", (Pixmap)NULL, 0, 0},
159     {AB_TYPE_CONTAINER, AB_CONT_TOOL_BAR, "DtABcnt2", (Pixmap)NULL, 0, 0},
160     {AB_TYPE_CONTAINER, AB_CONT_FOOTER, "DtABcnt2", (Pixmap)NULL, 0, 0},
161     {AB_TYPE_CONTAINER, AB_CONT_GROUP, "DtABgrp", (Pixmap)NULL, 0, 0},
162
163     {AB_TYPE_DRAWING_AREA, AB_NO_SUBTYPE, "DtABdrw2", (Pixmap)NULL, 0, 0},
164
165     {AB_TYPE_TEXT_PANE, AB_NO_SUBTYPE, "DtABtxp2", (Pixmap)NULL, 0, 0},
166
167     {AB_TYPE_BUTTON, AB_BUT_PUSH, "DtABbtn", (Pixmap)NULL, 0, 0},
168     {AB_TYPE_BUTTON, AB_BUT_DRAWN, "DtABbtn", (Pixmap)NULL, 0, 0},
169     {AB_TYPE_BUTTON, AB_BUT_MENU, "DtABmbt", (Pixmap)NULL, 0, 0},
170
171     {AB_TYPE_LIST, AB_NO_SUBTYPE, "DtABlst", (Pixmap)NULL, 0, 0},
172
173     {AB_TYPE_CHOICE, AB_CHOICE_OPTION_MENU, "DtABopm", (Pixmap)NULL, 0, 0},
174     {AB_TYPE_CHOICE, AB_CHOICE_EXCLUSIVE, "DtABrad", (Pixmap)NULL, 0, 0},
175     {AB_TYPE_CHOICE, AB_CHOICE_NONEXCLUSIVE, "DtABchk", (Pixmap)NULL, 0, 0},
176
177     {AB_TYPE_ITEM, AB_ITEM_FOR_MENU, "DtABcas", (Pixmap)NULL, 0, 0},
178     {AB_TYPE_ITEM, AB_ITEM_FOR_MENUBAR, "DtABcas", (Pixmap)NULL, 0, 0},
179     {AB_TYPE_ITEM, AB_ITEM_FOR_CHOICE, "DtABitm", (Pixmap)NULL, 0, 0},
180     {AB_TYPE_ITEM, AB_ITEM_FOR_LIST, "DtABitm", (Pixmap)NULL, 0, 0},
181     {AB_TYPE_ITEM, AB_ITEM_FOR_COMBO_BOX, "DtABitm", (Pixmap)NULL, 0, 0},
182     {AB_TYPE_ITEM, AB_ITEM_FOR_SPIN_BOX, "DtABitm", (Pixmap)NULL, 0, 0},
183
184     {AB_TYPE_TEXT_FIELD, AB_NO_SUBTYPE, "DtABtxf", (Pixmap)NULL, 0, 0},
185
186     {AB_TYPE_MENU, AB_MENU_PULLDOWN, "DtABpum", (Pixmap)NULL, 0, 0},
187     {AB_TYPE_SCALE, AB_SCALE_SCALE, "DtABsld", (Pixmap)NULL, 0, 0},
188     {AB_TYPE_SCALE, AB_SCALE_GAUGE, "DtABgau", (Pixmap)NULL, 0, 0}, 
189     {AB_TYPE_COMBO_BOX, AB_NO_SUBTYPE, "DtABcmb", (Pixmap)NULL, 0, 0},
190     {AB_TYPE_SPIN_BOX, AB_NO_SUBTYPE, "DtABspb", (Pixmap)NULL, 0, 0},
191     {AB_TYPE_TERM_PANE, AB_NO_SUBTYPE, "DtABtmp2", (Pixmap)NULL, 0, 0},
192     {AB_TYPE_SEPARATOR, AB_NO_SUBTYPE, "DtABsep", (Pixmap)NULL, 0, 0},
193     {AB_TYPE_LABEL, AB_NO_SUBTYPE, "DtABlbl", (Pixmap)NULL, 0, 0},
194
195     {AB_TYPE_MESSAGE, AB_MSG_ERROR, "DtABmbx", (Pixmap)NULL, 0, 0},
196     {AB_TYPE_MESSAGE, AB_MSG_INFORMATION, "DtABmbx", (Pixmap)NULL, 0, 0},
197     {AB_TYPE_MESSAGE, AB_MSG_QUESTION, "DtABmbx", (Pixmap)NULL, 0, 0},
198     {AB_TYPE_MESSAGE, AB_MSG_WARNING, "DtABmbx", (Pixmap)NULL, 0, 0},
199     {AB_TYPE_MESSAGE, AB_MSG_WORKING, "DtABmbx", (Pixmap)NULL, 0, 0},
200
201     {AB_TYPE_LAYERS, AB_NO_SUBTYPE, "DtABlyr", (Pixmap)NULL, 0, 0},
202
203     /* The last entry has to be this !!*/
204     {AB_TYPE_UNKNOWN, AB_NO_SUBTYPE, (char *)NULL, (Pixmap)NULL, 0, 0},
205 };
206
207 /*
208  * Default pixmap
209  */
210 static  Pixmap          default_pixmap = NULL;
211 static  unsigned int    default_pixmap_width = 0;
212 static  unsigned int    default_pixmap_height = 0;
213
214 /*
215  * State variables for rubber banding
216  */
217 static Boolean          rband_in_progress= False;
218 static Boolean          just_rbanded      = False;
219 static XRectangle       rb_rect;
220 static Widget           rb_widget = NULL;
221 static BOOL             rb_first_time = TRUE;
222 static UiRubberBandFunc rubberband_func = NULL;
223
224 /*************************************************************************
225 **                                                                      **
226 **       Function Definitions                                           **
227 **                                                                      **
228 **************************************************************************/
229 void
230 ui_win_front(
231     Widget widget
232 )
233 {
234     Widget p_shell;
235
236     if (widget == NULL)
237         return;
238
239     p_shell = ui_get_ancestor_shell(widget);
240
241     if (XtIsRealized(p_shell))
242         XRaiseWindow(XtDisplay(p_shell),XtWindow(p_shell));
243     else
244         if (util_get_verbosity() > 0)
245             fprintf(stderr,"ui_win_front: widget not realized\n");
246
247 }
248
249 void
250 ui_win_show(
251     Widget      widget,
252     BOOL        show,
253     XtGrabKind  grab_kind
254 )
255 {
256     Widget      shell;
257     Widget      dialog;
258
259     shell = ui_get_ancestor_shell(widget);
260
261     if (show)
262         XtPopup(shell, grab_kind);
263     else
264         XtPopdown(shell);
265 }
266
267 void
268 ui_win_set_resizable(
269     Widget      widget,
270     BOOL        resizable,
271     BOOL        remap
272 )
273 {
274     Widget      shell;
275     int         decor = 0;
276     int         new_decor = 0;
277     int         func = 0;
278     int         new_func = 0;
279
280     shell = ui_get_ancestor_shell(widget);
281
282     XtVaGetValues(shell, 
283         XmNmwmDecorations, &decor, 
284         XmNmwmFunctions,   &func,
285         NULL);
286
287     if (func & MWM_FUNC_ALL)
288     {
289         new_func |= MWM_FUNC_ALL;
290         if (!resizable)
291             new_func |= MWM_FUNC_RESIZE;
292     }
293     else
294     {
295         new_func = func;
296         if (resizable && !(func & MWM_FUNC_RESIZE))
297             new_func |= MWM_FUNC_RESIZE;
298         else if (!resizable && (func & MWM_FUNC_RESIZE))
299             new_func &= ~MWM_FUNC_RESIZE;
300     }
301
302     if (decor & MWM_DECOR_ALL)
303     {
304         new_decor |= MWM_DECOR_ALL;
305         if (!resizable)
306             new_decor |= MWM_DECOR_RESIZEH;
307     }
308     else
309     {
310         new_decor = decor;
311         if (resizable && !(decor & MWM_DECOR_RESIZEH))
312             new_decor |= MWM_DECOR_RESIZEH;
313         else if (!resizable && (decor & MWM_DECOR_RESIZEH)) 
314             new_decor &= ~MWM_DECOR_RESIZEH; 
315     }
316
317     if (new_func != func || new_decor != decor)
318     {
319         /* If requested, unmap & remap the window.
320          * Unfortunately, this is the only way to get the window
321          * manager to change the decorations for an already mapped
322          * window.
323          */
324         if (remap)
325             XtPopdown(shell);
326
327         XtVaSetValues(shell, 
328                 XmNmwmDecorations, new_decor, 
329                 XmNmwmFunctions,   new_func,
330                 NULL);
331
332         if (remap)
333             XtPopup(shell, XtGrabNone);
334     }
335 }
336             
337 void
338 ui_field_set_string(
339     Widget      field,
340     STRING      valuestr
341 )
342 {
343
344     XtVaSetValues(field,
345         XmNvalue,           (XtArgVal)(valuestr? valuestr : ""),
346         XmNcursorPosition,  (XtArgVal)valuestr? strlen(valuestr) : 0,
347         NULL);
348
349 }
350
351 STRING
352 ui_field_get_string(
353     Widget   field
354 )
355 {
356      char *string = NULL;
357
358      if (XtIsSubclass(field, xmTextFieldWidgetClass))
359         string = XmTextFieldGetString(field);
360      else if (XtIsSubclass(field, xmTextWidgetClass))
361         string = XmTextGetString(field);
362
363      return((STRING)string);
364 }
365
366 void
367 ui_field_select_string(
368     Widget      field,
369     BOOL        assign_focus
370 )
371 {
372     STRING      valuestr = NULL;
373
374     valuestr = ui_field_get_string(field);
375
376     if (XtIsSubclass(field, xmTextFieldWidgetClass))
377         XmTextFieldSetSelection(field, 0, strlen(valuestr), CurrentTime);
378     else if (XtIsSubclass(field, xmTextWidgetClass))
379         XmTextSetSelection(field, 0, strlen(valuestr), CurrentTime);
380
381     if (assign_focus) 
382         XmProcessTraversal(field, XmTRAVERSE_CURRENT);
383
384     util_free(valuestr);
385 }
386
387 void
388 ui_field_set_editable(
389     Widget      field,
390     BOOL        editable
391 )
392 {
393     XtVaSetValues(field,
394                 XmNeditable,              editable,
395                 XmNcursorPositionVisible, editable,
396                 NULL);
397 }
398
399 void
400 ui_set_active(
401     Widget      widget,
402     BOOL        state
403 )
404 {
405     XtSetSensitive(widget, (Boolean)state);
406
407     if (XtIsComposite(widget))
408     {
409         int i, num_children = 0;
410         WidgetList children = NULL;
411
412         XtVaGetValues(widget, 
413                 XmNnumChildren, &num_children,
414                 XmNchildren,    &children,
415                 NULL);
416
417         for (i = 0; i < num_children; i++)
418         {
419             int c = 0, num_children_children = 0;
420             WidgetList children_children = NULL;
421
422             XtSetSensitive(children[i], (Boolean)state);
423
424             /* REMIND: Hack to get scrolling list to grey out */
425
426             XtVaGetValues(children[i],
427                 XmNnumChildren, &num_children_children,
428                 XmNchildren,    &children_children,
429                 NULL);
430
431             if (num_children_children > 0)
432             {
433                 for (c = 0; c < num_children_children; c++)
434                     XtSetSensitive(children_children[c], (Boolean)state);
435             }
436         }
437     }
438 }
439
440 void
441 ui_set_visible(
442     Widget      widget,
443     BOOL        viz
444 )
445 {
446     if (viz == TRUE && !XtIsManaged(widget))
447         XtManageChild(widget);
448
449     else if (viz == FALSE && XtIsManaged(widget))
450         XtUnmanageChild(widget);
451
452 }
453
454 void
455 ui_set_label_string(
456     Widget      widget,
457     STRING      string
458 )
459 {
460     XmString    xmlabel;
461
462     xmlabel = XmStringCreateLocalized(string);
463
464     XtVaSetValues(widget, XmNlabelString, xmlabel, NULL);
465  
466     XmStringFree(xmlabel);
467 }
468
469 void
470 ui_set_label_glyph(
471     Widget      widget,
472     STRING      fileName
473 )
474 {
475     Pixmap    labelPixmap            = NULL;
476     Pixmap    labelInsensitivePixmap = NULL;
477     
478     XtVaGetValues(widget,
479         XmNlabelPixmap,            &labelPixmap,
480         XmNlabelInsensitivePixmap, &labelInsensitivePixmap,
481         NULL);
482
483     if (dtb_set_label_from_image_file(widget, fileName) < 0)
484         return;
485     
486     /* sucess, destroy the old pixmaps */
487     if (labelPixmap)
488         XmDestroyPixmap(XtScreen(widget), labelPixmap);
489
490     if (labelInsensitivePixmap)
491         XmDestroyPixmap(XtScreen(widget), labelInsensitivePixmap);
492 }
493
494
495 Widget
496 ui_get_ancestor_shell(
497     Widget      widget
498 )
499 {
500     Widget shell = widget;
501
502     while(shell && !XtIsSubclass(shell, shellWidgetClass))
503         shell = XtParent(shell);
504
505     return shell;
506
507 }
508
509 Widget
510 ui_get_ancestor_dialog(
511     Widget      widget
512 )
513 {
514     Widget dialog = widget;
515
516     while(dialog && !XtIsSubclass(XtParent(dialog), shellWidgetClass))
517         dialog = XtParent(dialog);
518
519     return dialog;
520 }
521
522 Widget
523 ui_build_menu(
524         Widget          parent,
525         int             menu_type,
526         int             num_columns,
527         char            *menu_title,
528         char            *menu_name,
529         MenuItem        *menu_items
530 )
531 {
532     Widget      menu,
533                 cascade,
534                 widget;
535     Arg         args[4];
536     int         i;
537     XmString    xmlabel;
538     int         n = 0;
539
540     if (num_columns > 1)
541     {
542         XtSetArg(args[n], XmNpacking, XmPACK_COLUMN);    n++;
543         XtSetArg(args[n], XmNnumColumns, num_columns);   n++;
544     }
545     if (menu_type == XmMENU_PULLDOWN)
546         menu = XmCreatePulldownMenu(parent, "pulldown_menu", args, n);
547     else
548     {
549         XtSetArg(args[n], XmNwhichButton, AB_BMenu); n++;
550         menu = XmCreatePopupMenu(parent, "popup_menu", args, n);
551     }
552
553     if (menu_type == XmMENU_PULLDOWN)
554     {
555         cascade = XtVaCreateManagedWidget(menu_name,
556                         xmCascadeButtonWidgetClass, parent,
557                         XmNsubMenuId,   menu,
558                         NULL);
559
560         if (menu_title)
561         {
562             xmlabel = XmStringCreateLocalized(menu_title);
563             XtVaSetValues(cascade, XmNlabelString, xmlabel, NULL);
564             XmStringFree(xmlabel);
565         }
566     }
567
568     for (i = 0; menu_items[i].label != NULL; i++)
569     {
570         if (menu_items[i].subitems)
571         {
572             widget = ui_build_menu(menu, XmMENU_PULLDOWN, 
573                                        menu_items[i].num_columns,
574                                        menu_items[i].label, 
575                                        menu_items[i].name,
576                                        (MenuItem *)menu_items[i].subitems);
577
578             XtVaSetValues(widget, XmNuserData, (XtArgVal)menu_items[i].user_data, NULL);
579         }
580         else
581         {
582             widget = XtVaCreateManagedWidget(menu_items[i].name,
583                                  *menu_items[i].wclass, 
584                                   menu, 
585                                   XmNuserData,    (XtArgVal)menu_items[i].user_data,
586                                   NULL);
587
588             if (menu_items[i].label != NULL)
589             {
590                 xmlabel = XmStringCreateLocalized(menu_items[i].label);
591                 XtVaSetValues(widget, XmNlabelString, xmlabel, NULL);
592                 XmStringFree(xmlabel);
593             }
594         
595             /* If label is glyph type, then change type and call
596              * routine to set glyph.
597              */
598             if (menu_items[i].label_type == AB_LABEL_GLYPH)
599             {
600                 XtVaSetValues(widget, XmNlabelType, XmPIXMAP, NULL);
601                 dtb_set_label_from_bitmap_data(widget,
602                                 menu_items[i].pixwidth,
603                                 menu_items[i].pixheight,
604                                 menu_items[i].bits);
605
606             }
607         }
608
609         if (menu_items[i].active == FALSE)
610             XtSetSensitive(widget, FALSE);
611         else if (menu_items[i].callback != NULL)
612             XtAddCallback(widget, XmNactivateCallback, 
613                                 menu_items[i].callback, 
614                                 menu_items[i].client_data);
615    }
616
617    if (menu_type == XmMENU_POPUP)
618         return menu;
619    else
620         return cascade;
621 }
622
623 void
624 ui_populate_pulldown_menu(
625         Widget          menu,
626         int             num_columns,
627         MenuItem        *menu_items
628 )
629 {
630     Widget      widget;
631     Arg         args[4];
632     int         i;
633     XmString    xmlabel;
634     int         n = 0;
635
636     if (!menu)
637         return;
638
639     if (num_columns > 1)
640     {
641         XtSetArg(args[n], XmNpacking, XmPACK_COLUMN);    n++;
642         XtSetArg(args[n], XmNnumColumns, num_columns);   n++;
643
644         XtSetValues(menu, args, n);
645     }
646
647     for (i = 0; menu_items[i].label != NULL; i++)
648     {
649         if (menu_items[i].subitems)
650         {
651             widget = ui_build_menu(menu, XmMENU_PULLDOWN, 
652                                        menu_items[i].num_columns,
653                                        menu_items[i].label, 
654                                        menu_items[i].name,
655                                        (MenuItem *)menu_items[i].subitems);
656
657             XtVaSetValues(widget, XmNuserData, (XtArgVal)menu_items[i].user_data, NULL);
658         }
659         else
660         {
661             widget = XtVaCreateManagedWidget(menu_items[i].name,
662                                  *menu_items[i].wclass, 
663                                   menu, 
664                                   XmNuserData,    (XtArgVal)menu_items[i].user_data,
665                                   NULL);
666
667             if (menu_items[i].label != NULL)
668             {
669                 xmlabel = XmStringCreateLocalized(menu_items[i].label);
670                 XtVaSetValues(widget, XmNlabelString, xmlabel, NULL);
671                 XmStringFree(xmlabel);
672             }
673         
674             /* If label is glyph type, then change type and call
675              * routine to set glyph.
676              */
677             if (menu_items[i].label_type == AB_LABEL_GLYPH)
678             {
679                 XtVaSetValues(widget, XmNlabelType, XmPIXMAP, NULL);
680                 dtb_set_label_from_bitmap_data(widget,
681                                 menu_items[i].pixwidth,
682                                 menu_items[i].pixheight,
683                                 menu_items[i].bits);
684
685             }
686         }
687
688         if (menu_items[i].active == FALSE)
689             XtSetSensitive(widget, FALSE);
690         else if (menu_items[i].callback != NULL)
691             XtAddCallback(widget, XmNactivateCallback, 
692                                 menu_items[i].callback, 
693                                 menu_items[i].client_data);
694    }
695
696 }
697
698
699 void
700 ui_size_to_row_col(
701     Widget         text,
702     unsigned short width,
703     unsigned short height,
704     int            *row_ptr,
705     int            *col_ptr
706 )
707 {
708
709     Widget      parent;
710     Widget      vsb, hsb;
711     Dimension   spacing    = 0;
712     Dimension   text_spacing = 0;
713     Dimension   hsb_height = 0;
714     Dimension   vsb_width  = 0;
715     Dimension   margin_w = 0;
716     Dimension   margin_h = 0;
717     Dimension   p_margin_w = 0;
718     Dimension   p_margin_h = 0;
719     XmFontList  fontlist;
720     XFontStruct  *font;
721     unsigned long charwidth;
722     unsigned long lineheight;
723     Dimension    pane_width, pane_height;
724
725     if (XtIsSubclass(text, dtTermWidgetClass))
726         XtVaGetValues(text,
727                 XmNmarginWidth, &margin_w,
728                 XmNmarginHeight,&margin_h,
729                 DtNuserFont,    &fontlist,
730                 NULL);
731     else
732         XtVaGetValues(text,
733                 XmNmarginWidth, &margin_w,
734                 XmNmarginHeight,&margin_h,
735                 XmNfontList,    &fontlist, 
736                 XmNlistSpacing, &text_spacing,
737                 NULL);
738
739     parent = XtParent(text);
740
741     if (XtIsSubclass(parent, xmScrolledWindowWidgetClass))
742     {
743         XtVaGetValues(parent,
744                 XmNhorizontalScrollBar, &hsb,
745                 XmNverticalScrollBar,   &vsb,
746                 XmNspacing,             &spacing,
747                 NULL);
748         if (hsb)
749             XtVaGetValues(hsb,
750                 XmNheight,              &hsb_height,
751                 NULL);
752         if (vsb)
753             XtVaGetValues(vsb,
754                 XmNwidth,               &vsb_width,
755                 NULL); 
756     }
757     else if (XtIsSubclass(parent, xmRowColumnWidgetClass))
758         XtVaGetValues(parent,
759                 XmNmarginWidth,         &p_margin_w,
760                 XmNmarginHeight,        &p_margin_h,
761                 NULL);
762
763     font = objxm_fontlist_to_font(fontlist);
764
765     if ((!XGetFontProperty(font, XA_QUAD_WIDTH, &charwidth)) || charwidth == 0) {
766        if (font->per_char && font->min_char_or_byte2 <= '0' &&
767                                  font->max_char_or_byte2 >= '0')
768            charwidth = font->per_char['0' - font->min_char_or_byte2].width;
769        else
770            charwidth = font->max_bounds.width;
771     }
772     lineheight = font->max_bounds.ascent + font->max_bounds.descent +
773                         text_spacing;
774
775     /* Calculate new pane size */
776     pane_width  = width  - (vsb_width  + spacing) - (2*p_margin_w);
777     pane_height = height - (hsb_height + spacing) - (2*p_margin_h);
778
779     *row_ptr = (int)((pane_height - (2*margin_h))/lineheight);
780     *col_ptr = (int)((pane_width  - (2*margin_w))/charwidth);
781
782     /* For some reason, above calculations result in rows being 1 too
783      * large for a scrolled list widget; put in workaround until
784      * error in calculations is found...
785      */
786 /*
787  REMIND: versions of Motif beyond August 10 don't need this
788     if (XtIsSubclass(text, xmListWidgetClass) && *row_ptr > 1)
789         (*row_ptr)--;
790 */
791
792 }
793
794 int
795 ui_set_busy_cursor(
796     Window      window,
797     BOOL        on
798 )
799 {
800     static Cursor  busy_cursor = NULL;
801     static Display *dpy        = NULL;
802
803     if (on) /* Turn ON busy cursor */
804     {
805         dpy = XtDisplay(AB_toplevel);
806
807         if (busy_cursor == NULL)
808             busy_cursor = XCreateFontCursor(dpy, XC_watch);
809
810         XDefineCursor(dpy, window, busy_cursor);
811     }
812     else if (dpy != NULL) /* Turn OFF busy cursor */
813     {
814         XUndefineCursor(dpy, window);
815         dpy = NULL;
816     }
817     return 0;
818
819 }
820
821 /*
822  * init_obj_pixmaps()
823  * Initialize object pixmaps
824  */
825 static void
826 init_obj_pixmaps
827 (
828 )
829 {
830     Display             *dpy;
831     Pixmap              tmp;
832     int                 i, 
833                         x, 
834                         y,
835                         status;
836     unsigned int        w, h, d, bw;
837     Window              root;
838     static int          init = False;
839     extern Widget       AB_toplevel;
840
841     /*
842      * Return immediately if this function was called once before
843      */
844     if (init)
845         return;
846
847     dpy = XtDisplay(AB_toplevel);
848
849     /*
850      * Loop thru object_pixmaps array uintil until last entry.
851      * The last entry should have type == AB_TYPE_UNKNOWN
852      */
853     for (i=0; (object_pixmaps[i].type != AB_TYPE_UNKNOWN); ++i)
854     {
855         /*
856          * Create pixmap
857          */
858         status = dtb_cvt_image_file_to_pixmap(AB_toplevel,
859             object_pixmaps[i].filename, &tmp);
860
861         if (!status)
862         {
863             /*
864              * Get width/height of pixmap
865              */
866             if (XGetGeometry(dpy, tmp, &root, &x, &y, &w, &h, &bw, &d))
867             {
868                 object_pixmaps[i].pixmap = tmp;
869                 object_pixmaps[i].width = w;
870                 object_pixmaps[i].height = h;
871             }
872             else
873                 fprintf(stderr, "XGetGeometry: returned error\n");
874         }
875     }
876
877     /*
878      * Create default pixmap
879      */
880     status = dtb_cvt_image_file_to_pixmap(AB_toplevel,
881                         "DtABdfl", &default_pixmap);
882
883     if (default_pixmap)
884     {
885         /*
886          * Get default pixmap width/height
887          */
888         if (XGetGeometry(dpy, default_pixmap, 
889                 &root, &x, &y, &w, &h, &bw, &d))
890         {
891             default_pixmap_width = w;
892             default_pixmap_height = h;
893         }
894         else
895             fprintf(stderr, "XGetGeometry: returned error\n");
896     }
897     
898     /*
899      * Set init flag
900      */
901     init = True;
902 }
903
904
905 /*
906  * ui_get_obj_pixmap
907  * based on an object's type and subtype, return a pixmap, and
908  * it's width/height. This pixmap typically can be used to represent
909  * the object in viewers/browsers.
910  */
911 void
912 ui_get_obj_pixmap
913 (
914     AB_OBJ              *obj,
915     Pixmap              *pixmap,        /* RETURN */
916     unsigned int        *width,         /* RETURN */
917     unsigned int        *height         /* RETURN */
918 )
919 {
920     int                 i;
921     AB_OBJECT_TYPE      type;
922     int                 subtype;
923     Pixmap              p = NULL;
924     BOOL                found = FALSE;
925
926     if (!obj || !pixmap || !width || !height)
927         return;
928
929     /*
930      * Initialize pixmaps
931      */
932     init_obj_pixmaps();
933
934     /*
935      * Get object type/subtype
936      */
937     type = obj_get_type(obj);
938     subtype = obj_get_subtype(obj);
939
940     /*
941      * Special case for scale/gauge
942      * The subtype field is not used. Instead it's read-only
943      * state is used to determine if it is a scale/gauge.
944      */
945     if (type == AB_TYPE_SCALE)
946     {
947         if (obj_get_read_only(obj) == False)
948             subtype = AB_SCALE_SCALE;
949         else /* Gauge */
950             subtype = AB_SCALE_GAUGE;
951     }
952
953     /*
954      * Search for object type/subtype match
955      */
956     for (i=0; (object_pixmaps[i].type != AB_TYPE_UNKNOWN); ++i)
957     {
958         if ((type == object_pixmaps[i].type) &&
959             (subtype == object_pixmaps[i].subtype))
960         {
961             *pixmap = object_pixmaps[i].pixmap;
962             *width = object_pixmaps[i].width;
963             *height = object_pixmaps[i].height;
964
965             if (*pixmap)
966                 found = TRUE;
967
968             break;
969         }
970     }
971
972     /*
973      * If no match, return the default pixmap
974      */
975     if (!found)
976     {
977         *pixmap = default_pixmap;
978         *width = default_pixmap_width;
979         *height = default_pixmap_height;
980     }
981 }
982
983 void
984 ui_add_window_close_callback(
985     Widget         shell,
986     XtCallbackProc delete_callback,
987     XtPointer      client_data,
988     unsigned char  delete_response
989 )
990 {
991     Atom WM_DELETE_WINDOW;
992
993     WM_DELETE_WINDOW = XmInternAtom(XtDisplay(shell), "WM_DELETE_WINDOW", False);
994
995     XtVaSetValues(shell, XmNdeleteResponse, delete_response, NULL);
996     XmAddWMProtocolCallback(shell, WM_DELETE_WINDOW, delete_callback, client_data);
997
998 }
999
1000 void
1001 ui_remove_window_close_callback(
1002     Widget         shell,
1003     XtCallbackProc delete_callback,
1004     XtPointer      client_data
1005 )
1006 {
1007     Atom WM_DELETE_WINDOW;
1008
1009     WM_DELETE_WINDOW = XmInternAtom(XtDisplay(shell),"WM_DELETE_WINDOW",False);
1010     XmRemoveWMProtocolCallback(shell,WM_DELETE_WINDOW, 
1011         delete_callback, client_data);
1012 }
1013
1014 void
1015 ui_add_window_iconify_handler(
1016     Widget              shell,
1017     XtEventHandler      iconify_proc,
1018     XtPointer           client_data
1019 )
1020 {
1021     XtAddEventHandler(shell, StructureNotifyMask, False, iconify_proc,
1022                 (XtPointer)client_data);
1023 }
1024
1025 void
1026 ui_remove_window_iconify_handler(
1027     Widget              shell,
1028     XtEventHandler      iconify_proc,
1029     XtPointer           client_data 
1030
1031
1032     XtRemoveEventHandler(shell, StructureNotifyMask, False, iconify_proc,
1033                 (XtPointer)client_data);
1034 }
1035
1036 void
1037 ui_refresh_widget_tree(
1038     Widget      widget
1039 )
1040 {
1041     WidgetList  children;
1042     int         num_children = 0;
1043     int         i;
1044
1045     if (widget == NULL || !XtIsWidget(widget) || !XtIsRealized(widget))
1046         return;
1047
1048     if (XtIsSubclass(widget, compositeWidgetClass))
1049     {
1050         XtVaGetValues(widget,
1051                 XmNnumChildren, &num_children,
1052                 XmNchildren,    &children,
1053                 NULL);
1054
1055         /* Use recursion to traverse all the way to leaf nodes...*/
1056         for (i=0; i < num_children; i++)
1057             ui_refresh_widget_tree(children[i]);
1058     }
1059     XClearArea(XtDisplay(widget), XtWindow(widget), 0, 0, 0, 0, TRUE);
1060 }
1061
1062
1063 static Bool             
1064 event_is_expose(XEvent *event)
1065 {
1066     Bool        is_expose = FALSE;
1067
1068     switch (event->type)
1069     {
1070         case CreateNotify:
1071         case DestroyNotify:
1072         case Expose:
1073         case GraphicsExpose:
1074         case MapNotify:
1075         case MapRequest:
1076         case NoExpose:
1077         case UnmapNotify:
1078         case VisibilityNotify:
1079             is_expose= TRUE;
1080         break;
1081     }
1082
1083     return is_expose;
1084 }
1085
1086
1087 static void
1088 sync_timeout_proc(
1089                             XtPointer           clientData,
1090                             XtIntervalId        *intervalIdPtr
1091 )
1092 {
1093     SyncData            syncData = (SyncData)clientData;
1094     time_t              cur_time = time(NULL);
1095     BOOL                done = FALSE;
1096
1097     if (syncData->synced)
1098     {
1099         return;
1100     }
1101
1102     done =
1103         ((syncData->timeout_ticks - syncData->last_expose_ticks) >= 5);
1104
1105     if (done)
1106     {
1107         XEvent  event;
1108         Display *display = syncData->display;
1109         Window  window = syncData->window;
1110         int     i = 0;
1111         int     rc = 0;
1112         long    event_mask = 0;
1113
1114         syncData->synced = TRUE;
1115
1116         /*
1117          * Fill in the event
1118          */
1119         event.type = ClientMessage;
1120         event.xclient.display = display;
1121         event.xclient.window = window;
1122         event.xclient.message_type = 0;
1123         event.xclient.format = 32;
1124         for (i = 0; i < 8; ++i)
1125         {
1126             event.xclient.data.l[i] = sync_notify_value;
1127         }
1128         rc = XSendEvent(display, window, True, event_mask, &event);
1129         if (rc == 0)
1130         {
1131             util_dprintf(0, "BIG TIME ERROR: send event failed\n");
1132         }
1133     }
1134
1135     if (!(syncData->synced))
1136     {
1137         syncData->timerId = XtAppAddTimeOut(
1138                 XtWidgetToApplicationContext(AB_toplevel), 100, 
1139                 sync_timeout_proc, (XtPointer)clientData);
1140     }
1141
1142     ++(syncData->timeout_ticks);
1143 }
1144
1145
1146 int
1147 ui_sync_display_of_widget(Widget widget)
1148 {
1149     int                 return_value = 0;
1150     XtAppContext        appContext = 
1151                                 XtWidgetToApplicationContext(widget);
1152     XEvent              eventRec, *event = &eventRec;
1153     SyncDataRec         syncData;
1154     Bool                ignore_event = FALSE;
1155     Widget              ancestor = widget;
1156     Widget              last_ancestor = ancestor;
1157     Widget              sync_widget = NULL;
1158     Screen              *screen = NULL;
1159
1160     syncData.timerId = 0;
1161     syncData.synced = FALSE;
1162     syncData.start_time = time(NULL);
1163     syncData.last_expose_ticks = 0;
1164     syncData.timeout_ticks = 0;
1165     syncData.display = NULL;
1166     syncData.window = NULL;
1167 #define last_expose_ticks (syncData.last_expose_ticks)
1168 #define synced (syncData.synced)
1169 #define timeout_ticks (syncData.timeout_ticks)
1170
1171     syncData.display = XtDisplay(widget);
1172     screen = XtScreen(widget);
1173     syncData.window = RootWindowOfScreen(screen);
1174
1175     /*
1176      * Find topmost parent of this widget that belongs to application.
1177      * This is in case this widget is destroyed (common for popups)
1178      */
1179     last_ancestor = ancestor = widget;
1180     while ((ancestor != NULL) && 
1181            (XtWidgetToApplicationContext(ancestor) == appContext))
1182     {
1183         last_ancestor = ancestor;
1184         ancestor = XtParent(ancestor);
1185     }
1186     sync_widget = last_ancestor;
1187     syncData.window = XtWindow(sync_widget);
1188
1189     syncData.timerId = XtAppAddTimeOut(appContext, 100, 
1190                                 sync_timeout_proc, (XtPointer)&syncData);
1191
1192     while (!synced)
1193     {
1194         XtAppNextEvent(appContext, event);
1195         ignore_event = (   (event->type == ClientMessage) 
1196                         && (event->xclient.data.l[0] == sync_notify_value));
1197         if (!ignore_event)
1198         {
1199             XtDispatchEvent(event);
1200         }
1201         
1202         if (event_is_expose(event))
1203         {
1204             last_expose_ticks = timeout_ticks;
1205         }
1206         if (difftime(time(NULL), syncData.start_time) >= 5)
1207         {
1208             /* we've done this long enough - give up */
1209             synced = TRUE;
1210         }
1211     } /* while !synced */
1212
1213     XtRemoveTimeOut(syncData.timerId); syncData.timerId = 0;
1214     return return_value;
1215 #undef last_expose_ticks
1216 #undef synced
1217 #undef timeout_ticks
1218 }
1219
1220 /*
1221  * Rubber banding convenience routines
1222  */
1223
1224 /*
1225  * Rubberbanding has just finished.
1226  * Finish up rubber banding:
1227  *      - erase last box drawn
1228  *      - call rubber band func
1229  *      - reset some state variables
1230  */
1231 static void
1232 rubberband_finish(
1233     Widget      widget,
1234     XEvent      *event,
1235     XtPointer   client_data
1236 )
1237 {
1238     if (!rb_first_time)
1239     {
1240         /* erase last box */
1241         x_box_r(rb_widget, &rb_rect);
1242
1243         /*
1244          * If a rubber band func was supplied, call it
1245          */
1246         if (rubberband_func)
1247             rubberband_func(widget, event, &rb_rect, client_data);
1248
1249         rubberband_func = NULL;
1250         rb_first_time = TRUE;
1251     }
1252 }
1253
1254 /*
1255  * EventHandler: rubberband action is completed...
1256  * Call rubberband_finish() which calls the rubber 
1257  * band func.
1258  */
1259 static void
1260 rubberband_release(
1261     Widget widget,
1262     XtPointer client_data,
1263     XEvent *event,
1264     Boolean *cont_dispatch
1265 )
1266 {
1267     if (event->type != ButtonRelease)
1268         return;
1269
1270     if (rband_in_progress)
1271     {
1272         XtUngrabPointer(widget, CurrentTime);
1273         XtRemoveEventHandler(widget, ButtonReleaseMask, False,
1274             rubberband_release, client_data);
1275         rband_in_progress = False;
1276
1277         if (just_rbanded)
1278         {
1279             rubberband_finish(widget, event, client_data);
1280             just_rbanded = False;
1281             *cont_dispatch = False;
1282         }
1283     }
1284 }
1285
1286 /*
1287  * rubberband_draw()
1288  * Draws the rubber band box seen when the mouse is dragged
1289  */
1290 static void
1291 rubberband_draw(
1292     Widget      widget,
1293     XEvent      *event,
1294     XtPointer   client_data
1295 )
1296 {
1297     short              x,y;
1298
1299     if (event->type == ButtonPress)
1300     {
1301         x = (short)((XButtonEvent*)event)->x;
1302         y = (short)((XButtonEvent*)event)->y;
1303     }
1304     else if (event->type == MotionNotify)
1305     {
1306         x = (short)((XMotionEvent*)event)->x;
1307         y = (short)((XMotionEvent*)event)->y;
1308     }
1309     else
1310         return;
1311
1312     if (rb_first_time)
1313     {
1314         rb_widget = widget;
1315
1316         rb_rect.x = x;
1317         rb_rect.y = y;
1318
1319         rb_first_time = FALSE;
1320     }
1321     else
1322         x_box_r(rb_widget, &rb_rect);
1323
1324     rb_rect.width  = x - rb_rect.x;
1325     rb_rect.height = y - rb_rect.y;
1326
1327     x_box_r(rb_widget, &rb_rect); 
1328
1329 }
1330
1331 /*
1332  * Starts up the rubber band UI.
1333  * It grab the pointer and adds an event handler 
1334  * which detects the ButtonRelease. It also sets the
1335  * rubber band func.
1336  */
1337 int
1338 ui_initiate_rubberband(
1339     Widget              widget,
1340     Boolean             confine_to_window,
1341     UiRubberBandFunc    rb_func,
1342     XtPointer           client_data
1343 )
1344 {
1345
1346     XtAddEventHandler(widget, ButtonReleaseMask,  False,
1347                 rubberband_release, client_data);
1348  
1349     if (XtGrabPointer(widget, False,
1350         ButtonReleaseMask | ButtonMotionMask | PointerMotionMask,
1351         GrabModeAsync, GrabModeAsync,  
1352         confine_to_window ? XtWindow(widget) : None,
1353             NULL, CurrentTime) == GrabSuccess)
1354     {
1355         rband_in_progress = True;
1356         rubberband_func = rb_func;
1357         return OK;
1358     }
1359
1360     rband_in_progress = False;
1361     rubberband_func = NULL;
1362     return ERROR;
1363 }
1364
1365
1366 /*
1367  * ui_button_drag: drag action ...
1368  * Called by the drag button event handler for the widget
1369  * where rubber banding is desired.
1370  */
1371 void
1372 ui_button_drag(
1373     Widget      widget,
1374     XEvent      *event,
1375     XtPointer   client_data
1376 )
1377 {
1378     if (event->type == MotionNotify)
1379     {
1380         if (rband_in_progress)
1381         {
1382             rubberband_draw(widget, event, client_data);
1383             just_rbanded = True;
1384         }
1385     }
1386 }
1387
1388
1389 Widget
1390 ui_optionmenu_add_item(
1391     Widget      opmenu,
1392     STRING      item_str
1393 )
1394 {
1395     XmString    xmitem;
1396     Widget      cascade_btn = NULL;
1397     Widget      menu = NULL;
1398     Widget      mpb = NULL;
1399     int         ret = 0;
1400  
1401     if ((cascade_btn = XmOptionButtonGadget(opmenu)) != NULL)
1402     {
1403         XtVaGetValues(cascade_btn, XmNsubMenuId, &menu, NULL);
1404         if (menu)
1405         {
1406             xmitem = XmStringCreateLocalized(item_str);
1407             mpb = XtVaCreateManagedWidget(item_str,
1408                 xmPushButtonWidgetClass,
1409                 menu,
1410                 XmNlabelString, xmitem,
1411                 NULL);
1412             XmStringFree(xmitem);
1413         }
1414     }
1415
1416     return (mpb);
1417 }
1418
1419 int 
1420 ui_optionmenu_delete_item( 
1421     Widget      opmenu, 
1422     STRING      item_str
1423
1424
1425     Widget      item = NULL; 
1426     int         iRet = 0;
1427   
1428     item = ui_optionmenu_find_item(opmenu, item_str); 
1429     if (item != NULL)
1430     {
1431         XtDestroyWidget(item);
1432     }
1433     else
1434     {
1435         iRet = -1;
1436     }
1437
1438     return (iRet);
1439 }
1440
1441 Widget
1442 ui_optionmenu_replace_item(
1443     Widget      opmenu,
1444     STRING      old_item_str,
1445     STRING      new_item_str
1446 )
1447 {
1448     Widget      item = NULL;
1449     Widget      opmenu_label = NULL;
1450     XmString    xmstr = NULL;
1451     XmString    new_item_xmstr = NULL;
1452     XmString    old_item_xmstr = NULL;
1453
1454     item = ui_optionmenu_find_item(opmenu, old_item_str);
1455     if (item != NULL)
1456     {
1457         new_item_xmstr = XmStringCreateLocalized(new_item_str);
1458
1459         /* Check if the item we're replacing is the one
1460          * which is currently showing in the optionmenu.
1461          * If so, change the string.
1462          */
1463         old_item_xmstr = XmStringCreateLocalized(old_item_str);
1464         opmenu_label = XmOptionButtonGadget(opmenu);
1465         XtVaGetValues(opmenu_label, XmNlabelString, &xmstr, NULL);
1466         if (XmStringCompare(xmstr, old_item_xmstr))
1467         {
1468             XtVaSetValues(opmenu_label, 
1469                           XmNlabelString, new_item_xmstr, 
1470                           NULL); 
1471         }
1472
1473         /* Change the button label to the new string */
1474         XtVaSetValues(item, XmNlabelString, new_item_xmstr, NULL);
1475
1476         XmStringFree(xmstr);
1477         XmStringFree(old_item_xmstr);
1478         XmStringFree(new_item_xmstr);
1479     }
1480     return (item);
1481 }
1482
1483 Widget
1484 ui_optionmenu_find_item(
1485     Widget      opmenu,
1486     STRING      item_str
1487 )
1488 {
1489     Widget      cascade_btn = NULL;
1490     Widget      menu = NULL;
1491     Widget      found_item = NULL;
1492     WidgetList  children = NULL;
1493     XmString    search_item, child = NULL;
1494     int         i, numChildren = 0;
1495     BOOL        Found = FALSE;
1496
1497     if ((cascade_btn = XmOptionButtonGadget(opmenu)) != NULL)
1498     { 
1499         XtVaGetValues(cascade_btn, XmNsubMenuId, &menu, NULL);
1500         if (menu)   
1501         {
1502             search_item = XmStringCreateLocalized(item_str);
1503             XtVaGetValues(menu,
1504                         XmNnumChildren, &numChildren,
1505                         XmNchildren, &children,
1506                         NULL);
1507             for (i=0; i < numChildren && !Found; i++)
1508             {
1509                 XtVaGetValues(children[i], XmNlabelString, &child, NULL);
1510                 if (XmStringCompare(search_item, child))
1511                 {
1512                     Found = TRUE;
1513                     found_item = children[i];
1514                 }
1515             }
1516             XmStringFree(search_item);
1517             XmStringFree(child);
1518         }
1519     }
1520     return (found_item);
1521 }
1522
1523 int
1524 ui_optionmenu_num_items(
1525     Widget      opmenu
1526 )
1527 {
1528     Widget      cascade_btn = NULL;
1529     Widget      menu = NULL;
1530     int         numChildren = 0;
1531
1532     if ( (opmenu != NULL) &&
1533          ((cascade_btn = XmOptionButtonGadget(opmenu)) != NULL)
1534        )
1535     {
1536         XtVaGetValues(cascade_btn, XmNsubMenuId, &menu, NULL);
1537         if (menu)
1538         {
1539             XtVaGetValues(menu,
1540                         XmNnumChildren, &numChildren,
1541                         NULL);
1542         }
1543     }
1544     return (numChildren);
1545 }
1546
1547
1548 void
1549 ui_optionmenu_change_label(
1550     Widget      opmenu,
1551     STRING      new_str
1552 )
1553 {
1554     Widget      opmenu_label = NULL;
1555     XmString    new_xmstr;
1556     XmString    old_xmstr = NULL;
1557
1558     opmenu_label = XmOptionButtonGadget(opmenu);
1559     if ((opmenu_label != NULL) && (new_str != NULL))
1560     {
1561         new_xmstr = XmStringCreateLocalized(new_str);
1562         XtVaGetValues(opmenu_label, XmNlabelString, &old_xmstr, NULL);
1563         
1564         /* If the two labels are different, then change
1565          * the optionmenu label.
1566          */
1567         if (!XmStringCompare(old_xmstr, new_xmstr))
1568         {
1569             XtVaSetValues(opmenu_label,
1570                           XmNlabelString, new_xmstr,
1571                           NULL);
1572         }
1573         XmStringFree(new_xmstr);
1574     }
1575 }
1576
1577 void
1578 ui_optionmenu_change_label_pixmap(
1579     Widget      opmenu,
1580     Pixmap      pixmap
1581 )
1582 {
1583     Widget opmenu_label;
1584  
1585     opmenu_label = XmOptionButtonGadget(opmenu);
1586  
1587     if (opmenu_label != NULL)
1588     {
1589         XtVaSetValues(opmenu_label,
1590                 XmNlabelPixmap, pixmap,
1591                 XmNlabelType,   XmPIXMAP,
1592                 NULL);
1593     }
1594 }
1595
1596 /*
1597 ** Set the label string on an object
1598 ** (converts it to XmString internally, if needed)
1599 */
1600 void
1601 ui_obj_set_label_string(
1602     ABObj       obj,
1603     STRING      label
1604 )
1605 {
1606     ABObj labelObj   = NULL;
1607     
1608     if (obj == NULL)
1609         return;
1610         
1611     switch (obj_get_type(obj))
1612     {
1613         case AB_TYPE_BUTTON:
1614         case AB_TYPE_CHOICE:
1615         case AB_TYPE_COMBO_BOX:
1616         case AB_TYPE_LABEL:
1617         case AB_TYPE_LIST:
1618         case AB_TYPE_SPIN_BOX:
1619         case AB_TYPE_SCALE:
1620         case AB_TYPE_TEXT_FIELD:
1621             labelObj = objxm_comp_get_subobj(obj, AB_CFG_LABEL_OBJ);
1622             if (labelObj == NULL || objxm_get_widget(labelObj) == NULL)
1623                 return;
1624
1625             ui_set_label_string(objxm_get_widget(labelObj), label);
1626             break;
1627
1628         case AB_TYPE_ITEM:
1629             switch(obj_get_item_type(obj))
1630             {
1631                 case AB_ITEM_FOR_MENU:
1632                 case AB_ITEM_FOR_MENUBAR:
1633                 case AB_ITEM_FOR_CHOICE:
1634                     labelObj = objxm_comp_get_subobj(obj, AB_CFG_LABEL_OBJ);
1635                     if (labelObj == NULL || objxm_get_widget(labelObj) == NULL)
1636                         return;
1637
1638                     ui_set_label_string(objxm_get_widget(labelObj), label);
1639                     break;
1640
1641                 case AB_ITEM_FOR_COMBO_BOX:
1642                 case AB_ITEM_FOR_LIST:
1643                 case AB_ITEM_FOR_SPIN_BOX:
1644                     {
1645                         ABObj        p_obj = obj_get_parent(obj);
1646                         Widget       parent = objxm_get_widget(p_obj);
1647                         AB_ITEM_TYPE itype = (AB_ITEM_TYPE)obj_get_subtype(obj);
1648                         int          pos;
1649                         int          num_items;
1650                         XmString     xmitem;
1651             
1652                         if (parent != NULL)
1653                         {
1654                             xmitem = XmStringCreateLocalized(label);
1655                             pos = obj_get_child_num(obj);
1656                             pos++; /* XmList starts at 1 */
1657                 
1658                             if (obj_is_combo_box_item(obj))
1659                                 parent = ui_combobox_get_list_widget(parent);
1660                 
1661                             if (obj_is_list_item(obj) ||
1662                                 obj_is_combo_box_item(obj))
1663                                 XtVaGetValues(parent,
1664                                     XmNitemCount, &num_items,
1665                                     NULL);
1666                             else if (obj_is_spin_box_item(obj))
1667                                 XtVaGetValues(parent,
1668                                     DtNnumValues, &num_items,
1669                                     NULL);
1670
1671                             if (pos <= num_items)
1672                             {
1673                                 if (obj_is_list_item(obj) ||
1674                                     obj_is_combo_box_item(obj))
1675                                 {
1676                                     XmListReplacePositions(parent, &pos,
1677                                         &xmitem, 1);
1678                                 }
1679                                 else
1680                                 {
1681                                     DtSpinBoxDeletePos(parent, pos);
1682                                     DtSpinBoxAddItem(parent, xmitem, pos);
1683                                 }
1684                             }
1685                             XmStringFree(xmitem);
1686                         }
1687                     }
1688                     break;
1689
1690                 default:
1691                     break;
1692             }
1693             break;
1694             
1695         case AB_TYPE_BASE_WINDOW:
1696         case AB_TYPE_DIALOG:
1697         case AB_TYPE_FILE_CHOOSER:
1698             labelObj = objxm_comp_get_subobj(obj, AB_CFG_LABEL_OBJ);
1699             if (labelObj == NULL || objxm_get_widget(labelObj) == NULL)
1700                 return;
1701
1702             XtVaSetValues(objxm_get_widget(labelObj), XmNtitle, label, NULL);
1703             break;
1704
1705         default:
1706             break;
1707     }
1708 }
1709
1710 /*
1711 ** Set the label glyph (ie graphic) on an object
1712 */
1713 void
1714 ui_obj_set_label_glyph(
1715     ABObj       obj,
1716     STRING      fileName
1717 )
1718 {
1719     ABObj  labelObj = NULL;
1720     
1721     if (obj == NULL)
1722         return;
1723
1724     if (util_strempty(fileName))
1725         return;
1726     
1727     labelObj = objxm_comp_get_subobj(obj, AB_CFG_LABEL_OBJ);
1728     if (labelObj == NULL || objxm_get_widget(labelObj) == NULL)
1729         return;
1730
1731     switch (obj_get_type(obj))
1732     {
1733         case AB_TYPE_BUTTON:
1734         case AB_TYPE_CHOICE:
1735         case AB_TYPE_COMBO_BOX:
1736         case AB_TYPE_LABEL:
1737         case AB_TYPE_LIST:
1738         case AB_TYPE_SPIN_BOX:
1739         case AB_TYPE_SCALE:
1740         case AB_TYPE_TEXT_FIELD:
1741             ui_set_label_glyph(objxm_get_widget(labelObj), fileName);
1742             break;
1743
1744         case AB_TYPE_ITEM:
1745             switch(obj_get_item_type(obj))
1746             {
1747                 case AB_ITEM_FOR_MENU:
1748                 case AB_ITEM_FOR_MENUBAR:
1749                 case AB_ITEM_FOR_CHOICE:
1750                     ui_set_label_glyph(objxm_get_widget(labelObj), fileName);
1751                     break;
1752
1753                 default:
1754                     break;
1755             }
1756             break;
1757             
1758         default:
1759             break;
1760     }
1761 }
1762
1763 /*
1764 ** Set the label on an object
1765 **     string and glyphs are supported
1766 */
1767 void
1768 ui_obj_set_label(
1769     ABObj       obj,
1770     STRING      label
1771 )
1772 {
1773     if (obj == NULL)
1774         return;
1775
1776     switch (obj_get_label_type(obj))
1777     {
1778         case AB_LABEL_STRING:
1779             ui_obj_set_label_string(obj, label);
1780             break;
1781
1782         case AB_LABEL_GLYPH:
1783             ui_obj_set_label_glyph(obj, label);
1784             break;
1785
1786         default:
1787             return;
1788     }
1789 }
1790