dtcalc: change from obsoleted MAXFLOAT to FLT_MAX from std C
[oweals/cde.git] / cde / lib / DtWidget / ComboBox.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  * DtWidget/ComboBox.c
25  */
26 /*
27  * (c) Copyright 1996 Digital Equipment Corporation.
28  * (c) Copyright 1993, 1994, 1996 Hewlett-Packard Company
29  * (c) Copyright 1993, 1994, 1996 International Business Machines Corp.
30  * (c) Copyright 1993, 1994, 1996 Sun Microsystems, Inc.
31  * (c) Copyright 1993, 1994, 1996 Novell, Inc.
32  * (c) Copyright 1996 FUJITSU LIMITED.
33  * (c) Copyright 1996 Hitachi.
34  */
35 #ifdef REV_INFO
36 #ifndef lint
37 static char rcsid[] = 
38   "$XConsortium: ComboBox.c /main/15 1996/10/29 12:48:08 cde-hp $"
39 #endif
40 #endif
41 /***********************************************************
42 Copyright 1993 Interleaf, Inc.
43
44 Permission to use, copy, modify, and distribute this software
45 and its documentation for any purpose without fee is granted,
46 provided that the above copyright notice appear in all copies
47 and that both copyright notice and this permission notice appear
48 in supporting documentation, and that the name of Interleaf not
49 be used in advertising or publicly pertaining to distribution of
50 the software without specific written prior permission.
51
52 Interleaf makes no representation about the suitability of this
53 software for any purpose. It is provided "AS IS" without any
54 express or implied warranty. 
55 ******************************************************************/
56
57 /*
58  * (C) Copyright 1991,1992, 1993
59  * Interleaf, Inc.
60  * 9 Hillside Avenue, 
61  * Waltham, MA  02154
62  *
63  * ComboBox.c (DtComboBoxWidget):
64  *
65  * I wanted a margin around the widget (outside the shadow, like buttons), 
66  * so that the combo-box could be made the same size as a 
67  * push-button, etc.  The bulletin-board widget always puts the shadow at 
68  * the outside edge of the widget, so combo-box is a sublcass of
69  * manager, and we do everything ourselves.
70  * 
71  * One must be carefull when using Dimension (for core width and height).
72  * Dimension is an unsigned short.  This causes problems when subtracting
73  * and ending up with what should be a negative number (but it doesn't).
74  * All child widget positioning is done by the combo_box.  We don't
75  * use any heavy-weight forms, etc. to help us out.
76  *
77  * There is no padding when editable.  If using a label given it a
78  * small margin, so it doesn't run up against the side of our
79  * shadow or the arrow.
80  * 
81  * Make some of the ComboBox functions common, so they can be shared
82  * with SpinButton.
83  *
84  * The label-string resource got out of control.  Its role kept getting
85  * expanded; now the whole thing is a mess.  Currently it shadows the
86  * label's label-string.  If the user sets it explicitly it will 
87  * take affect for as long as update-label is false.  If update-label
88  * is true, it will take affect until the end-user makes a selection
89  * off the list.
90  * 
91  * Known bugs:
92  *          Changing margin_width or margin_height resources when the
93  *          combo_box has focus will probably result in display glitches.
94  *
95  */
96 /*
97  * The DtComboBox widget is rigged with the Motif widget binary compatibilit 
98  * mechanism. All Motif-specific changes for this mechanism are preceded  
99  * by a comment including the string "MotifBc".
100  *
101  * For a description of the Motif widget binary compatibility mechanism 
102  * see the reference manual entry on XmResolveAllPartOffsets().
103  *
104  */
105
106 /* _NO_PROTO support no longer required: */
107
108 #include <Xm/XmP.h>             /* for fast subclassing in XmIsComboBox */
109 #include <Xm/XmosP.h>           /* for INT_MAX */
110 #include <Dt/DtMsgsP.h>
111 #include "ComboBoxP.h"
112 #include <Xm/DrawP.h>
113 #include <Xm/DisplayP.h>
114 #include <Xm/List.h>
115 #include <Xm/ComboBox.h>        /* for redirecting utility functions */
116 #include "DtWidgetI.h"          /* for _Dt thread-safety macros */
117 /* some unpublished Motif interfaces */
118 #include <Xm/XmPrivate.h>
119
120 /* From MenuUtilP.h */
121 extern int _XmGrabKeyboard(Widget widget, int owner_events, int pointer_mode,
122                         int keyboard_mode, Time time) ;
123 /*
124  * MotifBc
125  */
126 #define DtComboBoxIndex (XmManagerIndex + 1)
127 static XmOffsetPtr ipot; /* Instance part offset table */
128 static XmOffsetPtr cpot; /* Constraint part offset table */
129
130 #define ScrollBarVisible( wid)      (wid && XtIsManaged( wid))
131
132 static void     ClassInitialize (void);
133 static void     Initialize (DtComboBoxWidget request, 
134                                DtComboBoxWidget new, ArgList given_args, 
135                                Cardinal *num_args);
136 static XmNavigability WidgetNavigable (DtComboBoxWidget combo);
137 static void     _ComboBoxFocusIn (DtComboBoxWidget combo, XEvent *event, 
138                                      char **params, Cardinal *num_params);
139 static void     _ComboBoxFocusOut (DtComboBoxWidget combo, XEvent *event,
140                                       char **params, Cardinal *num_params);
141 static void     DrawHighlight (DtComboBoxWidget combo, Boolean clear);
142 static void     _ComboBoxActivate (Widget w, XEvent *event, char **params,
143                                       Cardinal *num_params);
144 static void     _ComboBoxKbdCancel (Widget w, XEvent *event, char **params,
145                                        Cardinal *num_params);
146 static void     _ComboBoxPrevTabGroup (Widget w, XEvent *event, 
147                                 char **params, Cardinal *num_params);
148 static void     _ComboBoxNextTabGroup (Widget w, XEvent *event, 
149                                 char **params, Cardinal *num_params);
150 static void     CheckResources (DtComboBoxWidget combo);
151 static void     Destroy (DtComboBoxWidget combo);
152 static void     Resize (DtComboBoxWidget combo);
153 static void     Redisplay (DtComboBoxWidget w, XEvent *event, 
154                               Region region);
155 static XtGeometryResult GeometryManager (Widget w, 
156                                             XtWidgetGeometry *request, 
157                                             XtWidgetGeometry *reply);
158 static void     SetComboBoxSize (DtComboBoxWidget combo);
159 static void     ForceChildSizes (DtComboBoxWidget combo);
160 static void     LayoutChildren (DtComboBoxWidget combo);
161 static Boolean  SetValues (DtComboBoxWidget current, 
162                               DtComboBoxWidget request, DtComboBoxWidget new);
163 static void     ClearShadow (DtComboBoxWidget w, Boolean all);
164 static void     DrawShadow (DtComboBoxWidget w);
165 static char*    GetTextString (XmString xm_string);
166 static void     SetTextFieldData (DtComboBoxPart *combo_p, XmString item);
167 static void     SetMaximumLabelSize (DtComboBoxPart *combo_p);
168 static void     SetLabelData (DtComboBoxPart *combo_p, XmString item,
169                                  Boolean force_label_string);
170 static void     select_cb (Widget w, XtPointer client_data, 
171                               XtPointer call_data);
172 static void     shell_event_handler (Widget widget, XtPointer client_data,
173                                         XEvent* event, Boolean *dispatch);
174 static void     list_event_handler (Widget widget, XtPointer client_data,
175                                        XEvent* event, Boolean *dispatch);
176 static void     TextFieldActivate (DtComboBoxPart *combo_p, XtPointer call_data);
177 static void     activate_cb (Widget w, XtPointer client_data,
178                                 XtPointer call_data);
179 static void     arrow_expose_cb (Widget w, XtPointer client_data,
180                                     XtPointer call_data);
181 static void     text_losing_focus_cb (Widget w, XtPointer client_data,
182                                          XtPointer call_data);
183 static void     text_activate_cb (Widget w, XtPointer client_data,
184                                      XtPointer call_data);
185 static void     text_focus_cb (Widget w, XtPointer client_data,
186                                   XtPointer call_data);
187 static void     SyncWithList (DtComboBoxPart *combo_p);
188 static XmImportOperator _XmSetSyntheticResForChild (Widget widget,
189                                                        int offset, 
190                                                        XtArgVal * value);
191 /* Converter */
192 static  Boolean _CvtStringToType (Display *dpy, XrmValuePtr args, 
193         Cardinal *num_args, XrmValuePtr from, XrmValuePtr to, XtPointer *data);
194
195 /* Grab and Ungrab processing */
196 static void     input_ungrab ( DtComboBoxWidget combo, int ungrab_mask);
197
198 /* Resolution Independent Processing */
199 void _DtComboBoxGetArrowSize(   Widget w,
200                                         int resource_offset,
201                                         XtArgVal *value);
202 void _DtComboBoxGetListMarginHeight(    Widget w,
203                                                 int resource_offset,
204                                                 XtArgVal *value);
205 void _DtComboBoxGetListMarginWidth(     Widget w,
206                                                 int resource_offset,
207                                                 XtArgVal *value);
208 void _DtComboBoxGetListSpacing(  Widget w,
209                                         int resource_offset,
210                                         XtArgVal *value);
211
212
213 static XmString InitLabel = NULL;
214
215 /*
216  * MotifBc
217  */
218
219 #define Arrow(w) XmField(w,ipot,DtComboBox,arrow,Widget)
220 #define Shell(w) XmField(w,ipot,DtComboBox,shell,Widget)
221 #define Frame(w) XmField(w,ipot,DtComboBox,frame,Widget)
222 #define Label(w) XmField(w,ipot,DtComboBox,label,Widget)
223 #define Sep(w) XmField(w,ipot,DtComboBox,sep,Widget)
224 #define OldWidth(w) XmField(w,ipot,DtComboBox,old_width,Dimension)
225 #define OldHeight(w) XmField(w,ipot,DtComboBox,old_height,Dimension)
226 #define LabelMaxLength(w) XmField(w,ipot,DtComboBox,label_max_length,Dimension)
227 #define LabelMaxHeight(w) XmField(w,ipot,DtComboBox,label_max_height,Dimension)
228
229 #define MaxShellWidth(w) XmField(w,ipot,DtComboBox,max_shell_width,Dimension)
230 #define MaxShellHeight(w) XmField(w,ipot,DtComboBox,max_shell_height,Dimension)
231
232 #define MarginHeight(w) XmField(w,ipot,DtComboBox,margin_height,Dimension)
233 #define MarginWidth(w) XmField(w,ipot,DtComboBox,margin_width,Dimension)
234 #define SelectedItem(w) XmField(w,ipot,DtComboBox,selected_item,XmString)
235 #define SelectedPosition(w) XmField(w,ipot,DtComboBox,selected_position,int)
236 #define SelectionCallback(w) \
237                 XmField(w,ipot,DtComboBox,selection_callback,XtCallbackList)
238 #define Type(w) XmField(w,ipot,DtComboBox,type,unsigned char)
239 #define ArrowSpacing(w) XmField(w,ipot,DtComboBox,arrow_spacing,Dimension)
240
241 #define ArrowSize(w) XmField(w,ipot,DtComboBox,arrow_size,Dimension)
242 #define ActivateCallback(w) \
243                 XmField(w,ipot,DtComboBox,activate_callback,XtCallbackList)
244 #define Alignment(w) XmField(w,ipot,DtComboBox,alignment,unsigned char)
245 #define ArrowType(w) XmField(w,ipot,DtComboBox,arrow_type,unsigned char)
246 #define TextColumns(w) XmField(w,ipot,DtComboBox,text_columns,short)
247 #define FocusCallback(w) XmField(w,ipot,DtComboBox,focus_callback,XtCallbackList)
248 #define HorizontalSpacing(w) XmField(w,ipot,DtComboBox,horizontal_spacing,Dimension)
249 #define ItemCount(w) XmField(w,ipot,DtComboBox,item_count,int)
250 #define Items(w) XmField(w,ipot,DtComboBox,items,XmStringTable)
251 #define ListItems(w) XmField(w,ipot,DtComboBox,list_items,XmStringTable)
252 #define LabelString(w) XmField(w,ipot,DtComboBox,label_string,XmString)
253 #define List(w) XmField(w,ipot,DtComboBox,list,Widget)
254 #define ListFontList(w) XmField(w,ipot,DtComboBox,list_font_list,XmFontList)
255 #define ListMarginHeight(w) XmField(w,ipot,DtComboBox,list_margin_height,Dimension)
256 #define ListMarginWidth(w) XmField(w,ipot,DtComboBox,list_margin_width,Dimension)
257 #define ListSpacing(w) XmField(w,ipot,DtComboBox,list_spacing,Dimension)
258 #define LosingFocusCallback(w) XmField(w,ipot,DtComboBox,losing_focus_callback,XtCallbackList)
259 #define TextMaxLength(w) XmField(w,ipot,DtComboBox,text_max_length,unsigned int)
260 #define MenuPostCallback(w) XmField(w,ipot,DtComboBox,menu_post_callback,XtCallbackList)
261 #define Orientation(w) XmField(w,ipot,DtComboBox,orientation,unsigned char)
262 #define PoppedUp(w) XmField(w,ipot,DtComboBox,popped_up,Boolean)
263 #define RecomputeSize(w) XmField(w,ipot,DtComboBox,recompute_size,Boolean)
264 #define Text(w) XmField(w,ipot,DtComboBox,text,Widget)
265 #define TopItemPosition(w) XmField(w,ipot,DtComboBox,top_item_position,int)
266 #define UpdateLabel(w) XmField(w,ipot,DtComboBox,update_label,Boolean)
267 #define VerticalSpacing(w) XmField(w,ipot,DtComboBox,vertical_spacing,Dimension)
268 #define VisibleItemCount(w) XmField(w,ipot,DtComboBox,visible_item_count,int)
269
270 /*
271  * DtComboBoxWidget specific defines.
272  */
273 #define PUnitType(w)        w->primitive.unit_type
274 #define ShellPoppedUp(w)    w->shell.popped_up
275 #define MUnitType(w)        w->manager.unit_type
276 #define COMBO_SHADOW(w)     w->manager.shadow_thickness
277 #define LayoutDirection(w)  w->manager.string_direction
278 #define NavigationType(w)   w->manager.navigation_type
279 #define TraversalOn(w)      w->manager.traversal_on
280 #define BackgroundGC(w)     w->manager.background_GC
281 #define HighlightGC(w)      w->manager.highlight_GC
282 #define TopShadowGC(w)      w->manager.top_shadow_GC
283 #define BottomShadowGC(w)   w->manager.bottom_shadow_GC
284 #define BackgroundPixel(w)  w->core.background_pixel
285 #define X(w)                w->core.x
286 #define Y(w)                w->core.y
287 #define Width(w)            w->core.width
288 #define Height(w)           w->core.height
289 #define BorderWidth(w)      w->core.border_width
290 #define Sensitive(w)        w->core.sensitive
291 #define AncestorSensitive(w)    w->core.ancestor_sensitive
292 #define Parent(w)           w->core.parent
293 #define COMBO_MARGIN_W(w)   MarginWidth(w)
294 #define COMBO_MARGIN_H(w)   MarginHeight(w)
295 #define COMBO_H_SPACING(w)  HorizontalSpacing(w)
296 #define COMBO_V_SPACING(w)  VerticalSpacing(w)
297
298 #define GRAB_POINTER        1 << 0
299 #define GRAB_KEYBOARD       1 << 1
300
301 #define DtNonePopup         0
302 #define DtPopup             1 << 0
303 #define DtButtonPressPopup  1 << 1
304 #define DtKeyPressPopup     1 << 2
305
306 #define LIST_EVENTS         (ButtonReleaseMask | FocusChangeMask | EnterWindowMask)
307 #define SHELL_EVENTS        (ButtonPressMask | ButtonReleaseMask)
308 #define INVALID_DIMENSION   (0xFFFF)
309
310
311 static char ComboBoxTranslationTable[] = "\
312         <FocusIn>:           ComboBoxFocusIn() \n\
313         <FocusOut>:          ComboBoxFocusOut() \n\
314         <Key>osfDown:        ComboBoxActivate() \n\
315         <Btn1Down>:          ComboBoxActivate() \n\
316         <Key>osfSelect:      ComboBoxActivate() \n\
317         ~s ~m ~a <Key>space: ComboBoxActivate() \n\
318 ";
319
320 static char ComboBoxLabelTranslationTable[] = "\
321         <Key>osfDown:        ComboBoxActivate(label) \n\
322         <Btn1Down>:          ComboBoxActivate(label) \n\
323         <Key>osfSelect:      ComboBoxActivate(label) \n\
324         ~s ~m ~a <Key>space: ComboBoxActivate(label) \n\
325 ";
326
327 /* Keyboard Only Traversing During Editable-Mode */
328 static char ComboBoxTextTranslationTable[] = "\
329         <Key>osfUp:          ComboBoxActivate(label) \n\
330         <Key>osfDown:        ComboBoxActivate(label) \n\
331 ";
332
333 static char ComboBoxButtonTranslationTable[] = "\
334         <Key>osfDown:        ComboBoxActivate(label) \n\
335         <Btn1Down>:          ComboBoxActivate(label) \n\
336         ~s ~m ~a <Key>space: ComboBoxActivate(label) \n\
337         s ~m ~a <Key>Tab:    ComboBoxPrevTabGroup()\n\
338         ~m ~a <Key>Tab:      ComboBoxNextTabGroup()\n\
339 ";
340
341 static char ComboBoxListTranslationTable[] = "\
342         <Key>osfCancel:      ListKbdCancel() ComboBoxKbdCancel() \n\
343 ";
344
345 static XtActionsRec ComboBoxActionTable[] = {
346        {"ComboBoxFocusIn",   (XtActionProc)_ComboBoxFocusIn},
347        {"ComboBoxFocusOut",  (XtActionProc)_ComboBoxFocusOut},
348        {"ComboBoxActivate",  (XtActionProc)_ComboBoxActivate},
349        {"ComboBoxKbdCancel", (XtActionProc)_ComboBoxKbdCancel},
350        {"ComboBoxPrevTabGroup", (XtActionProc)_ComboBoxPrevTabGroup},
351        {"ComboBoxNextTabGroup", (XtActionProc)_ComboBoxNextTabGroup},
352 };
353
354
355 /* 
356  * DtComboBoxWidget resources 
357  */
358 #define offset(field) XtOffset(DtComboBoxWidget, field)
359 #define DtOffset(field) XmPartOffset(DtComboBox,field)
360 static XmPartResource resources[] = {
361     {XmNshadowThickness, XmCShadowThickness, XmRHorizontalDimension, 
362          sizeof(Dimension), offset(manager.shadow_thickness),
363          XmRImmediate, (XtPointer)TEXT_FIELD_SHADOW},
364
365     /* 
366      * ComboBox specific resources
367      */
368     {DtNactivateCallback, DtCCallback, XmRCallback, sizeof(XtCallbackList),
369          DtOffset(activate_callback), XmRCallback, 
370          (XtPointer)NULL},
371     {DtNalignment, DtCAlignment, XmRAlignment, sizeof(unsigned char),
372          DtOffset(alignment), XmRImmediate, 
373          (XtPointer)DtALIGNMENT_END},
374     {DtNarrowSpacing, DtCArrowSpacing, XmRHorizontalDimension,
375          sizeof(Dimension), DtOffset(arrow_spacing),
376          XmRImmediate, (XtPointer)0},
377     {DtNarrowType, DtCArrowType, DtRArrowType, sizeof(unsigned char),
378          DtOffset(arrow_type), XmRImmediate, (XtPointer)DtMOTIF},
379     {DtNcolumns, DtCColumns, XmRShort, sizeof(short),
380          DtOffset(text_columns), XmRImmediate, (XtPointer)20},
381     {DtNfocusCallback, DtCCallback, XmRCallback, sizeof(XtCallbackList),
382          DtOffset(focus_callback), XmRCallback, 
383          (XtPointer)NULL},
384     {DtNhorizontalSpacing, DtCHorizontalSpacing, XmRHorizontalDimension,
385          sizeof(Dimension), DtOffset(horizontal_spacing),
386          XmRImmediate, (XtPointer)INVALID_DIMENSION},
387     {DtNitemCount, DtCItemCount, XmRInt, sizeof(int), 
388          DtOffset(item_count), XmRImmediate, (XtPointer)0},
389     /*
390      * items is used only for seeing if the user changed the list.  It
391      * is only a pointer that reflects the current list's items.
392      */
393     {DtNitems, DtCItems, XmRXmStringTable, sizeof(XmStringTable),
394          DtOffset(items), XmRImmediate, (XtPointer)NULL},
395     {DtNlabelString, DtCXmString, XmRXmString, sizeof(XmString),
396          DtOffset(label_string), XmRImmediate, (XtPointer)NULL},
397     {DtNlist, DtCList, XmRWidget, sizeof(Widget),
398          DtOffset(list), XmRImmediate, (XtPointer)NULL},
399     {DtNlistFontList, DtCListFontList, XmRFontList, sizeof(XmFontList), 
400          DtOffset(list_font_list), XmRImmediate, (XtPointer)NULL},
401     {DtNlistMarginHeight, DtCListMarginHeight, XmRVerticalDimension, 
402          sizeof(Dimension), DtOffset(list_margin_height),
403          XmRImmediate, (XtPointer)MARGIN},
404     {DtNlistMarginWidth, DtCListMarginWidth, XmRHorizontalDimension,
405          sizeof(Dimension), DtOffset(list_margin_width),
406          XmRImmediate, (XtPointer)MARGIN},
407     {DtNlistSpacing, DtCListSpacing, XmRVerticalDimension,sizeof(Dimension), 
408          DtOffset(list_spacing), XmRImmediate, (XtPointer)0},
409     {DtNlosingFocusCallback, DtCCallback, XmRCallback, sizeof(XtCallbackList),
410          DtOffset(losing_focus_callback), XmRCallback, 
411          (XtPointer)NULL},
412     {DtNmarginHeight, DtCMarginHeight, XmRVerticalDimension,
413          sizeof(Dimension), DtOffset(margin_height),
414          XmRImmediate, (XtPointer)MARGIN},
415     {DtNmarginWidth, DtCMarginWidth, XmRHorizontalDimension, sizeof(Dimension),
416          DtOffset(margin_width), XmRImmediate, (XtPointer)MARGIN},
417     {DtNmaxLength, DtCMaxLength, XmRInt, sizeof(unsigned int),
418          DtOffset(text_max_length), XmRImmediate, (XtPointer)INT_MAX},
419     {DtNmenuPostCallback, DtCCallback, XmRCallback, sizeof(XtCallbackList),
420          DtOffset(menu_post_callback), XmRCallback, (XtPointer)NULL},
421     {DtNorientation, DtCOrientation, XmROrientation, sizeof(unsigned char),
422          DtOffset(orientation), XmRImmediate, (XtPointer)DtRIGHT},
423     {DtNpoppedUp, DtCPoppedUp, XmRBoolean, sizeof(Boolean),
424          DtOffset(popped_up), XmRImmediate, (XtPointer)FALSE},
425     {DtNrecomputeSize, DtCRecomputeSize, XmRBoolean, sizeof(Boolean),
426          DtOffset(recompute_size), XmRImmediate, (XtPointer)TRUE},
427     {DtNselectedItem, DtCXmString, XmRXmString, sizeof(XmString),
428          DtOffset(selected_item), XmRImmediate, (XtPointer)NULL},
429     {DtNselectedPosition, DtCSelectedPosition, XmRInt, sizeof(int),
430          DtOffset(selected_position), XmRImmediate, (XtPointer)0},
431     {DtNselectionCallback, DtCCallback, XmRCallback, sizeof(XtCallbackList),
432          DtOffset(selection_callback), XmRCallback, (XtPointer)NULL},
433     {DtNtextField, DtCTextField, XmRWidget, sizeof(Widget),
434          DtOffset(text), XmRImmediate, (XtPointer)NULL},
435     {DtNtopItemPosition, DtCTopItemPosition, XmRInt, sizeof(int), 
436          DtOffset(top_item_position), XmRImmediate, (XtPointer)1},
437     {DtNcomboBoxType, DtCComboBoxType, DtRComboBoxType, sizeof(unsigned char),
438          DtOffset(type), XmRImmediate,(XtPointer)DtDROP_DOWN_LIST},
439     {DtNupdateLabel, DtCUpdateLabel, XmRBoolean, sizeof(Boolean),
440          DtOffset(update_label), XmRImmediate, (XtPointer)TRUE},
441     {DtNvisibleItemCount, DtCVisibleItemCount, XmRInt, sizeof(int),
442          DtOffset(visible_item_count), XmRImmediate, (XtPointer)10},
443     {DtNverticalSpacing, DtCVerticalSpacing, XmRVerticalDimension,
444          sizeof(Dimension), DtOffset(vertical_spacing),
445          XmRImmediate, (XtPointer)INVALID_DIMENSION},
446 };
447
448 /*
449  * List resources (used for GetValues).
450  */
451 static XmSyntheticResource syn_resources[] = {
452     {DtNarrowSpacing, sizeof(Dimension), DtOffset(arrow_spacing), 
453          XmeFromHorizontalPixels, XmeToHorizontalPixels},
454     {DtNhorizontalSpacing, sizeof(Dimension), DtOffset(horizontal_spacing), 
455          XmeFromHorizontalPixels, XmeToHorizontalPixels},
456     {DtNverticalSpacing, sizeof(Dimension), DtOffset(vertical_spacing), 
457          XmeFromVerticalPixels, XmeToVerticalPixels},
458     {DtNmarginWidth, sizeof(Dimension), DtOffset(margin_width), 
459          XmeFromHorizontalPixels, XmeToHorizontalPixels},
460     {DtNmarginHeight, sizeof(Dimension), DtOffset(margin_height), 
461          XmeFromVerticalPixels, XmeToVerticalPixels},
462     {DtNarrowSize, sizeof(Dimension), DtOffset(arrow_size), 
463          _DtComboBoxGetArrowSize, XmeToHorizontalPixels},
464     {DtNlabelString, sizeof(XmString), DtOffset(label_string), 
465          _DtComboBoxGetLabelString, _XmSetSyntheticResForChild},
466     {DtNitemCount, sizeof(int), DtOffset(item_count), 
467          _DtComboBoxGetListItemCount, _XmSetSyntheticResForChild},
468     {DtNitems, sizeof(XmStringTable), DtOffset(items), 
469          _DtComboBoxGetListItems, _XmSetSyntheticResForChild},
470     {DtNlistFontList, sizeof(XmFontList), DtOffset(list_font_list), 
471          _DtComboBoxGetListFontList, _XmSetSyntheticResForChild},
472     {DtNlistMarginHeight, sizeof(Dimension), 
473          DtOffset(list_margin_height),
474          _DtComboBoxGetListMarginHeight, XmeToVerticalPixels},
475     {DtNlistMarginWidth, sizeof(Dimension),DtOffset(list_margin_width),
476          _DtComboBoxGetListMarginWidth, XmeToHorizontalPixels},
477     {DtNlistSpacing, sizeof(Dimension), DtOffset(list_spacing),
478          _DtComboBoxGetListSpacing, XmeToVerticalPixels},
479     {DtNtopItemPosition, sizeof(int), DtOffset(top_item_position),
480          _DtComboBoxGetListTopItemPosition, _XmSetSyntheticResForChild},
481     {DtNvisibleItemCount, sizeof(int), DtOffset(visible_item_count),
482          _DtComboBoxGetListVisibleItemCount, _XmSetSyntheticResForChild},
483 };
484 #undef DtOffset
485 #undef offset
486
487 /* Need Class Extension for widget navigation */
488 static XmBaseClassExtRec baseClassExtRec = {
489     NULL,
490     NULLQUARK,
491     XmBaseClassExtVersion,
492     sizeof(XmBaseClassExtRec),
493     (XtInitProc)NULL,                   /* InitializePrehook    */
494     (XtSetValuesFunc)NULL,              /* SetValuesPrehook     */
495     (XtInitProc)NULL,                   /* InitializePosthook   */
496     (XtSetValuesFunc)NULL,              /* SetValuesPosthook    */
497     NULL,                               /* secondaryObjectClass */
498     (XtInitProc)NULL,                   /* secondaryCreate      */
499     (XmGetSecResDataFunc)NULL,          /* getSecRes data       */
500     { 0 },                              /* fastSubclass flags   */
501     (XtArgsProc)NULL,                   /* getValuesPrehook     */
502     (XtArgsProc)NULL,                   /* getValuesPosthook    */
503     (XtWidgetClassProc)NULL,            /* classPartInitPrehook */
504     (XtWidgetClassProc)NULL,            /* classPartInitPosthook*/
505     NULL,                               /* ext_resources        */
506     NULL,                               /* compiled_ext_resources*/
507     0,                                  /* num_ext_resources    */
508     FALSE,                              /* use_sub_resources    */
509     (XmWidgetNavigableProc)WidgetNavigable,
510                                         /* widgetNavigable      */
511     (XmFocusChangeProc)NULL,            /* focusChange          */
512     (XmWrapperData)NULL                 /* wrapperData          */
513 };
514
515 /*
516  * Define Class Record.
517  */
518 externaldef(dtcomboBoxclassrec) DtComboBoxClassRec dtComboBoxClassRec =
519 {
520     {           /* core_class fields      */
521     (WidgetClass)&(xmManagerClassRec),          /* superclass         */    
522     (String)"DtComboBox",                       /* class_name         */    
523     (Cardinal)sizeof(DtComboBoxPart),           /* widget_size        */    
524     (XtProc)ClassInitialize,                    /* class_initialize   */    
525     (XtWidgetClassProc)NULL,                    /* class_part_init    */    
526     (XtEnum)FALSE,                              /* class_inited       */    
527     (XtInitProc)Initialize,                     /* initialize         */    
528     (XtArgsProc)NULL,                           /* initialize_hook    */    
529     (XtRealizeProc)XtInheritRealize,            /* realize            */    
530     (XtActionList)ComboBoxActionTable,          /* actions             */    
531     (Cardinal)XtNumber(ComboBoxActionTable),    /* num_actions        */    
532     (XtResourceList)resources,                  /* resources          */    
533     (Cardinal)XtNumber(resources),              /* num_resources      */    
534     (XrmClass)NULLQUARK,                        /* xrm_class          */    
535     (Boolean)TRUE,                              /* compress_motion    */    
536     (XtEnum)XtExposeCompressMaximal,            /* compress_exposure  */    
537     (Boolean)TRUE,                              /* compress_enterleave*/    
538     (Boolean)FALSE,                             /* visible_interest   */    
539     (XtWidgetProc)Destroy,                      /* destroy            */    
540     (XtWidgetProc)Resize,                       /* resize             */    
541     (XtExposeProc)Redisplay,                    /* expose             */    
542     (XtSetValuesFunc)SetValues,                 /* set_values         */    
543     (XtArgsFunc)NULL,                           /* set values hook    */    
544     (XtAlmostProc)XtInheritSetValuesAlmost,     /* set values almost  */    
545     (XtArgsProc)NULL,                           /* get values hook    */    
546     (XtAcceptFocusProc)NULL,                    /* accept_focus       */    
547     (XtVersionType)XtVersionDontCheck,          /* Version            */    
548     (XtPointer)NULL,                            /* PRIVATE cb list    */
549     (String)XtInheritTranslations,              /* tm_table           */
550     (XtGeometryHandler)XtInheritQueryGeometry,  /* query_geom         */
551     (XtStringProc)XtInheritDisplayAccelerator,  /* display_accelerator*/
552     (XtPointer)&baseClassExtRec                 /* extension          */
553     },
554     {           /* composite_class fields */
555     (XtGeometryHandler)GeometryManager,         /* geometry_manager   */     
556     (XtWidgetProc)XtInheritChangeManaged,       /* change_managed     */     
557     (XtWidgetProc)XtInheritInsertChild,         /* insert_child       */     
558     (XtWidgetProc)XtInheritDeleteChild,         /* delete_child       */     
559     (XtPointer)NULL                             /* extension          */     
560     },
561     {           /* constraint_class fields */
562     (XtResourceList)NULL,                       /* resources          */     
563     (Cardinal)0,                                /* num_resources      */     
564     (Cardinal)0,                                /* constraint_size    */     
565     (XtInitProc)NULL,                           /* initialize         */     
566     (XtWidgetProc)NULL,                         /* destroy            */     
567     (XtSetValuesFunc)NULL,                      /* set_values         */     
568     (XtPointer)NULL                             /* extension          */     
569     },
570     {           /* manager class     */
571     (String)XtInheritTranslations,              /* translations       */     
572     (XmSyntheticResource*)syn_resources,        /* syn resources      */     
573     (int)XtNumber(syn_resources),               /* num syn_resources  */     
574     (XmSyntheticResource*)NULL,                 /* get_cont_resources */     
575     (int)0,                                     /* num_get_cont_resources */ 
576     (XmParentProcessProc)XmInheritParentProcess,/* parent_process     */     
577     (XtPointer)NULL                             /* extension          */     
578     },
579     {           /* combo_box_class fields */     
580     (Boolean)0,
581     }
582 };
583
584 externaldef(dtcomboBoxwidgetclass) WidgetClass dtComboBoxWidgetClass =
585                                         (WidgetClass)&dtComboBoxClassRec;
586 /* Parse the translation tables only once for the whole class
587  */
588 static XtTranslations trans;
589 static XtTranslations list_trans; 
590 static XtTranslations label_trans; 
591 static XtTranslations text_trans; 
592 static XtTranslations button_trans; 
593
594 /* 
595  * Must set up the record type for the class extensions to work.
596  */
597 static void
598 ClassInitialize(void)
599 {
600     baseClassExtRec.record_type = XmQmotif;
601 /*
602  * MotifBc
603  */
604     XmResolveAllPartOffsets(dtComboBoxWidgetClass, &ipot, &cpot);
605 /* Parse the translation tables here
606  */
607     trans =       XtParseTranslationTable(ComboBoxTranslationTable);
608     list_trans =  XtParseTranslationTable(ComboBoxListTranslationTable);
609     label_trans = XtParseTranslationTable(ComboBoxLabelTranslationTable);
610     text_trans =  XtParseTranslationTable(ComboBoxTextTranslationTable);
611     button_trans =XtParseTranslationTable(ComboBoxButtonTranslationTable);
612
613 /* Add a type converter for String to DtRComboBoxType
614  */
615     XtSetTypeConverter("String","ComboBoxType", _CvtStringToType, NULL, 0, 
616         XtCacheAll, NULL);
617
618     InitLabel = XmStringCreateLocalized(CB_LABEL);
619 }
620
621 /*
622  * ComboBox initialization function.  This builds the widgets inside
623  * our widget, to get the correct layout.  If the type resource
624  * is DtDROP_DOWN_COMBO_BOX, we create a textField; if FALSE, we create a
625  * label.  If the user changes this resource later, we will create the
626  * other widget (textField or Label).  We don't want to carry backage from
627  * both widgets if the user never changes the type resource.
628  */
629 static void
630 Initialize(     DtComboBoxWidget request,
631                 DtComboBoxWidget new,
632                 ArgList given_args,
633                 Cardinal *num_args)
634 {
635    /* use the address of the first element of DtComboBoxPart structure 
636     * as of DtComboBoxPart 
637     */    
638     DtComboBoxPart *combo_p = (DtComboBoxPart*)
639         &(XmField(new,ipot,DtComboBox,arrow,Widget)); 
640     Boolean force_label_string = FALSE;
641     Arg args[15];
642     int n;
643     /* Resolution Independent */
644     unsigned char unit_type = MUnitType(new);
645
646     /* Overwrite the manager's focusIn and focusOut translations */
647     XtOverrideTranslations((Widget)new, trans);
648
649
650     /* 
651      * force_label_string usage if it is specified and items is not.
652      * This will be the perminant label string only if update-label
653      * is false, else it is only used until the user picks something
654      * new off the list.
655      */
656     if (LabelString(new) == NULL)
657         LabelString(new) = InitLabel;
658     else if (!Items(new))
659         force_label_string = TRUE;
660
661     /* Copy given label-string. */
662     if (LabelString(new))
663         LabelString(new) = XmStringCopy(LabelString(new));
664
665     Text(new) = (Widget)NULL;
666     Label(new) = (Widget)NULL;
667     Sep(new) = (Widget)NULL;
668     OldWidth(new) = 0;
669     OldHeight(new) = 0;
670
671     CheckResources(new);
672
673     /*
674      * Create the text or label depending on the type resource.
675      * When part of X-Designer, we create both at initialization to
676      * avoid later crashes.
677      */
678     if (Type(new) == DtDROP_DOWN_COMBO_BOX)
679     {
680         n = 0;
681         XtSetArg(args[n], XmNcolumns, TextColumns(new)); n++;
682         XtSetArg(args[n], XmNmaxLength, TextMaxLength(new)); n++;
683         XtSetArg(args[n], XmNmarginWidth, TEXT_CONTEXT_MARGIN); n++;
684         XtSetArg(args[n], XmNmarginHeight, 2); n++;
685         /* Resolution Independent */
686         if (unit_type != XmPIXELS) {
687                 XtSetArg(args[n], XmNunitType, XmPIXELS); n++;
688         }
689         Text(new) = XtCreateManagedWidget("Text", 
690                                               xmTextFieldWidgetClass,
691                                               (Widget)new, args, n);
692         XtAddCallback(Text(new), XmNlosingFocusCallback, 
693                       text_losing_focus_cb, (XtPointer)new);
694         XtAddCallback(Text(new), XmNactivateCallback, 
695                       text_activate_cb, (XtPointer)new);
696         XtAddCallback(Text(new), XmNfocusCallback, 
697                       text_focus_cb, (XtPointer)new);
698
699         XtOverrideTranslations(Text(new), text_trans);
700
701         if (HorizontalSpacing(new) == INVALID_DIMENSION)
702             HorizontalSpacing(new) = 0;
703         if (VerticalSpacing(new) == INVALID_DIMENSION)
704             VerticalSpacing(new) = 0;
705         if (unit_type != XmPIXELS) {
706                 XtSetArg(args[0], XmNunitType, unit_type);
707                 XtSetValues(Text(new), args, 1);
708         }                
709     }
710     else
711     {
712         XmStringDirection new_direction = 
713           XmDirectionToStringDirection(LayoutDirection(new));
714
715         COMBO_SHADOW(new) = LABEL_SHADOW;
716         n = 0;
717         XtSetArg(args[n], XmNalignment, Alignment(new)); n++;
718         XtSetArg(args[n], XmNrecomputeSize, FALSE); n++;
719         XtSetArg(args[n], XmNlabelString, InitLabel); n++;
720         XtSetArg(args[n], XmNmarginLeft, LABEL_PADDING); n++;
721         XtSetArg(args[n], XmNmarginRight, LABEL_PADDING); n++;
722         XtSetArg(args[n], XmNmarginWidth, TEXT_CONTEXT_MARGIN); n++;
723         XtSetArg(args[n], XmNmarginHeight, 0); n++;
724         XtSetArg(args[n], XmNstringDirection, new_direction); n++;
725         /* Resolution Independent */
726         if (unit_type != XmPIXELS) {
727                 XtSetArg(args[n], XmNunitType, XmPIXELS); n++;
728         }
729         Label(new) = XtCreateManagedWidget("Label", 
730                                                xmLabelWidgetClass,
731                                                (Widget)new, args, n);
732         XtOverrideTranslations(Label(new), label_trans);
733         if (HorizontalSpacing(new) == INVALID_DIMENSION)
734             HorizontalSpacing(new) = 1;
735         if (VerticalSpacing(new) == INVALID_DIMENSION)
736             VerticalSpacing(new) = 2;
737         if (unit_type != XmPIXELS) {
738                 XtSetArg(args[0], XmNunitType, unit_type);
739                 XtSetValues(Label(new), args, 1);
740         }                
741     }
742
743     /*
744      * Create the separator used if non-editable combo-box.
745      */
746     if (Type(new) == DtDROP_DOWN_LIST) 
747     {
748         n = 0;
749         XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
750         /* Resolution Independent */
751         if (unit_type != XmPIXELS) {
752                 XtSetArg(args[n], XmNunitType, XmPIXELS); n++;
753         }
754         Sep(new) = XtCreateManagedWidget("ComboBoxSeparator", 
755                                              xmSeparatorWidgetClass,
756                                              (Widget)new, args, n);
757
758         XtOverrideTranslations((Widget)Sep(new), button_trans);
759         if (unit_type != XmPIXELS) {
760                 XtSetArg(args[0], XmNunitType, unit_type);
761                 XtSetValues(Sep(new), args, 1);
762         }                
763     }
764
765     /*
766      * Create the ArrowWidget.
767      */
768     n = 0;
769     XtSetArg(args[n], XmNtraversalOn, FALSE); n++;
770     XtSetArg(args[n], XmNhighlightThickness, 0); n++;
771     XtSetArg(args[n], XmNshadowThickness, 0); n++;
772     if (ArrowType(new) == DtMOTIF) {
773         XtSetArg(args[n], XmNarrowDirection, XmARROW_DOWN); n++;
774         XtSetArg(args[n], XmNforeground, BackgroundPixel(new)); n++;
775         Arrow(new) = XtCreateManagedWidget("ComboBoxArrow", 
776                                                xmArrowButtonWidgetClass,
777                                                (Widget)new, args, n);
778     }
779     else {
780         Arrow(new) = XtCreateManagedWidget("ComboBoxArrow", 
781                                                xmDrawnButtonWidgetClass,
782                                                (Widget)new, args, n);
783         XtAddCallback(Arrow(new), XmNexposeCallback, arrow_expose_cb, 
784                       (XtPointer)new);
785     }
786     XtAddCallback(Arrow(new), XmNactivateCallback, activate_cb, 
787                   (XtPointer)new);
788
789     XtOverrideTranslations((Widget)Arrow(new), button_trans); 
790
791     /*
792      *  Create the shell and associated list widgets.
793      */
794     n = 0;
795     XtSetArg(args[n], XtNoverrideRedirect, TRUE); n++;
796     XtSetArg(args[n], XtNallowShellResize, TRUE); n++;
797     XtSetArg(args[n], XtNsaveUnder, TRUE); n++;
798     Shell(new) = XtCreatePopupShell("ComboBoxMenuShell", 
799                                         topLevelShellWidgetClass, 
800                                         (Widget)new, args, n);
801     
802     n = 0;
803     Frame(new) = XtCreateManagedWidget("ComboBoxRowColumn",
804                                            xmFrameWidgetClass,
805                                            Shell(new), args, n);
806
807     n = 0;
808     /* Store combo widget in list for later use */
809     XtSetArg(args[n], XmNuserData, (XtPointer)new); n++;
810     if (ListFontList(new)) {
811         XtSetArg(args[n], XmNfontList, ListFontList(new)); n++;
812     }
813     /* to disable double click */
814     XtSetArg(args[n], XmNdoubleClickInterval, 0); n++;
815     XtSetArg(args[n], XmNitemCount, ItemCount(new)); n++;
816     XtSetArg(args[n], XmNitems, Items(new)); n++;
817     XtSetArg(args[n], XmNlistMarginHeight, ListMarginHeight(new)); n++;
818     XtSetArg(args[n], XmNlistMarginWidth, ListMarginWidth(new)); n++;
819     XtSetArg(args[n], XmNlistSpacing, ListSpacing(new)); n++;
820     {
821       XmStringDirection new_direction =
822         XmDirectionToStringDirection(LayoutDirection(new));
823       XtSetArg(args[n], XmNstringDirection, new_direction); n++;
824     }
825     XtSetArg(args[n], XmNtopItemPosition, TopItemPosition(new)); n++;
826     XtSetArg(args[n], XmNvisibleItemCount, VisibleItemCount(new)); n++;
827     XtSetArg(args[n], XmNlistSizePolicy, XmRESIZE_IF_POSSIBLE); n++;
828     XtSetArg(args[n], XmNselectionPolicy, XmBROWSE_SELECT); n++;
829     /* Resolution Independent */
830     if (unit_type != XmPIXELS) {
831         XtSetArg(args[n], XmNunitType, XmPIXELS); n++;
832     }
833     List(new) = XmCreateScrolledList(Frame(new), "List", args, n);
834     XtOverrideTranslations((Widget)List(new), list_trans);
835
836     n = 0;
837     XtSetArg(args[n], XmNshadowThickness, (XtArgVal) 0); n++;
838     XtSetValues(XtParent(List(new)), args, n);
839
840     /* selected_item resource used before selected_position */
841     if (SelectedItem(new) && XmeStringIsValid(SelectedItem(new)) ) {
842         SelectedItem(new) =XmStringCopy(SelectedItem(new));
843         DtComboBoxSelectItem((Widget)new, SelectedItem(new));
844     }
845     else {
846         SelectedItem(new) = (XmString) NULL;
847         if (SelectedPosition(new)<0 || SelectedPosition(new)>=ItemCount(new))
848             SelectedPosition(new) = 0;
849         if ( ItemCount(new))
850             XmListSelectPos(List(new), SelectedPosition(new) + 1, FALSE);
851     }
852     if (unit_type != XmPIXELS) {
853             XtSetArg(args[0], XmNunitType, unit_type);
854             XtSetValues(List(new), args, 1);
855     }                
856
857     SyncWithList(combo_p);
858     XtManageChild(List(new));
859     XtRealizeWidget(Shell(new));
860
861     MaxShellWidth(new) = Width(((Widget) Shell(new)));
862     MaxShellHeight(new) = Height(((Widget) Shell(new)));
863
864     XtAddCallback(List(new), XmNdefaultActionCallback, select_cb, new);
865     XtAddCallback(List(new), XmNbrowseSelectionCallback, select_cb, new);
866
867     /*
868      * Set up event handlers needed for handling grab states.
869      */
870     XtInsertEventHandler(List(new), LIST_EVENTS, TRUE,
871                          (XtEventHandler)list_event_handler, 
872                          (XtPointer)new, XtListHead);
873     XtInsertEventHandler(Shell(new), SHELL_EVENTS, TRUE,
874                          (XtEventHandler)shell_event_handler, 
875                          (XtPointer)new, XtListHead);
876
877     /*
878      * Set initial value in text or label if items was specified
879      */
880     if (Type(new) == DtDROP_DOWN_LIST) {
881         SetMaximumLabelSize(combo_p);
882         SetLabelData(combo_p, NULL, force_label_string);
883     }
884     else
885         SetTextFieldData(combo_p, NULL);
886
887     SetComboBoxSize(new);
888     LayoutChildren(new);
889 }
890
891
892 /*
893  * Allow the manager to gain focus if not editable.  If editable (using
894  * text-field), then let the toolkit give focus to the text-field.
895  */
896 static XmNavigability
897 WidgetNavigable(DtComboBoxWidget combo)
898 {   
899     XmNavigationType nav_type = NavigationType(((XmManagerWidget)combo));
900
901     if (Sensitive(combo) &&  AncestorSensitive(combo) &&
902         TraversalOn(((XmManagerWidget)combo))) {
903         if ((nav_type == XmSTICKY_TAB_GROUP) ||
904             (nav_type == XmEXCLUSIVE_TAB_GROUP) ||
905             ((nav_type == XmTAB_GROUP) && 
906              !_XmShellIsExclusive((Widget)combo))) {
907             if (Type(combo) == DtDROP_DOWN_COMBO_BOX)
908                 return(XmDESCENDANTS_TAB_NAVIGABLE);
909             else
910                 return(XmTAB_NAVIGABLE);
911         }
912         return(XmDESCENDANTS_NAVIGABLE);
913     }
914     return(XmNOT_NAVIGABLE);
915 }
916
917 /* 
918  * The combo_box gets focus.
919  */
920 static void 
921 _ComboBoxFocusIn(       DtComboBoxWidget combo,
922                         XEvent *event,
923                         char **params,
924                         Cardinal *num_params)
925 {
926     DrawHighlight(combo, FALSE);
927 }
928
929 /* 
930  * The combo_box loses focus. Only happens if not editable.
931  */
932 static void 
933 _ComboBoxFocusOut(      DtComboBoxWidget combo,
934                         XEvent *event,
935                         char **params,
936                         Cardinal *num_params)
937 {
938     DrawHighlight(combo, TRUE);
939 }
940
941 /*
942  * This function gets called whenever we draw or clear the shadow (to
943  * redraw highlight during resize, etc), as well as during focus_in
944  * and focus_out events.
945  */
946 static void
947 DrawHighlight(  DtComboBoxWidget combo,
948                 Boolean clear)
949 {
950     XRectangle rect[4] ;
951
952     if (XtIsRealized((Widget)combo)) {
953         if (clear) {
954             rect[0].x = rect[1].x = rect[2].x = 0;
955             rect[3].x = OldWidth(combo) - COMBO_MARGIN_W(combo);
956             rect[0].y = rect[2].y = rect[3].y = 0 ;
957             rect[1].y = OldHeight(combo) - COMBO_MARGIN_H(combo);
958             rect[0].width = rect[1].width = OldWidth(combo);
959             rect[2].width = rect[3].width = COMBO_MARGIN_W(combo);
960             rect[0].height = rect[1].height = COMBO_MARGIN_H(combo);
961             rect[2].height = rect[3].height = OldHeight(combo);
962             XFillRectangles(XtDisplayOfObject((Widget)combo),
963                             XtWindowOfObject((Widget)combo), 
964                             BackgroundGC(combo), rect, 4);
965         }
966         else if (XmGetFocusWidget((Widget)combo) == (Widget)combo) {
967             rect[0].x = rect[1].x = rect[2].x = 0;
968             rect[3].x = XtWidth(combo) - COMBO_MARGIN_W(combo);
969             rect[0].y = rect[2].y = rect[3].y = 0 ;
970             rect[1].y = XtHeight(combo) - COMBO_MARGIN_H(combo);
971             rect[0].width = rect[1].width = XtWidth(combo);
972             rect[2].width = rect[3].width = COMBO_MARGIN_W(combo);
973             rect[0].height = rect[1].height = COMBO_MARGIN_H(combo);
974             rect[2].height = rect[3].height = XtHeight(combo);
975             XFillRectangles(XtDisplayOfObject((Widget)combo),
976                             XtWindowOfObject((Widget)combo), 
977                             HighlightGC(combo), rect, 4);
978         }
979     }
980 }
981
982 /* Add a global variable to avoid the handler to process the
983  * the ButtonPress which popup the shell
984  */
985 static int popup_shell_init=DtNonePopup;
986
987 /*
988  * osfSelect virtual key hit.  Simulate hitting the arrow.
989  */
990 static void 
991 _ComboBoxActivate(      Widget w,
992                         XEvent *event,
993                         char **params,
994                         Cardinal *num_params)
995 {
996     DtComboBoxWidget combo;
997     XmAnyCallbackStruct cb;
998
999     if (*num_params == 0) /* no params means combo */
1000         combo = (DtComboBoxWidget)w;
1001     else /* params means label */
1002     {
1003         combo = (DtComboBoxWidget)XtParent(w);
1004     }
1005
1006     _DtProcessLock();
1007     if (event->type == KeyPress)
1008         popup_shell_init = DtKeyPressPopup;
1009     else if (event->type == ButtonPress)
1010         popup_shell_init = DtButtonPressPopup;
1011     else
1012         popup_shell_init = DtPopup;
1013     _DtProcessUnlock();
1014
1015     cb.reason = XmCR_ACTIVATE;
1016     cb.event  = event;
1017     activate_cb((Widget)Arrow(combo), (XtPointer)combo, (XtPointer)&cb);
1018 }
1019
1020 /*
1021  * osfCancel virtual key hit.
1022  */
1023 static void 
1024 _ComboBoxKbdCancel(     Widget w,
1025                         XEvent *event,
1026                         char **params,
1027                         Cardinal *num_params)
1028 {
1029     DtComboBoxWidget combo;
1030     XtPointer data;
1031     Arg args[1];
1032
1033     /* Get combo-box off list data */
1034     XtSetArg(args[0], XmNuserData, &data);
1035     XtGetValues(w, args, 1);
1036     
1037     combo = (DtComboBoxWidget)data;
1038
1039     input_ungrab( combo, GRAB_POINTER | GRAB_KEYBOARD );
1040 }
1041
1042 /* #7
1043  * Tab Group Action for Buttons
1044  */
1045 static void 
1046 _ComboBoxPrevTabGroup(  Widget w,
1047                         XEvent *event,
1048                         char **params,
1049                         Cardinal *num_params)
1050 {
1051    XmProcessTraversal ((Widget)XtParent(w), XmTRAVERSE_PREV_TAB_GROUP);
1052 }
1053 static void 
1054 _ComboBoxNextTabGroup(  Widget w,
1055                         XEvent *event,
1056                         char **params,
1057                         Cardinal *num_params)
1058 {
1059    XmProcessTraversal ((Widget)XtParent(w), XmTRAVERSE_NEXT_TAB_GROUP);
1060 }
1061
1062
1063 /*
1064  * This function goes through most of the resources and makes sure 
1065  * they have legal values.
1066  */
1067 static void
1068 CheckResources( DtComboBoxWidget combo)
1069 {
1070     if ((Alignment(combo) != DtALIGNMENT_CENTER) && 
1071         (Alignment(combo) != DtALIGNMENT_BEGINNING) &&
1072         (Alignment(combo) != DtALIGNMENT_END)) {
1073         XtWarning(CB_ALIGNMENT);
1074         Alignment(combo) = DtALIGNMENT_CENTER;
1075     }
1076     if ((Orientation(combo) != DtLEFT) &&
1077         (Orientation(combo) != DtRIGHT)) {
1078         XtWarning(CB_ORIENTATION);
1079         Orientation(combo) = DtRIGHT;
1080     }
1081     if (ItemCount(combo) < 0) {
1082         XtWarning(CB_ITEM_COUNT);
1083         ItemCount(combo) = 0;
1084     }
1085     if ((SelectedPosition(combo) < 0) ||
1086         ((SelectedPosition(combo) >= ItemCount(combo)) && 
1087          (ItemCount(combo) > 0))) {
1088         XtWarning(CB_VISIBLE_ITEM);
1089         SelectedPosition(combo) = 0;
1090     }
1091     /* NEW: to adjust the size of the list to its content *
1092     if (ItemCount(combo) < VisibleItemCount(combo)) 
1093         VisibleItemCount(combo) = ItemCount(combo); */
1094 }
1095
1096 /*
1097  * Destroy procedure called by the toolkit.  Free local resources
1098  */
1099 static void 
1100 Destroy(DtComboBoxWidget combo)
1101 {
1102     if (LabelString(combo))
1103         XmStringFree(LabelString(combo));
1104     if (SelectedItem(combo))
1105         XmStringFree( SelectedItem(combo) );
1106 }
1107
1108 /*
1109  * Resize function called by toolkit.  The size of our combo-box
1110  * has already been changed.  That is why we must store 
1111  * old_width and old_height.
1112  */
1113 static void
1114 Resize(DtComboBoxWidget combo)
1115 {
1116     ClearShadow(combo, TRUE);
1117     LayoutChildren(combo);
1118     DrawShadow(combo);
1119     OldWidth(combo) = Width(combo);
1120     OldHeight(combo) = Height(combo);
1121 }
1122
1123
1124 /*
1125  * Redisplay function called by toolkit. The widget didn't change size, 
1126  * so just redisplay the shadow.
1127  */
1128 static void
1129 Redisplay(      DtComboBoxWidget w,
1130                 XEvent *event,
1131                 Region region)
1132 {
1133     DrawShadow(w);
1134 }
1135
1136
1137 /*
1138  * GeometryManager function called by toolkit when a child resizes/moves.
1139  * We are not allowing any changes but width/height of the text-field.
1140  * this is because the user can retrieve the text-field and make changes
1141  * that we want to honor.  If they mess around with the label or arrow,
1142  * then we won't honor the request.
1143  * If the text-field requests a change, then make the change, and allow
1144  * our SetComboBoxSize() and LayoutChildren() figure out what size will
1145  * be allowed.  
1146  * Returning GeometryDone was suppose to tell the toolkit
1147  * that we resized the child ourselves, but the text-field had trouble
1148  * with this (its' geometry_manager wasn't called or working right?), so
1149  * we return GeometryYes.
1150  */
1151 static XtGeometryResult
1152 GeometryManager(Widget w,
1153                 XtWidgetGeometry *request,
1154                 XtWidgetGeometry *reply)
1155 {
1156     DtComboBoxWidget combo = (DtComboBoxWidget) Parent(w);
1157
1158     /* Ignore everything but text-field */
1159     if (w != Text(combo))
1160         return(XtGeometryNo);
1161
1162     /* Only allow width/height changes */
1163     if (!(request->request_mode & (CWWidth | CWHeight)))
1164         return(XtGeometryNo);
1165     
1166     /* Set the text-field to the requested size */
1167     if (request->request_mode & CWWidth)
1168         Width(w) = request->width;
1169     if (request->request_mode & CWHeight)
1170         Height(w) = request->height;
1171     XtResizeWidget(w, Width(w), Height(w), BorderWidth(w));
1172     
1173     ClearShadow(combo, TRUE);
1174     if (RecomputeSize(combo))
1175         SetComboBoxSize(combo);
1176     LayoutChildren(combo);
1177     DrawShadow(combo);
1178     return(XtGeometryYes);
1179 }
1180
1181 /* 
1182  * This function sets the size of the combo_box widget based on the
1183  * current size of the children.  Don't worry if it doesn't work, the
1184  * children will be squeezed in later.
1185  */
1186 static void
1187 SetComboBoxSize(DtComboBoxWidget combo)
1188 {
1189     Widget text_holder = ((Type(combo) == DtDROP_DOWN_COMBO_BOX) ? 
1190                           Text(combo) : Label(combo));
1191     Dimension shadow = COMBO_SHADOW(combo) * 2;
1192     Dimension h_spacing = COMBO_H_SPACING(combo) * 2;
1193     Dimension v_spacing = COMBO_V_SPACING(combo) * 2;
1194     Dimension arrow_width, text_width, text_height;
1195     Dimension sep_width = 0;
1196         XtGeometryResult ResizeResult;
1197     Arg args[3];
1198     unsigned char unit_type = XmPIXELS;
1199
1200     /* Resolution Independent */
1201     if (MUnitType(combo) != XmPIXELS) {
1202         unit_type = MUnitType(combo);
1203         XtSetArg(args[0], XmNunitType, XmPIXELS);
1204         XtSetValues(text_holder, args, 1);
1205         if (Type(combo) == DtDROP_DOWN_LIST)
1206                 XtSetValues((Widget)Sep(combo), args, 1);       
1207     }
1208
1209     /* 
1210      * Find out how big the arrow can be (needed to get 
1211      * available_width for text_holder).
1212      */
1213     /* MotifBc */
1214     XtSetArg(args[0], XmNwidth, &text_width);
1215     XtSetArg(args[1], XmNheight, &text_height);
1216     XtGetValues(text_holder, args, 2);
1217
1218     arrow_width = (Dimension)((float)text_height * ARROW_MULT);
1219     arrow_width = (arrow_width < ARROW_MIN) ? ARROW_MIN : arrow_width;
1220
1221     if (Type(combo) == DtDROP_DOWN_LIST) {
1222         XtSetArg(args[0], XmNwidth, &sep_width);
1223         XtGetValues((Widget)Sep(combo), args, 1);
1224     }
1225
1226     ResizeResult=XtMakeResizeRequest((Widget)combo, arrow_width + sep_width +
1227                               ArrowSpacing(combo) +
1228                               text_width + shadow + h_spacing +
1229                               (COMBO_MARGIN_W(combo) * 2), 
1230                               text_height + shadow + v_spacing +
1231                               (COMBO_MARGIN_H(combo) * 2), 
1232                               NULL, NULL);
1233     if (ResizeResult==XtGeometryNo || ResizeResult==XtGeometryAlmost) {
1234         XtWarning(CB_RESIZE);
1235     }
1236     OldWidth(combo) = Width(combo);
1237     OldHeight(combo) = Height(combo);
1238
1239     /* Resolution Independent */
1240     if (unit_type != XmPIXELS) {
1241         XtSetArg(args[0], XmNunitType, unit_type);
1242         XtSetValues(text_holder, args, 1);
1243         if (Type(combo) == DtDROP_DOWN_LIST)
1244                 XtSetValues((Widget)Sep(combo), args, 1);       
1245     }
1246 }
1247
1248 /*
1249  * This function makes the text_holder (label or text-field) smaller
1250  * if the combo_box couldn't grow to the needed full size.  It will
1251  * also make the text_holder grow if there is space.  The textfield will
1252  * grow with the combo_box, but the label will only grow to its' 
1253  * maximum size.  The label will also shrink down to nothing, but the
1254  * text-field will always keep its' core height.
1255  */
1256 static void
1257 ForceChildSizes(DtComboBoxWidget combo)
1258 {
1259     Dimension full_available_height, available_height, available_width;
1260     Dimension arrow_width;
1261     Dimension sep_width = 0;
1262     Dimension tmp_width, tmp_height, tmp_borderwidth;
1263     Arg args[3];
1264     unsigned char unit_type = XmPIXELS;
1265
1266     /* Resolution Independent */
1267     if (MUnitType(combo) != XmPIXELS) {
1268         unit_type = MUnitType(combo);
1269         XtSetArg(args[0], XmNunitType, XmPIXELS);
1270         if (Type(combo) == DtDROP_DOWN_LIST) {
1271                 XtSetValues(Sep(combo), args, 1);
1272                 XtSetValues(Label(combo), args, 1);
1273         }
1274         else
1275                 XtSetValues(Text(combo), args, 1);
1276         XtSetValues(Arrow(combo), args, 1);
1277     }
1278     /* Calculate available height for children */
1279     if ((available_height = Height(combo) - (COMBO_SHADOW(combo) * 2) - 
1280          (COMBO_MARGIN_H(combo) * 2) - (COMBO_V_SPACING(combo) * 2)) <= 0) {
1281         full_available_height = available_height = 1;
1282     }
1283     else {
1284         /* Seperator need available_height plus the vertical_spacing */
1285         full_available_height = (available_height + 
1286                                  (COMBO_V_SPACING(combo) * 2));
1287     }
1288
1289     /* Get initial available width for children */
1290     available_width = (Width(combo) - (COMBO_SHADOW(combo) * 2) - 
1291                        (COMBO_MARGIN_W(combo) * 2) - 
1292                        (COMBO_H_SPACING(combo) * 2));
1293     
1294     /* label only grows to maximum width needed */
1295     if ((Type(combo) == DtDROP_DOWN_LIST) && 
1296         ((int)available_height > (int)LabelMaxHeight(combo)))
1297         available_height = LabelMaxHeight(combo);
1298     else if (Type(combo) == DtDROP_DOWN_COMBO_BOX) {
1299         XtSetArg(args[0], XmNheight, &available_height);
1300         XtGetValues((Widget)Text(combo), args, 1);
1301     }
1302     
1303     /* 
1304      * Find out how big the arrow can be (needed to get 
1305      * available_width for text_holder).
1306      */
1307     arrow_width = (Dimension)((float)available_height * ARROW_MULT);
1308     arrow_width = (arrow_width < ARROW_MIN) ? ARROW_MIN : arrow_width;
1309         
1310     if (Type(combo) == DtDROP_DOWN_LIST) {
1311         XtSetArg(args[0], XmNwidth, &sep_width);
1312         XtGetValues((Widget)Sep(combo), args, 1);
1313     }
1314
1315     /* Make sure width isn't too small or too big */
1316     if ((available_width -= 
1317          (arrow_width + sep_width + ArrowSpacing(combo) )) <= (Dimension)0)
1318         available_width = 1;
1319
1320     /* Motif BC */
1321     XtSetArg(args[0], XmNwidth, &tmp_width);
1322     XtSetArg(args[1], XmNheight, &tmp_height);
1323     XtSetArg(args[2], XmNborderWidth, &tmp_borderwidth);
1324     if (Type(combo) == DtDROP_DOWN_LIST) {  /** label **/
1325         if ((int)available_width > (int)LabelMaxLength(combo))
1326             available_width = LabelMaxLength(combo);
1327
1328         /* Motif BC */
1329         XtGetValues((Widget)Label(combo), args, 3);
1330         if ((available_width != tmp_width) ||
1331             (available_height != tmp_height))
1332                 XtResizeWidget(Label(combo), available_width, available_height,
1333                                 tmp_borderwidth);
1334         /* Motif BC */ 
1335         XtGetValues((Widget)Sep(combo), args, 3); 
1336         if (full_available_height != tmp_height)
1337             XtResizeWidget(Sep(combo), tmp_width, full_available_height,
1338                            tmp_borderwidth);
1339     }
1340     else {
1341         /* Motif BC */
1342         XtGetValues((Widget)Text(combo), args, 3);
1343         if ( Width(((Widget)Text(combo))) != available_width) /** TextField **/
1344         XtResizeWidget(Text(combo), available_width,
1345                        tmp_height, tmp_borderwidth);
1346     }
1347
1348     /* Motif BC */
1349     XtGetValues((Widget)Arrow(combo), args, 3);
1350     if ((arrow_width != tmp_width) || (tmp_height != available_height)) {
1351         available_height = (available_height < ARROW_MIN) ? ARROW_MIN : 
1352                             available_height;
1353         XtResizeWidget(Arrow(combo), arrow_width, available_height,
1354                        tmp_borderwidth);
1355     }
1356
1357     /* Resolution Independent */
1358     if (unit_type != XmPIXELS) {
1359         XtSetArg(args[0], XmNunitType, unit_type);
1360         if (Type(combo) == DtDROP_DOWN_LIST) {
1361                 XtSetValues(Sep(combo), args, 1);
1362                 XtSetValues(Label(combo), args, 1);
1363         }
1364         else
1365                 XtSetValues(Text(combo), args, 1);
1366         XtSetValues(Arrow(combo), args, 1);
1367     }
1368 }
1369
1370 /*
1371  * This function positions the children within the combo_box widget.
1372  * It calls ForceChildSizes() to make sure the children fit within the
1373  * combo_box widget, but it will not try to resize the combo_box widget.
1374  */
1375 static void
1376 LayoutChildren(DtComboBoxWidget combo)
1377 {
1378     Widget text_holder = ((Type(combo) == DtDROP_DOWN_COMBO_BOX)
1379                           ? Text(combo) : Label(combo));
1380     Position start_x = (COMBO_SHADOW(combo) + COMBO_MARGIN_W(combo) +
1381                         COMBO_H_SPACING(combo));
1382     Position start_y = (COMBO_SHADOW(combo) + COMBO_MARGIN_H(combo) +
1383                         COMBO_V_SPACING(combo));
1384     short available_height = Height(combo) - (start_y * 2);
1385     Position y, arrow_y;
1386     unsigned char unit_type = XmPIXELS;
1387     Dimension tmp_width, tmp_height, sep_width;
1388     Arg args[3];
1389     
1390     ForceChildSizes(combo);
1391
1392     /* Resolution Independent */
1393     if (MUnitType(combo) != XmPIXELS) {
1394         unit_type = MUnitType(combo);
1395         XtSetArg(args[0], XmNunitType, XmPIXELS);
1396         XtSetValues(text_holder, args, 1);
1397         XtSetValues(Arrow(combo), args, 1);
1398         if (Type(combo) == DtDROP_DOWN_LIST) 
1399                 XtSetValues(Sep(combo), args, 1);
1400     }
1401     /* Center text_holder within combo_box */
1402     /* MotifBc */
1403     XtSetArg(args[0], XmNheight, &tmp_height);
1404     XtGetValues(text_holder, args, 1);
1405     y = available_height - tmp_height;
1406     y = ((y < 0) ? 0 : y)/2 + start_y;
1407  
1408     /* Center arrow within combo_box */
1409     /* MotifBc */
1410     XtSetArg(args[1], XmNwidth, &tmp_width);
1411     XtGetValues(Arrow(combo), args, 2);
1412     arrow_y = available_height - tmp_height;
1413     arrow_y = ((arrow_y < 0) ? 0 : arrow_y)/2 + start_y;
1414
1415     /* MotifBc */
1416     if (Type(combo) == DtDROP_DOWN_LIST) {
1417         XtSetArg(args[0], XmNwidth, &sep_width);
1418         XtGetValues(Sep(combo), args, 1);
1419     }
1420     if (Orientation(combo) == DtLEFT) {
1421         XtMoveWidget(Arrow(combo), start_x, arrow_y);
1422         start_x += tmp_width;
1423         if (Type(combo) == DtDROP_DOWN_LIST) {
1424             XtMoveWidget(Sep(combo), start_x, start_y - 
1425                          COMBO_V_SPACING(combo));
1426             start_x += sep_width;
1427         }
1428         start_x += ArrowSpacing(combo);
1429         XtMoveWidget(text_holder, start_x, y);
1430     }
1431     else {
1432         XtMoveWidget(text_holder, start_x, y);
1433         /*  
1434          * We want the arrow at the end of the combo_box, so
1435          * the user can use recompute_size more effectively.
1436          */
1437         start_x = Width(combo) - start_x - tmp_width;
1438         if (Type(combo) == DtDROP_DOWN_LIST) {
1439             start_x -= sep_width;
1440             XtMoveWidget(Sep(combo), start_x, start_y -
1441                          COMBO_V_SPACING(combo));
1442             start_x += sep_width;
1443         }
1444         XtMoveWidget(Arrow(combo), start_x, arrow_y);
1445     }
1446
1447     /* Resolution Independent */
1448     if (unit_type != XmPIXELS) {
1449         XtSetArg(args[0], XmNunitType, unit_type);
1450         XtSetValues(text_holder, args, 1);
1451         XtSetValues(Arrow(combo), args, 1);
1452         if (Type(combo) == DtDROP_DOWN_LIST) 
1453                 XtSetValues(Sep(combo), args, 1);
1454     }
1455 }
1456
1457 /*
1458  * SetValues() routine for ComboBox widget. 
1459  */
1460 static Boolean
1461 SetValues(      DtComboBoxWidget current,
1462                 DtComboBoxWidget request,
1463                 DtComboBoxWidget new)
1464 {
1465     DtComboBoxPart *new_p = (DtComboBoxPart*)
1466         &(XmField(new,ipot,DtComboBox,arrow,Widget));
1467     Boolean label_size_changed = FALSE;
1468     Boolean force_label_string = FALSE;
1469     Arg args[10];
1470     int n;
1471     unsigned char new_unit_type = XmPIXELS, curr_unit_type = XmPIXELS;
1472
1473     CheckResources(new);
1474
1475     /* Resolution Independent */
1476     if (MUnitType(new) != XmPIXELS) {
1477         new_unit_type = MUnitType(new);
1478         XtSetArg(args[0], XmNunitType, XmPIXELS);
1479         if (Arrow(new)) XtSetValues(Arrow(new), args, 1);
1480         if (List(new)) XtSetValues(List(new), args, 1);
1481         if (Shell(new)) XtSetValues(Shell(new), args, 1);
1482         if (Label(new)) XtSetValues(Label(new), args, 1);
1483         if (Text(new)) XtSetValues(Text(new), args, 1);
1484         if (Sep(new)) XtSetValues(Sep(new), args, 1);
1485     }
1486     if (MUnitType(current) != XmPIXELS) {
1487         curr_unit_type = MUnitType(current);
1488         XtSetArg(args[0], XmNunitType, XmPIXELS);
1489         if (Arrow(current)) XtSetValues(Arrow(current), args, 1);
1490         if (List(current)) XtSetValues(List(current), args, 1);
1491         if (Shell(current)) XtSetValues(Shell(current), args, 1);
1492         if (Label(current)) XtSetValues(Label(current), args, 1);
1493         if (Text(current)) XtSetValues(Text(current), args, 1);
1494         if (Sep(current)) XtSetValues(Sep(current), args, 1);
1495     }
1496
1497     if (Text(new) != Text(current)) {
1498         XtWarning(CB_TEXT);
1499         Text(new) = Text(current);
1500     }
1501
1502     /*
1503      * Pass any list specific resources on to our List Widget.
1504      * Check each one, since it's too costly to always set them.
1505      */
1506     n = 0;
1507     if (ItemCount(new) != ItemCount(current)){
1508         if (Items(new) && (ItemCount(new) < 0)) {
1509             XtWarning(CB_ITEM_COUNT);
1510             ItemCount(new) = 0;
1511         }
1512         XtSetArg(args[n], XmNitemCount, ItemCount(new)); n++;
1513     }
1514     if (Items(new) != ListItems(current)) {
1515         XtSetArg(args[n], XmNitems, Items(new)); n++;
1516         /* Make sure itemCount will get sent to list */
1517         if (ItemCount(new) == ItemCount(current)) {
1518             XtSetArg(args[n], XmNitemCount, ItemCount(new)); n++;
1519         }
1520     }
1521     if (ListFontList(new) != ListFontList(current)) {
1522         XtSetArg(args[n], XmNfontList, ListFontList(new)); n++;
1523     }
1524     if (ListMarginHeight(new) != ListMarginHeight(current)) {
1525         XtSetArg(args[n], XmNlistMarginHeight, ListMarginHeight(new)); n++; 
1526     }
1527     if (ListMarginWidth(new) != ListMarginWidth(current)) {
1528         XtSetArg(args[n], XmNlistMarginWidth, ListMarginWidth(new)); n++;
1529     }
1530     if (ListSpacing(new) != ListSpacing(current)) {
1531         XtSetArg(args[n], XmNlistSpacing, ListSpacing(new)); n++;
1532     }
1533     if (LayoutDirection(new) != LayoutDirection(current)) {
1534         XmStringDirection new_direction =
1535           XmDirectionToStringDirection(LayoutDirection(new));
1536         XtSetArg(args[n], XmNstringDirection, new_direction); n++;
1537     }
1538     if (TopItemPosition(new) != TopItemPosition(current)) {
1539         XtSetArg(args[n], XmNtopItemPosition, TopItemPosition(new)); n++;
1540     }
1541     if (VisibleItemCount(new) != VisibleItemCount(current)) {
1542         XtSetArg(args[n], XmNvisibleItemCount, VisibleItemCount(new)); n++;
1543     }
1544     if (n > 0) {
1545         /* MotifBc */
1546         Arg tmp_arg[2];
1547         Dimension tmp_width, tmp_height;
1548
1549         XtSetValues(List(new), args, n);
1550         /* MotifBc */
1551         XtSetArg(tmp_arg[0], XmNwidth, &tmp_width);
1552         XtSetArg(tmp_arg[1], XmNheight, &tmp_height);
1553         XtGetValues(((Widget) Shell(new)), tmp_arg, 2);
1554         MaxShellWidth(new) = tmp_width;
1555         MaxShellHeight(new) = tmp_height;
1556     }
1557
1558     /* If arrow type changes delete the old one and create the new one */
1559     if (ArrowType(new) != ArrowType(current)) {
1560         XtRemoveCallback(Arrow(new), XmNactivateCallback, activate_cb, 
1561                          (XtPointer)new);
1562         if (ArrowType(current) == DtWINDOWS)
1563             XtRemoveCallback(Arrow(new), XmNexposeCallback,
1564                              arrow_expose_cb, (XtPointer)new);
1565         XtDestroyWidget(Arrow(new));
1566
1567         n = 0;
1568         XtSetArg(args[n], XmNtraversalOn, FALSE); n++;
1569         XtSetArg(args[n], XmNhighlightThickness, 0); n++;
1570         XtSetArg(args[n], XmNshadowThickness, 0); n++;
1571         if (ArrowType(new) == DtMOTIF) {
1572             XtSetArg(args[n], XmNarrowDirection, XmARROW_DOWN); n++;
1573             XtSetArg(args[n], XmNforeground, BackgroundPixel(new)); n++;
1574             Arrow(new) = XtCreateManagedWidget("ComboBoxArrow", 
1575                                                  xmArrowButtonWidgetClass,
1576                                                  (Widget)new, args, n);
1577         }
1578         else {
1579             Arrow(new) = XtCreateManagedWidget("ComboBoxArrow", 
1580                                                  xmDrawnButtonWidgetClass,
1581                                                  (Widget)new, args, n);
1582             XtAddCallback(Arrow(new), XmNexposeCallback, arrow_expose_cb, 
1583                           (XtPointer)new);
1584         }
1585         XtAddCallback(Arrow(new), XmNactivateCallback, activate_cb, 
1586                       (XtPointer)new);
1587     }
1588
1589     /*
1590      * Type resource changed.  If the widget (textField or Label)
1591      * doesn't exist, then create it.  Always reset orientation
1592      * constraint resources when type changes; otherwise, the
1593      * text_holder widget positioning could be screwed up.  We don't
1594      * reset both widgets if the orientation changes (because we might
1595      * not have created both widgets).
1596      * If label must be created, also create the separator widget.
1597      */
1598     if (Type(new) != Type(current)) {
1599         if (Type(new) == DtDROP_DOWN_COMBO_BOX) {
1600             if (Text(new) == NULL) {
1601                 n = 0;
1602                 XtSetArg(args[n], XmNcolumns, TextColumns(new)); n++;
1603                 XtSetArg(args[n], XmNmaxLength, TextMaxLength(new)); n++;
1604                 XtSetArg(args[n], XmNmarginWidth, 2); n++;
1605                 XtSetArg(args[n], XmNmarginHeight, 2); n++;
1606                 Text(new) = XtCreateWidget("ComboBoxTextField", 
1607                                              xmTextFieldWidgetClass,
1608                                              (Widget)new, args, n);
1609                 XtAddCallback(Text(new), XmNlosingFocusCallback, 
1610                               text_losing_focus_cb, (XtPointer)new);
1611                 XtAddCallback(Text(new), XmNactivateCallback, 
1612                               text_activate_cb, (XtPointer)new);
1613                 XtAddCallback(Text(new), XmNfocusCallback, 
1614                               text_focus_cb, (XtPointer)new);
1615                 if (HorizontalSpacing(new) == HorizontalSpacing(current))
1616                     HorizontalSpacing(new) = 0;
1617                 if (VerticalSpacing(new) == VerticalSpacing(current))
1618                     VerticalSpacing(new) = 0;
1619             }
1620             XtUnmanageChild(Sep(new));
1621             XtUnmanageChild(Label(new));
1622             XtManageChild(Text(new));
1623         }
1624         else {
1625             if (Label(new) == NULL) {
1626                 XmStringDirection new_direction =
1627                   XmDirectionToStringDirection(LayoutDirection(new));
1628
1629                 XtTranslations label_trans = 
1630                     XtParseTranslationTable(ComboBoxLabelTranslationTable);
1631
1632                 n = 0;
1633                 XtSetArg(args[n], XmNalignment, Alignment(new)); n++;
1634                 XtSetArg(args[n], XmNrecomputeSize, FALSE); n++;
1635                 XtSetArg(args[n], XmNmarginLeft, LABEL_PADDING); n++;
1636                 XtSetArg(args[n], XmNmarginRight, LABEL_PADDING); n++;
1637                 XtSetArg(args[n], XmNmarginWidth, TEXT_CONTEXT_MARGIN); n++;
1638                 XtSetArg(args[n], XmNmarginHeight, 0); n++;
1639                 XtSetArg(args[n], XmNstringDirection, new_direction); n++;
1640                 Label(new) = XtCreateWidget("ComboBoxLabel", 
1641                                               xmLabelWidgetClass,
1642                                               (Widget)new, args, n);
1643                 XtOverrideTranslations((Widget)Label(new), label_trans);
1644                 if (HorizontalSpacing(new) == HorizontalSpacing(current))
1645                     HorizontalSpacing(new) = 1;
1646                 if (VerticalSpacing(new) == VerticalSpacing(current))
1647                     VerticalSpacing(new) = 2;
1648
1649                 n = 0;
1650                 XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
1651                 Sep(new) = XtCreateWidget("ComboBoxSeparator", 
1652                                             xmSeparatorWidgetClass,
1653                                             (Widget)new, args, n);
1654             }
1655             else if (LayoutDirection(new) != LayoutDirection(current)) {
1656                 XmStringDirection new_direction =
1657                   XmDirectionToStringDirection(LayoutDirection(new));
1658                 XtSetArg(args[0], XmNstringDirection, new_direction);
1659                 XtSetValues(Label(new), args, 1);
1660             }
1661             XtUnmanageChild(Text(new));
1662             XtManageChild(Label(new));
1663             XtManageChild(Sep(new));
1664         }
1665         /* 
1666          * Text-fields and labels have different shadows.  Only
1667          * change if user didn't change the shadow resource.
1668          */
1669         if (COMBO_SHADOW(new) == COMBO_SHADOW(current))
1670             COMBO_SHADOW(new) = ((Type(new) == DtDROP_DOWN_COMBO_BOX) ?
1671                                  TEXT_FIELD_SHADOW : LABEL_SHADOW);
1672     }
1673
1674     if (Text(new) && (Text(new) == Text(current))) {
1675         n = 0;
1676         if (TextColumns(new) != TextColumns(current)) {
1677             XtSetArg(args[n], XmNcolumns, TextColumns(new)); n++;
1678         }
1679         if (TextMaxLength(new) != TextMaxLength(current) ) {
1680             XtSetArg(args[n], XmNmaxLength, TextMaxLength(new)); n++;
1681         }
1682         if (n > 0)
1683             XtSetValues(Text(new), args, n);
1684     }
1685
1686     /*
1687      * LabelWidget alignment has changed.
1688      */
1689     if (Label(new) && (Alignment(new) != Alignment(current))) {
1690         XtSetArg(args[0], XmNalignment, Alignment(new));
1691         XtSetValues(Label(new), args, 1);
1692     }
1693
1694     if (Label(new) && ((Items(new) != ListItems(current)) || 
1695                          (ItemCount(new) != ItemCount(current)) ||
1696                          (Label(new) != Label(current)))) {
1697         SetMaximumLabelSize(new_p);
1698         label_size_changed = TRUE;
1699     }
1700
1701     /* Copy and free label-string */
1702     if (LabelString(new) != LabelString(current)) {
1703         if (LabelString(new))
1704             LabelString(new) = XmStringCopy(LabelString(new));
1705         if (LabelString(current))
1706             XmStringFree(LabelString(current)); 
1707         /* 
1708          * force_label_string usage if it is specified and items is not.
1709          * This will be the perminant label string only if update-label
1710          * is false, else it is only used until the user picks something
1711          * new off the list.
1712          */
1713         if (Items(new) == ListItems(current))
1714             force_label_string = TRUE;
1715     }
1716
1717     if ((Items(new) != ListItems(current)) ||
1718         (Alignment(new) != Alignment(current)) ||
1719         (Type(new) != Type(current)) ||
1720         (ItemCount(new) != ItemCount(current)) ||
1721         (SelectedPosition(new) != SelectedPosition(current)) ||
1722         (XmStringByteCompare(SelectedItem(new), SelectedItem(current))!=True) ||
1723         (Label(new) != Label(current)) ||
1724         (UpdateLabel(new) != UpdateLabel(current)) ||
1725         (LabelString(new) != LabelString(current))) {
1726
1727         /* selected_item resource used before selected_position */
1728         if (SelectedItem(new) && XmeStringIsValid(SelectedItem(new)) &&
1729             (XmStringByteCompare(SelectedItem(new), 
1730                                  SelectedItem(current))!=True) ){
1731             if (SelectedItem(current)) {
1732                 XmStringFree(SelectedItem(current));
1733                 SelectedItem(current) = NULL;
1734             }
1735             SelectedItem(new) = XmStringCopy(SelectedItem(new));
1736             DtComboBoxSelectItem((Widget)new, SelectedItem(new));
1737         }
1738         else {
1739             if (SelectedPosition(new)<0||SelectedPosition(new)>=ItemCount(new))
1740                 SelectedPosition(new) = 0;
1741             if ((ItemCount(new)) && 
1742                 (SelectedPosition(new) != SelectedPosition(current))) {
1743                 
1744                 XmListSelectPos(List(new), SelectedPosition(new) + 1, FALSE);
1745                 if (SelectedItem(current)) {
1746                     
1747                     XmStringFree(SelectedItem(current));
1748                     SelectedItem(current) = NULL;
1749                 }
1750                 SyncWithList(new_p);
1751                 SelectedItem(new) = 
1752                     XmStringCopy((ListItems(new))[SelectedPosition(new)]);
1753             }
1754
1755             /* Else, same item selected as last time */
1756             else {
1757                 SelectedItem(new) = XmStringCopy(SelectedItem(new));
1758                 if ((SelectedItem(new) != NULL) && (ListItems(new) != NULL))
1759                     DtComboBoxSelectItem((Widget)new, SelectedItem(new));
1760                 if (SelectedItem(current)) {
1761                     XmStringFree(SelectedItem(current));
1762                     SelectedItem(current) = NULL;
1763                 }
1764             }
1765         }
1766
1767         if (Type(new) == DtDROP_DOWN_COMBO_BOX)
1768             SetTextFieldData(new_p, NULL);
1769         else
1770             SetLabelData(new_p, NULL, force_label_string);
1771     }
1772
1773     /* Else, same item selected as last time */
1774     else {
1775         SelectedItem(new) = XmStringCopy(SelectedItem(new));
1776         if ((SelectedItem(new) != NULL) && (ListItems(new) != NULL))
1777             DtComboBoxSelectItem((Widget)new, SelectedItem(new));
1778         if (SelectedItem(current)) {
1779             XmStringFree(SelectedItem(current));
1780             SelectedItem(current) = NULL;
1781         }
1782     }
1783
1784     /*
1785      * Must recalculate the combo_box and re-layout the children.
1786      * If this is not editable, then set the label to its' maximum
1787      * size; it will get chopped if it is too big.  This is needed 
1788      * because we shrink the label down, and SetComboBoxSize() uses
1789      * the label's core sizes to figure what size to become.
1790      */
1791     if ((Type(new) != Type(current)) ||
1792         (ArrowType(new) != ArrowType(current)) ||
1793         (COMBO_MARGIN_W(new) != COMBO_MARGIN_W(current)) ||
1794         (COMBO_MARGIN_H(new) != COMBO_MARGIN_H(current)) ||
1795         (COMBO_H_SPACING(new) != COMBO_H_SPACING(current)) ||
1796         (COMBO_V_SPACING(new) != COMBO_V_SPACING(current)) ||
1797         (COMBO_SHADOW(new) != COMBO_SHADOW(current)) ||
1798         (Orientation(new) != Orientation(current)) ||
1799         (ArrowSpacing(new) != ArrowSpacing(current)) ||
1800         ((Type(new) == DtDROP_DOWN_LIST) && label_size_changed)) {
1801         ClearShadow(current, TRUE);
1802         if (RecomputeSize(new))
1803             SetComboBoxSize(new);
1804         LayoutChildren(new);
1805         DrawShadow(new);
1806     }
1807
1808     SyncWithList(new_p);
1809     /* Resolution Independent */
1810     if (new_unit_type != XmPIXELS) {
1811         XtSetArg(args[0], XmNunitType, new_unit_type);
1812         if (Arrow(new)) XtSetValues(Arrow(new), args, 1);
1813         if (List(new)) XtSetValues(List(new), args, 1);
1814         if (Shell(new)) XtSetValues(Shell(new), args, 1);
1815         if (Label(new)) XtSetValues(Label(new), args, 1);
1816         if (Text(new)) XtSetValues(Text(new), args, 1);
1817         if (Sep(new)) XtSetValues(Sep(new), args, 1);
1818     }
1819     if (curr_unit_type != XmPIXELS) {
1820         XtSetArg(args[0], XmNunitType, curr_unit_type);
1821         if (Arrow(current)) XtSetValues(Arrow(current), args, 1);
1822         if (List(current)) XtSetValues(List(current), args, 1);
1823         if (Shell(current)) XtSetValues(Shell(current), args, 1);
1824         if (Label(current)) XtSetValues(Label(current), args, 1);
1825         if (Text(current)) XtSetValues(Text(current), args, 1);
1826         if (Sep(current)) XtSetValues(Sep(current), args, 1);
1827     }
1828     return(FALSE);
1829 }
1830
1831
1832 /*
1833  * This function clears the shadow around our widget.  If all is TRUE,
1834  * then clear all 4 sides; otherwise, only clear the right and bottom
1835  * sides (during resize). 
1836  */ 
1837 static void
1838 ClearShadow(    DtComboBoxWidget w,
1839                 Boolean all)
1840 {
1841     Dimension shadow = COMBO_SHADOW(w);
1842     Dimension margin_w = COMBO_MARGIN_W(w);
1843     Dimension margin_h = COMBO_MARGIN_H(w);
1844
1845     if ((shadow > 0) && XtIsRealized((Widget)w)) {
1846         if (all) {
1847             XClearArea(XtDisplayOfObject((Widget)w),
1848                        XtWindowOfObject((Widget)w), 
1849                        margin_w, margin_h,
1850                        OldWidth(w) - (margin_w * 2),
1851                        shadow, FALSE);
1852             XClearArea(XtDisplayOfObject((Widget)w),
1853                        XtWindowOfObject((Widget)w), 
1854                        margin_w, margin_h, shadow, 
1855                        OldHeight(w) - (margin_h * 2), FALSE);
1856         }
1857         XClearArea(XtDisplayOfObject((Widget)w), 
1858                    XtWindowOfObject((Widget)w), margin_w,
1859                    OldHeight(w) - margin_h - shadow,
1860                    OldWidth(w) - (margin_w * 2), shadow, FALSE);
1861         XClearArea(XtDisplayOfObject((Widget)w), XtWindowOfObject((Widget)w),
1862                    OldWidth(w) - margin_w - shadow,
1863                    margin_h, shadow, 
1864                    OldHeight(w) - (margin_h * 2), FALSE);
1865     }
1866     DrawHighlight(w, TRUE);
1867 }
1868
1869 /* 
1870  * This functions draws the shadow around our combo-box.
1871  */
1872 static void
1873 DrawShadow(DtComboBoxWidget w)
1874 {
1875     Dimension shadow = COMBO_SHADOW(w);
1876     Dimension margin_w = COMBO_MARGIN_W(w);
1877     Dimension margin_h = COMBO_MARGIN_H(w);
1878     
1879     if ((shadow > 0) && XtIsRealized((Widget)w)) {
1880         XmeDrawShadows(XtDisplayOfObject((Widget)w),
1881                        XtWindowOfObject((Widget)w),
1882                        TopShadowGC(w),
1883                        BottomShadowGC(w), 
1884                        margin_w, margin_h,
1885                        Width(w) - (margin_w * 2),
1886                        Height(w) - (margin_h * 2),
1887                        shadow, XmSHADOW_OUT);
1888     }
1889     DrawHighlight(w, FALSE);
1890 }
1891
1892 /*
1893  * Take the string out of the list and put it into the text-field.
1894  * text-fields don't handle xm-strings, so we must get the char*
1895  * out of it (only getting the first segment).  This is slower than
1896  * storing the text-strings (char*) ourselves, but that would take
1897  * up a lot of memory.  Since this setting happens during a user
1898  * action, speed isn't a problem.
1899  */
1900 static void
1901 SetTextFieldData(DtComboBoxPart *combo_p, XmString item)
1902 {
1903     XmListWidget list = (XmListWidget)combo_p->list;
1904     XmStringContext context;
1905     Boolean done = FALSE;
1906     Arg args[2];
1907     XmStringComponentType type;
1908     char *text;
1909     XmStringCharSet charset;
1910     XmStringDirection direction;
1911     XmStringComponentType unknown_tag;
1912     unsigned short ul;
1913     unsigned char *uv;
1914     XmStringTable list_items;
1915     int item_count;
1916     Boolean isItemCopied = FALSE;
1917 /* MotifBc 
1918  */
1919     XtSetArg(args[0], XmNitemCount, &item_count);
1920     XtSetArg(args[1], XmNitems, &list_items);
1921     XtGetValues((Widget)list, args, 2); 
1922     if (item_count && item_count>combo_p->selected_position && 
1923         !item && list_items) {
1924         item = XmStringCopy(list_items[combo_p->selected_position]);
1925         isItemCopied = TRUE;
1926     }
1927
1928     if (!item) {
1929         combo_p->selected_item = NULL;
1930         XtSetArg(args[0], XmNvalue, "");
1931         XtSetValues(combo_p->text, args, 1);
1932     }
1933     else {
1934         if (combo_p->selected_item != item) 
1935           {
1936             if (combo_p->selected_item)
1937               XmStringFree (combo_p->selected_item);
1938             combo_p->selected_item = XmStringCopy(item);
1939           }
1940         XmStringInitContext(&context, item);
1941         
1942         /* Loop until 1st char* found */
1943         while (!done) {
1944             type = XmStringGetNextComponent(context, &text, &charset,
1945                                             &direction, &unknown_tag, 
1946                                             &ul, &uv);
1947             switch (type) {
1948             case XmSTRING_COMPONENT_END:
1949                 done = TRUE;
1950                 break;
1951             case XmSTRING_COMPONENT_TEXT:
1952             case XmSTRING_COMPONENT_LOCALE_TEXT:
1953                 XtSetArg(args[0], XmNvalue, text);
1954                 XtSetValues(combo_p->text, args, 1);
1955                 XtFree(text);
1956                 done = TRUE;
1957                 break;
1958             default:
1959                 break;
1960             }
1961         }
1962         XmStringFreeContext(context);
1963         if (isItemCopied)
1964             XmStringFree(item);
1965     }
1966 }
1967
1968
1969 /*
1970  * Set the maximum size of the label, depending on the
1971  * characteristics of the list of items.
1972  */
1973 static void
1974 SetMaximumLabelSize(DtComboBoxPart *combo_p)
1975 {
1976     XmListWidget list = (XmListWidget)combo_p->list;
1977     XmFontList font_list;
1978     Dimension width, height, border_width;
1979     Dimension longest = 0;
1980     Dimension highest = 0;
1981     Arg args[5];
1982     int i, item_count;
1983     XmStringTable list_items;
1984     unsigned char unit_type = XmPIXELS;
1985
1986     /* Resolution Independent */
1987     XtSetArg(args[0], XmNunitType, &unit_type);
1988     XtGetValues(combo_p->list, args, 1); /* Assume list/Combo has same uniType*/
1989     if (unit_type != XmPIXELS) {
1990         XtSetArg(args[0], XmNunitType, XmPIXELS);
1991         XtSetValues(combo_p->label, args, 1);
1992         XtSetValues(combo_p->list, args, 1);
1993     }
1994         
1995     /* Get font info from the widget */
1996     XtSetArg(args[0], XmNfontList, &font_list);
1997     XtGetValues(combo_p->label, args, 1);
1998 /* MotifBc
1999  */
2000     XtSetArg(args[0], XmNitems, &list_items);
2001     XtSetArg(args[1], XmNitemCount, &item_count);
2002     XtGetValues((Widget)list, args, 2);
2003
2004     if ( item_count && item_count >= combo_p->item_count &&
2005          list_items && combo_p->update_label) {
2006         /*
2007          * Loop through all the items to find the biggest dimensions
2008          */
2009         for (i = 0; i < combo_p->item_count; i++) {
2010             XmStringExtent(font_list, list_items[i], &width, &height);
2011             longest = (width > longest) ? width : longest;
2012             highest = (height > highest) ? height : highest;
2013          }
2014     }
2015     else {
2016         XmStringExtent(font_list, combo_p->label_string, &longest, &highest);
2017     }
2018         
2019     combo_p->label_max_length = longest + ((LABEL_PADDING+TEXT_CONTEXT_MARGIN) * 2);
2020     combo_p->label_max_height = highest;
2021     /* MotifBc */
2022     XtSetArg(args[0], XmNborderWidth, &border_width);
2023     XtGetValues(combo_p->label, args, 1);
2024     XtResizeWidget(combo_p->label, combo_p->label_max_length, highest, 
2025                    border_width);
2026
2027     /* Resolution Independent */
2028     if (unit_type != XmPIXELS) {
2029         XtSetArg(args[0], XmNunitType, unit_type);
2030         XtSetValues(combo_p->label, args, 1);
2031         XtSetValues(combo_p->list, args, 1);
2032     }
2033 }
2034
2035
2036 /*
2037  * Put the current list item into the label.
2038  * This could probably be faster if we see if the label is the
2039  * same as the new item?
2040  */
2041 static void
2042 SetLabelData(   DtComboBoxPart *combo_p,
2043                 XmString item,
2044                 Boolean force_label_string)
2045 {
2046     XmListWidget list = (XmListWidget)combo_p->list;
2047     int index = combo_p->selected_position;
2048     Arg args[2];
2049     XmStringTable list_items;
2050     int item_count;
2051
2052     /*
2053      * If the item is empty, get the current item from the list, or
2054      * use label_string if update_label is FALSE.  If that is empty, 
2055      * use InitLabel.
2056      */
2057     if (force_label_string || (combo_p->update_label == FALSE))
2058         item = combo_p->label_string ? combo_p->label_string : InitLabel;
2059     else {
2060         if (!item) {
2061 /* MotifBc
2062  */
2063             XtSetArg(args[0], XmNitemCount, &item_count);
2064             XtSetArg(args[1], XmNitems, &list_items);
2065             XtGetValues((Widget)list, args, 2);
2066             if (item_count && item_count>index && list_items)
2067                 item = list_items[index];
2068             else
2069                 item = InitLabel;
2070         }
2071         
2072         /* Keep label_string in sync with item picked */
2073         if (combo_p->label_string)
2074             XmStringFree(combo_p->label_string);
2075         combo_p->label_string = XmStringCopy(item);
2076     }
2077
2078     combo_p->selected_item = XmStringCopy(item);
2079     XtSetArg(args[0], XmNlabelString, item);
2080     XtSetValues(combo_p->label, args, 1);
2081 }
2082
2083 /*
2084  * This is the browseSelect and defaultAction callback handler for the
2085  * ListWidget.  If using the textWidget, we only take the first 
2086  * segment of the XmString (TextWidgets don't handle XmStrings).  If we
2087  * are using a label, then just set the labelString resource.
2088  */
2089 static void
2090 select_cb(      Widget w,
2091                 XtPointer client_data,
2092                 XtPointer call_data)
2093 {
2094     DtComboBoxWidget combo_w = (DtComboBoxWidget)client_data;
2095     DtComboBoxPart *combo_p = (DtComboBoxPart*)
2096         &(XmField(combo_w,ipot,DtComboBox,arrow,Widget));
2097     XmListCallbackStruct *info = (XmListCallbackStruct*)call_data;
2098     DtComboBoxCallbackStruct cb;
2099     
2100     SelectedPosition(combo_w) = info->item_position - 1;
2101     if (SelectedItem(combo_w))
2102         XmStringFree(SelectedItem(combo_w));
2103     SelectedItem(combo_w) = XmStringCopy(info->item);
2104     if (Type(combo_w) == DtDROP_DOWN_COMBO_BOX) {
2105         SetTextFieldData(combo_p, SelectedItem(combo_w));
2106     }
2107     else {      /* Set the labelWidget string */
2108         SetLabelData(combo_p, SelectedItem(combo_w), FALSE);
2109     }
2110     
2111     /*
2112      * Only popdown if this is the defaultAction callback.  We don't
2113      * want to popdown with browseSelect callback; that would cause the
2114      * menu to popdown when the user moved selection with the keyboard.
2115      * Doing it this way, allows the menu to stay up during 
2116      * keyboard navigation.  When menu goes away, make sure input
2117      * focus goes back into the textField (if editable).
2118      */
2119     /* This is one of three places to popdown the menu and here is 
2120      * to pop it down by Keyboard input: KSelect
2121      * Another place using keyboard input to popdown the menu is 
2122      * in _ComboBoxKbdCancel() by <Key>osfEsc
2123      * the last place is in shell_event_handler and that is for
2124      * poping down through Button operation: BSelect
2125      */
2126     if (info->reason == XmCR_DEFAULT_ACTION) 
2127         input_ungrab( combo_w, GRAB_POINTER | GRAB_KEYBOARD );
2128
2129     if ( ShellPoppedUp(((ShellWidget)Shell(combo_w))) == FALSE) {
2130         /* The list will free info->item */
2131         /* The semantic of a DtNselectionCallback is:
2132          * a callback to here + ShellPoppedUp==False
2133          * In reality, there are two scenario for this:
2134          *     1. XmList's XmNdefaultActionCallback which is activated by
2135          *        KSelect, will first pop down the shell (see above) and
2136          *        and then get here.
2137          *     2. BSelect on XmList, which first call the list_event_handler()
2138          *        (for the handler is registered as LIST_HEAD) to pop down
2139          *        the shell, and then call XmList's XmNbrowseSelectionCallback
2140          *        which in turn get here
2141          */
2142         cb.reason = DtCR_SELECT;
2143         cb.event = info->event;
2144         cb.item_or_text = XmStringCopy(info->item);
2145         cb.item_position = SelectedPosition(combo_w);
2146         XtCallCallbackList((Widget)combo_w, SelectionCallback(combo_w), 
2147                            (XtPointer)&cb);
2148         if (cb.item_or_text != NULL) {
2149             XmStringFree(cb.item_or_text);
2150             cb.item_or_text = NULL;
2151         }
2152     }
2153 }
2154
2155
2156 /*
2157  * This is the event_handler for our shell widget.  The grab happens
2158  * on the shell while the user is not doing anything inside the list.
2159  * This allows us to know if the user pressed a button outside our
2160  * application.  If the user pressed a button anywhere but inside
2161  * the shell, then popdown the menu and ungrab everything.
2162  */
2163
2164 static void
2165 shell_event_handler(    Widget widget,
2166                         XtPointer client_data,
2167                         XEvent* event,
2168                         Boolean *dispatch)
2169 {
2170     DtComboBoxWidget combo_w = (DtComboBoxWidget)client_data;
2171     XmScrolledWindowWidget sw = (XmScrolledWindowWidget)XtParent(List(combo_w));
2172     XmScrollBarWidget v_scrollbar;
2173     XmScrollBarWidget h_scrollbar;
2174     Window window = event->xbutton.window;
2175     Arg args[2];
2176
2177     _DtProcessLock();
2178     if (popup_shell_init) {
2179         if (popup_shell_init != DtKeyPressPopup) {
2180             /* Menu popped up by ButtonPress */
2181             popup_shell_init = DtNonePopup;
2182             _DtProcessUnlock();
2183             return;
2184         }
2185         else
2186             /* Menu popped up by KActivate */
2187             popup_shell_init = DtNonePopup;
2188     }
2189     _DtProcessUnlock();
2190
2191     /* MotifBc */
2192     XtSetArg(args[0], XmNverticalScrollBar, &v_scrollbar);
2193     XtSetArg(args[1], XmNhorizontalScrollBar, &h_scrollbar);
2194     XtGetValues((Widget)sw, args, 2);
2195
2196     /* condition : Shell is popped up;
2197      *             ButtonPress event;
2198      *             the cursor is Not inside the XmList area,
2199      *             the horizontal scrollbar or the vertical one;
2200      * action:     remove all the grabs by DtComboBox
2201      */
2202     if ( ShellPoppedUp(((ShellWidget)Shell(combo_w))) &&
2203          (event->type == ButtonPress &&
2204           (window != XtWindowOfObject(List(combo_w))) &&
2205           !(ScrollBarVisible((Widget)h_scrollbar) && 
2206             (window == XtWindowOfObject((Widget)h_scrollbar))) &&
2207           !(ScrollBarVisible((Widget)v_scrollbar) && 
2208             (window == XtWindowOfObject((Widget)v_scrollbar))))
2209        )
2210         input_ungrab( combo_w, GRAB_POINTER | GRAB_KEYBOARD );
2211
2212     /* condition : ButtonRelease event
2213      *             the cursor is outside the scrollbar(horizontal or vertical)
2214      * action:     call action routine "Release" of ScrollBar to release
2215      *             possible pressed slider arrow (up/down)
2216      */
2217     if (event->type == ButtonRelease) {
2218         if ( ScrollBarVisible((Widget)h_scrollbar) &&
2219              window != XtWindowOfObject((Widget)h_scrollbar) )
2220             XtCallActionProc((Widget)h_scrollbar, "Release", event,NULL,0);
2221         if ( ScrollBarVisible((Widget)v_scrollbar) &&
2222              window != XtWindowOfObject((Widget)v_scrollbar) )
2223             XtCallActionProc((Widget)v_scrollbar, "Release", event,NULL,0);
2224     }
2225 }
2226
2227
2228 /*
2229  * This is the event_handler for our list widget.  Getting the pointer
2230  * grabbing to work correctly was not very easy.  In order for everything
2231  * to work correctly, we only do grab-pointer, for the shell, while not
2232  * doing anything inside the list.  If doing something inside the list
2233  * we remove the grab on the shell.  This is the only way that the 
2234  * list will get the ButtonRelease if doing browse while outside the
2235  * list.  The toolkit automatically does a grab in between ButtonPress
2236  * and ButtonRelease; therefore, the shell ungrab can't be done inside
2237  * the ButtonPress event.
2238  */
2239 static void
2240 list_event_handler(     Widget widget,
2241                         XtPointer client_data,
2242                         XEvent* event,
2243                         Boolean *dispatch)  /* call remaining event handlers */
2244 {
2245     DtComboBoxWidget combo_w = (DtComboBoxWidget)client_data;
2246     Arg         args[5];
2247     int         num_args;
2248     int         top_item_position;
2249     int         visible_item_count;
2250     int         item_count;
2251     XmScrolledWindowWidget sw = (XmScrolledWindowWidget)XtParent(widget);
2252     XmScrollBarWidget v_scrollbar;
2253     XmScrollBarWidget h_scrollbar;
2254
2255     switch (event->type) {
2256     case ButtonRelease:
2257         /*
2258          * Pop down the menu when Button is released inside the menu.
2259          */
2260         /* Doing the popdown here upon receiving ButtonRelease event, 
2261          * rather than in shell_even_hanlder(), is
2262          * essential to allow select_cb() to recognize that this 
2263          * XmNbrowseSelectionCallback is the last one in this popup session
2264          * and must treat it as a DtNselectionCallback
2265          */
2266         input_ungrab( combo_w, GRAB_KEYBOARD );
2267
2268         /* condition : ButtonRelease event
2269          *             cursor is outside the scrollbar(horizontal or vertical)
2270          * action:     call action routine "Release" of ScrollBar to release
2271          *             possible pressed slider arrow (up/down)
2272          */
2273         /* MotifBc */
2274         XtSetArg(args[0], XmNverticalScrollBar, &v_scrollbar);
2275         XtSetArg(args[1], XmNhorizontalScrollBar, &h_scrollbar);
2276         XtGetValues((Widget)sw, args, 2);
2277         if ( ScrollBarVisible((Widget)h_scrollbar) )
2278             XtCallActionProc((Widget)h_scrollbar, "Release", event,NULL,0);
2279         if ( ScrollBarVisible((Widget)v_scrollbar) )
2280             XtCallActionProc((Widget)v_scrollbar, "Release", event,NULL,0);
2281
2282         break;
2283     case FocusOut:
2284         /*
2285          * There is interaction conflict between the list and the
2286          * scrollbars in terms of Focus.  We always want our list
2287          * to have focus, so grab it back if we lose it.
2288          */
2289         if ( ShellPoppedUp(((ShellWidget)(Shell(combo_w)))) ) {
2290             _XmGrabKeyboard(widget, False, GrabModeAsync, GrabModeAsync, 
2291                             CurrentTime);
2292             XtSetKeyboardFocus(List(combo_w), None);
2293         }
2294         break;
2295     case EnterNotify:
2296         /* call ListBeginSelect() action directly to simulate Btn1Down*/
2297         {Display *disp = XtDisplay(List(combo_w));
2298          Window  win   = XtWindow(List(combo_w));
2299          Window  root;
2300          Window  child;
2301          XmListWidget  list;
2302          int     root_x, root_y, win_x, win_y, item_pos;
2303          unsigned int keys_buttons;
2304          unsigned char unit_type = XmPIXELS;
2305
2306          /* Resolution Independent */
2307          if ( MUnitType(combo_w) != XmPIXELS) {
2308                 unit_type = MUnitType(combo_w);
2309                 XtSetArg(args[0], XmNunitType, XmPIXELS);
2310                 XtSetValues(List(combo_w), args, 1);
2311          }
2312          root  = XDefaultRootWindow( disp );
2313          XQueryPointer ( disp, win, &root,
2314                                         &child, &root_x, &root_y,
2315                                         &win_x, &win_y, &keys_buttons );
2316          if ( keys_buttons & Button1Mask ) {
2317                 item_pos = XmListYToPos(List(combo_w), event->xbutton.y);
2318                 list = (XmListWidget)List(combo_w);
2319 /* MotifBc
2320  */
2321                 num_args = 0;
2322                 XtSetArg(args[num_args],XmNtopItemPosition,&top_item_position);
2323                 num_args ++;
2324                 XtSetArg(args[num_args], XmNvisibleItemCount, 
2325                         &visible_item_count);
2326                 num_args ++;
2327                 XtSetArg(args[num_args], XmNitemCount, &item_count);
2328                 num_args ++;
2329                 XtGetValues((Widget)list, args, num_args);
2330                 /* Adjust top_item_position value to its' internal form */
2331                 if (top_item_position)
2332                        top_item_position--;
2333                 else
2334                        top_item_position = item_count - 1;
2335
2336                 if((item_pos<1 ) ||
2337                    (item_pos>=(top_item_position + visible_item_count))||
2338                    (item_pos < top_item_position) ||
2339                    (item_pos >= item_count) )
2340                 {
2341                         Position item_x, item_y;
2342                         Dimension item_height, item_width;
2343                         
2344                         XmListPosToBounds((Widget)list, 
2345                                 ((top_item_position + visible_item_count )> 
2346                                  item_count)? item_count:
2347                                  (top_item_position + visible_item_count ),
2348                                 &item_x, &item_y, &item_width, &item_height);
2349
2350                         if ( item_pos ==0 && event->xbutton.y<(int)(item_height/2) )
2351                                 event->xbutton.y = item_height/2;
2352                         else
2353                                 event->xbutton.y = item_y + item_height/2;
2354                         event->xbutton.x = item_x;
2355                 }
2356                 
2357                 XtCallActionProc(List(combo_w), "ListBeginSelect",
2358                                                 /* XEvent */ event,
2359                                                 /* params */NULL,
2360                                                 /* num_params */0);
2361          }
2362          /* Resolution Independent */
2363          if ( unit_type != XmPIXELS) {
2364                 XtSetArg(args[0], XmNunitType, unit_type);
2365                 XtSetValues(List(combo_w), args, 1);
2366          }
2367         }
2368         break;
2369     }
2370 }
2371
2372
2373 /* Caller must free string */
2374 static char*
2375 GetTextString(XmString xm_string)
2376 {
2377     XmStringContext context;
2378     XmStringComponentType type;
2379     XmStringCharSet charset;
2380     XmStringDirection direction;
2381     XmStringComponentType unknown_tag;
2382     unsigned short ul;
2383     unsigned char *uv;
2384     char *text = NULL;
2385     Boolean done = FALSE;
2386
2387     XmStringInitContext(&context, xm_string);
2388     
2389     /* Loop until 1st char* found */
2390     while (!done) {
2391         type = XmStringGetNextComponent(context, &text, &charset,
2392                                         &direction, &unknown_tag, 
2393                                         &ul, &uv);
2394         switch (type) {
2395         case XmSTRING_COMPONENT_END:
2396             done = TRUE;
2397             break;
2398         case XmSTRING_COMPONENT_TEXT:
2399         case XmSTRING_COMPONENT_LOCALE_TEXT:
2400             done = TRUE;
2401             break;
2402         default:
2403             break;
2404         }
2405     }
2406     XmStringFreeContext(context);
2407     return(text);
2408 }
2409
2410 static void
2411 TextFieldActivate(DtComboBoxPart *combo_p, XtPointer call_data)
2412 {
2413     XmTextFieldWidget w = (XmTextFieldWidget)(combo_p->text);
2414     XmListWidget list = (XmListWidget)combo_p->list;
2415     XmAnyCallbackStruct cb;
2416     char *data = NULL;
2417     char *text = NULL;
2418     Arg arg;
2419     XmStringTable list_items;
2420     
2421     XtSetArg(arg, XmNvalue, &data);
2422     XtGetValues((Widget)w, &arg, 1);
2423 /* MotifBc
2424  */
2425     XtSetArg(arg, XmNitems, &list_items);
2426     XtGetValues((Widget)list, &arg, 1);
2427
2428     if ( list_items)
2429         text = GetTextString(list_items[combo_p->selected_position]);
2430
2431     if (text && data && (strcmp(text, data) == 0)) {
2432         XtFree(text);
2433     }
2434     /* Only send callback if both are not NULL */
2435     else if (!((text == NULL) && (data == NULL))) {
2436         XmAnyCallbackStruct *local_cb = (XmAnyCallbackStruct *)call_data;
2437
2438         cb.reason = XmCR_ACTIVATE;
2439         cb.event  = local_cb ? local_cb->event : NULL;
2440 /* MotifBc
2441  */
2442         if (XtHasCallbacks((Widget)w, XmNactivateCallback)==XtCallbackHasSome)
2443                XtCallCallbacks((Widget)w, XmNactivateCallback, 
2444                                (XtPointer) &cb);
2445         if (text)   
2446             XtFree(text);
2447     }
2448
2449     if ( data )
2450         XtFree (data);
2451 }
2452
2453 /*
2454  * This is the activate callback for the arrow button.  This 
2455  * sets the shell position and width, does the correct grabs, and
2456  * puts the shell on the screen.
2457  */
2458 static void
2459 activate_cb(    Widget w,
2460                 XtPointer client_data,
2461                 XtPointer call_data)
2462 {
2463     DtComboBoxWidget combo_w = (DtComboBoxWidget)client_data;
2464     DtComboBoxPart *combo_p = (DtComboBoxPart*)
2465         &(XmField(combo_w,ipot,DtComboBox,arrow,Widget));
2466     Display *disp = XtDisplayOfObject((Widget)combo_w);
2467     XmDisplay xmdisp = (XmDisplay) XmGetXmDisplay(disp);
2468     int screen;
2469     Dimension width, height;
2470     Dimension disp_width, disp_height;
2471     Position root_x, root_y, root_y0;
2472     Arg args[5];
2473     int n;
2474     unsigned char unit_type = XmPIXELS;
2475
2476     /* Resolution Independent Handling */
2477     XtSetArg(args[0], XmNunitType, &unit_type);
2478     XtGetValues((Widget)combo_w, args, 1);
2479    /* Getting Focus */
2480    if ( !_XmFocusIsHere( (Widget)combo_w) )
2481     XmProcessTraversal((Widget)combo_w, 
2482                         (XmTraversalDirection) XmTRAVERSE_CURRENT);
2483
2484     if (Type(combo_w) == DtDROP_DOWN_COMBO_BOX)
2485         TextFieldActivate(combo_p, call_data);
2486
2487     /*
2488      * Don't popup if no items in the list.
2489      */
2490 /* MotifBc
2491  */
2492     XtSetArg(args[0], XmNitemCount, &n);
2493     XtGetValues(((Widget)List(combo_w)), args, 1);
2494     if ( n != ItemCount(combo_w) )
2495         SyncWithList(combo_p);
2496     if ( !n )
2497         return;
2498
2499     screen = DefaultScreen(disp);
2500     disp_width = DisplayWidth(disp, screen);
2501     disp_height = DisplayHeight(disp, screen);
2502
2503     /*
2504      * Call the menu-post callback if requested.  This allows the
2505      * user to change the items, instead of using the losing-focus callback.
2506      * If the user used the losing-focus callback to change the items, the
2507      * size of the list/shell will change while it is popped up.  We
2508      * could disallow SetValues while the menu is posted, but let's see
2509      * how things go first.
2510      */
2511     if (MenuPostCallback(combo_w)) {
2512         XmAnyCallbackStruct info;
2513
2514         info.reason = DtCR_MENU_POST;
2515         info.event = (XEvent*)NULL;
2516         XtCallCallbackList((Widget)combo_w, MenuPostCallback(combo_w), 
2517                            (XtPointer)&info);
2518     }
2519
2520     width = MaxShellWidth(combo_w);
2521     height = MaxShellHeight(combo_w);
2522
2523
2524     /* Get root coords of ComboBox */
2525     XtTranslateCoords((Widget)combo_w, X(combo_w), Y(combo_w),
2526                       &root_x, &root_y);
2527         root_y0 = root_y;
2528
2529     /*
2530      * Make necessary adjustments for offset of our widget 
2531      * inside its' parent.  Calculate the width of the shell.
2532      * This must be done every time the shell gets popped up, because 
2533      * the x/y can change as well as the width (from list's visibleItemCount 
2534      * or geometry management changes).
2535      */
2536     root_x -= X(combo_w);
2537     root_y -= Y(combo_w);
2538     root_y += (Height(combo_w) - COMBO_MARGIN_H(combo_w));
2539
2540     /*
2541      * Make sure the shell is at least as big as our combo-box, and
2542      * make sure it stays on the screen.
2543      */
2544         /* to enforce a scrollbar with Shell */
2545     if (width < Width(combo_w))
2546         {
2547                 Dimension sb_width, spacing, list_width;
2548                 Widget sb;
2549                 n = 0;
2550                 XtSetArg(args[n], XmNverticalScrollBar, &sb); n++;
2551                 XtSetArg(args[n], XmNspacing, &spacing); n++;
2552                 XtGetValues(XtParent(List(combo_w)), args, n);
2553                 /* Resolution Independent Resource */
2554                 if ( unit_type != XmPIXELS) {
2555                         n = XmConvertUnits(List(combo_w), XmHORIZONTAL, 
2556                                 (int)unit_type, spacing, XmPIXELS);     
2557                         spacing = n;
2558                 }
2559                 if (sb && XtIsWidget(sb) ) {
2560                     n = 0;
2561                     XtSetArg(args[n], XmNwidth, &sb_width); n++;
2562                     XtGetValues(sb, args, n);
2563                     /* Resolution Independent Resource */
2564                     if (unit_type != XmPIXELS) { 
2565                         n = XmConvertUnits(sb, XmHORIZONTAL, 
2566                                 (int)unit_type, sb_width, XmPIXELS);
2567                         sb_width = n;
2568                     } 
2569                 }
2570                 else
2571                         sb_width = 0;
2572
2573                 n = 0;
2574                 width = Width(combo_w);
2575                 list_width = ( ScrollBarVisible(sb) ?
2576                                 (width - sb_width - spacing)
2577                                 :(width - spacing) );
2578
2579                 if (unit_type != XmPIXELS) {
2580                         n = XmConvertUnits(sb, XmHORIZONTAL,
2581                                 XmPIXELS, list_width, (int)unit_type);
2582                         list_width = n; n=0;
2583                 }
2584                 XtSetArg(args[n], XmNwidth, list_width); n++;
2585                 XtSetValues(List(combo_w), args, n);
2586         }
2587     if ((int)(root_x + width) > (int)disp_width)
2588         root_x = (disp_width - width);
2589         else if (root_x <=0)
2590         root_x = 0;
2591         else 
2592           ;
2593
2594     if ((int)(root_y + height) > (int)disp_height)
2595         root_y = root_y0 - Y(combo_w) - height;
2596
2597     if (unit_type != XmPIXELS) {
2598         XtSetArg(args[0], XmNunitType, XmPIXELS);
2599         XtSetValues(Shell(combo_w), args, 1);
2600     }
2601     n = 0;
2602     XtSetArg(args[n], XmNx, root_x); n++;
2603     XtSetArg(args[n], XmNy, root_y); n++;
2604     XtSetValues(Shell(combo_w), args, n);
2605     if (unit_type != XmPIXELS) {
2606         XtSetArg(args[0], XmNunitType, unit_type); 
2607         XtSetValues(Shell(combo_w), args, 1); 
2608     } 
2609
2610
2611     PoppedUp(combo_w) = TRUE;
2612     XtPopup(Shell(combo_w), XtGrabNone);
2613
2614     /*
2615      * Set up the grab for the shell and list.  The shell gets the
2616      * pointer grab so that events will go into the list and scrollbars
2617      * correctly, but events outside the shell will go to the shell.
2618      * See shell and list event handlers for details about grabs.
2619      */
2620     _XmAddGrab(Shell(combo_w), True, True);
2621     _XmGrabPointer(Shell(combo_w), True, ButtonPressMask |ButtonReleaseMask,
2622                         GrabModeAsync, GrabModeAsync, None, 
2623                    XmGetMenuCursor(disp), CurrentTime);
2624     _XmGrabKeyboard(List(combo_w), False, GrabModeAsync, GrabModeAsync, 
2625                    CurrentTime);
2626     xmdisp->display.userGrabbed = True;
2627         
2628     /*
2629      * Where to define the cursor for the list widget.  It would be
2630      * nice to do it in the list's realize function, but that's not
2631      * possible.  We can't use the ComboBox realize function, because
2632      * the list isn't realized at that point.  This is the simpliest
2633      * way to get this done.  This is needed to make sure the list has the
2634      * correct menu during browse scrolling, etc.
2635      */
2636     XDefineCursor(disp, XtWindowOfObject(Shell(combo_w)), 
2637                   XmGetMenuCursor(disp));
2638 }
2639
2640
2641 /*
2642  * Make sure arrow is symetrical. 45 degree angle.  I'm not sure how
2643  * inefficient get/releasing the GC every time is (they are cached by
2644  * the toolkit)?
2645  */
2646 static void
2647 arrow_expose_cb(Widget w,
2648                 XtPointer client_data,
2649                 XtPointer call_data)
2650 {
2651     DtComboBoxWidget combo_w = (DtComboBoxWidget)client_data;
2652     Display *disp = XtDisplayOfObject(w);
2653     Window win = XtWindowOfObject(w);
2654     XGCValues values;
2655     short center_w;
2656     short center_h;
2657     XPoint points[10];
2658     Arg args[3];
2659     GC gc;
2660     Dimension arrow_width, arrow_height;
2661     unsigned char unit_type = XmPIXELS;
2662
2663     /* Resolution Independent */
2664     if ( MUnitType(combo_w) != XmPIXELS ) {
2665         unit_type = MUnitType(combo_w);
2666         XtSetArg(args[0], XmNunitType, XmPIXELS);
2667         XtSetValues(w, args, 1);
2668     }
2669     /* MotifBc */
2670     XtSetArg(args[0], XmNwidth, &arrow_width);
2671     XtSetArg(args[1], XmNheight, &arrow_height);
2672     XtSetArg(args[2], XmNforeground, &(values.foreground));
2673     XtGetValues(w, args, 3);
2674     center_w = arrow_width/2;
2675     center_h = (int) (arrow_height -3.)/2;
2676
2677     values.line_width = 0;
2678     values.line_style = LineSolid;
2679     values.fill_style = FillSolid;
2680     gc = XtGetGC(w, GCForeground | GCFillStyle | GCLineStyle | GCLineWidth,
2681                  &values);
2682
2683     XDrawLine(disp, win, gc, 1, center_h + center_w + 1, Width(w) - 2,
2684               center_h + center_w + 1);
2685
2686     /* A - bottom point */
2687     points[0].x = center_w;
2688     points[0].y = center_h + (int)(center_w * .8);
2689
2690     /* B - far left point */
2691     points[1].x = center_w - (int)(center_w * .8);
2692     points[1].y = center_h;
2693
2694     /* C  - inner left point */
2695     points[2].x = center_w - (int)(center_w * .3);
2696     points[2].y = points[1].y;
2697
2698     /* D - top left point */
2699     points[3].x = points[2].x;
2700     points[3].y = center_h - (int)(center_w * .8);
2701
2702     /* E - top right point */
2703     points[4].x = center_w + (int)(center_w * .3);
2704     points[4].y = points[3].y;
2705
2706     /* F - inner right point */
2707     points[5].x = points[4].x;
2708     points[5].y = points[1].y;
2709
2710     /* G - far right point */
2711     points[6].x = center_w + (int)(center_w * .8);
2712     points[6].y = points[1].y;
2713
2714     /* A - bottom point */
2715     points[7].x = points[0].x;
2716     points[7].y = points[0].y;
2717
2718     XDrawLines(disp, win, gc, points, 8, CoordModeOrigin);
2719     XFillPolygon(disp, win, gc, points, 8, Convex, CoordModeOrigin);
2720     XtReleaseGC(w, gc);
2721
2722     /* Resolution Independent */
2723     if ( unit_type != XmPIXELS ) {
2724         XtSetArg(args[0], XmNunitType, unit_type);
2725         XtSetValues(w, args, 1);
2726     }
2727 }
2728
2729 /*
2730  * We get the text-field losing-focus callback, so pass it on to
2731  * the user if they requested it.  Our losing-focus callback 
2732  * is just a convenience callback, so that the user doesn't
2733  * have to get the text-field first.  This make our integration
2734  * with XDesigner a little easier.d
2735  */
2736 static void
2737 text_losing_focus_cb(   Widget w,
2738                         XtPointer client_data,
2739                         XtPointer call_data)
2740 {
2741     DtComboBoxWidget combo = (DtComboBoxWidget)client_data;
2742     DtComboBoxPart *combo_p = (DtComboBoxPart*)
2743         &(XmField(combo,ipot,DtComboBox,arrow,Widget));
2744     XmTextFieldWidget wt=(XmTextFieldWidget) Text(combo);
2745     XmString xmStr;
2746     Arg arg;
2747     String text_string;
2748     int i, need_sync_flag=1;
2749 /* MotifBc
2750  */
2751     XtSetArg(arg, XmNvalue, &text_string);
2752     XtGetValues((Widget)wt, &arg, 1);
2753     xmStr = (XmString) XmStringCreateLocalized(text_string?text_string:"");
2754     if ( text_string )
2755         XtFree (text_string);
2756
2757     if (LosingFocusCallback(combo))
2758         XtCallCallbackList((Widget)combo, LosingFocusCallback(combo), 
2759                            (XtPointer)call_data);
2760
2761     /* To synchronize the ComboBox record with XmList */
2762     XtVaGetValues(List(combo), XmNitemCount, &i, NULL);
2763     if (i != ItemCount(combo) ) {
2764         SyncWithList(combo_p);
2765         need_sync_flag = 0;
2766     }
2767         
2768     for (i = 0; i < ItemCount(combo); i++) {
2769         if ( need_sync_flag && 
2770              !( (ListItems(combo))[i] && XmeStringIsValid((ListItems(combo))[i]) )) {
2771             SyncWithList(combo_p);
2772             need_sync_flag = 0;
2773         }
2774         if (XmStringCompare(xmStr, (ListItems(combo))[i]))
2775             break;
2776     }
2777
2778     if (i < ItemCount(combo) && i != SelectedPosition(combo) ) {
2779         SelectedPosition(combo) = i;
2780         if (SelectedItem(combo))
2781             XmStringFree(SelectedItem(combo));
2782         SelectedItem(combo) = xmStr;
2783         if (Type(combo) == DtDROP_DOWN_COMBO_BOX)
2784             SetTextFieldData(combo_p, NULL);
2785         else
2786             SetLabelData(combo_p, NULL, FALSE);
2787         XmListSetPos(List(combo), SelectedPosition(combo) + 1);
2788         XmListSelectPos(List(combo), SelectedPosition(combo) + 1, True);
2789         
2790         XtVaGetValues(List(combo), XmNtopItemPosition,
2791                       &(combo_p->top_item_position), NULL);
2792     }
2793     else
2794         XmStringFree( xmStr );
2795 }
2796
2797 /*
2798  * We get the text-field activate callback, so pass it on to
2799  * the user if they requested it.  Our activate callback 
2800  * is just a convenience callback, so that the user doesn't
2801  * have to get the text-field first.  This make our integration
2802  * with XDesigner a little easier.
2803  */
2804 static void
2805 text_activate_cb(       Widget w,
2806                         XtPointer client_data,
2807                         XtPointer call_data)
2808 {
2809     DtComboBoxWidget combo = (DtComboBoxWidget)client_data;
2810     DtComboBoxPart *combo_p = (DtComboBoxPart*)
2811         &(XmField(combo,ipot,DtComboBox,arrow,Widget));
2812     XmTextFieldWidget wt=(XmTextFieldWidget) Text(combo);
2813     XmString xmStr;
2814     Arg arg;
2815     String text_string;
2816     int i, need_sync_flag=1;
2817 /* MotifBc
2818  */
2819     XtSetArg(arg, XmNvalue, &text_string);
2820     XtGetValues((Widget)wt, &arg, 1);
2821     xmStr = (XmString) XmStringCreateLocalized(text_string?text_string:"");
2822     if ( text_string )
2823         XtFree (text_string);
2824
2825     if (ActivateCallback(combo))
2826         XtCallCallbackList((Widget)combo, 
2827                            ActivateCallback(combo),
2828                            (XtPointer)call_data);
2829
2830     /* To synchronize the ComboBox record with XmList */
2831     XtVaGetValues(List(combo), XmNitemCount, &i, NULL);
2832     if (i != ItemCount(combo) ) {
2833         SyncWithList(combo_p);
2834         need_sync_flag = 0;
2835     }
2836         
2837     for (i = 0; i < ItemCount(combo); i++) {
2838         if ( need_sync_flag && 
2839              !( (ListItems(combo))[i] && 
2840                XmeStringIsValid((ListItems(combo))[i]) )) {
2841             SyncWithList(combo_p);
2842             need_sync_flag = 0;
2843         }
2844         if (XmStringCompare(xmStr, (ListItems(combo))[i]))
2845             break;
2846     }
2847
2848     if (i < ItemCount(combo) && i != SelectedPosition(combo) ) {
2849         SelectedPosition(combo) = i;
2850         if (SelectedItem(combo))
2851             XmStringFree(SelectedItem(combo));
2852         SelectedItem(combo) = xmStr;
2853         if (Type(combo) == DtDROP_DOWN_COMBO_BOX)
2854             SetTextFieldData(combo_p, NULL);
2855         else
2856             SetLabelData(combo_p, NULL, FALSE);
2857         XmListSetPos(List(combo), SelectedPosition(combo) + 1);
2858         XmListSelectPos(List(combo), SelectedPosition(combo) + 1, True);
2859         XtVaGetValues(List(combo), XmNtopItemPosition,
2860                       &(combo_p->top_item_position), NULL);
2861     }
2862     else
2863         XmStringFree( xmStr );
2864 }
2865
2866
2867 /*
2868  * We get the text-field focus callback, so pass it on to
2869  * the user if they requested it.  Our focus callback 
2870  * is just a convenience callback, so that the user doesn't
2871  * have to get the text-field first.  This make our integration
2872  * with XDesigner a little easier.
2873  */
2874 static void
2875 text_focus_cb(  Widget w,
2876                 XtPointer client_data,
2877                 XtPointer call_data)
2878 {
2879     DtComboBoxWidget combo = (DtComboBoxWidget)client_data;
2880
2881     if (FocusCallback(combo))
2882         XtCallCallbackList((Widget)combo, FocusCallback(combo), 
2883                            (XtPointer)call_data);
2884 }
2885
2886 /*
2887  * Try and keep our list related rsources in sync with the list widget.
2888  * This is not always possible, depending on if the programmer makes
2889  * list widget calls directly.  If we get out of sync with the
2890  * list widget, our SetValues() may not work correctly (when the
2891  * comparisons are done).  Should do get values in case list widget
2892  * names are changed?
2893  */
2894 static void
2895 SyncWithList(DtComboBoxPart *combo_p)
2896 {
2897     XmListWidget list = (XmListWidget)combo_p->list;
2898     Arg         args[10];
2899     int         num_args;
2900     unsigned char unit_type = XmPIXELS;
2901
2902 /* Resolution Independent */
2903     XtSetArg(args[0],XmNunitType,&unit_type); 
2904     XtGetValues((Widget)list, args, 1);
2905     if (unit_type != XmPIXELS) {
2906         XtSetArg(args[0],XmNunitType,XmPIXELS); 
2907         XtSetValues((Widget)list, args, 1);
2908     }
2909 /* MotifBc
2910  */
2911     num_args = 0;
2912     XtSetArg(args[num_args],XmNitems,&(combo_p->list_items)); num_args ++;
2913     XtSetArg(args[num_args],XmNitems,&(combo_p->items)); num_args ++;
2914     XtSetArg(args[num_args],XmNitemCount,&(combo_p->item_count)); num_args ++;
2915     XtSetArg(args[num_args],XmNfontList,&(combo_p->list_font_list));
2916     num_args ++;
2917     XtSetArg(args[num_args],XmNlistMarginHeight,&(combo_p->list_margin_height));
2918     num_args ++;
2919     XtSetArg(args[num_args],XmNlistMarginWidth,&(combo_p->list_margin_width));
2920     num_args ++;
2921     XtSetArg(args[num_args],XmNlistSpacing,&(combo_p->list_spacing));
2922     num_args ++;
2923     XtSetArg(args[num_args],XmNtopItemPosition,&(combo_p->top_item_position));
2924     num_args ++;
2925     XtSetArg(args[num_args],XmNvisibleItemCount,&(combo_p->visible_item_count));
2926     num_args ++;
2927     XtGetValues((Widget)list, args, num_args);
2928     /* Adjustment with empty list */
2929     if (! combo_p->item_count) {
2930         combo_p->items = NULL;
2931         combo_p->list_items = NULL;
2932     }
2933
2934 /* Resolution Independent */
2935     if (unit_type != XmPIXELS) {
2936         XtSetArg(args[0],XmNunitType,unit_type); 
2937         XtSetValues((Widget)list, args, 1);
2938     }
2939 }
2940
2941 /*
2942  * Routines which manipulate the ComboBox list.  These are external
2943  * for use by users of our widget.
2944  */
2945 Widget 
2946 DtCreateComboBox(Widget parent,
2947                 char *name,
2948                 ArgList arglist,
2949                 Cardinal num_args)
2950 {
2951     return(XtCreateWidget(name, dtComboBoxWidgetClass, parent,
2952                           arglist, num_args));
2953 }
2954
2955 void
2956 DtComboBoxAddItem(      Widget combow,
2957                         XmString item,
2958                         int pos,
2959                         Boolean unique)
2960 {
2961     DtComboBoxWidget combo = (DtComboBoxWidget)combow;
2962     DtComboBoxPart *combo_p = (DtComboBoxPart*)
2963         &(XmField(combo,ipot,DtComboBox,arrow,Widget));
2964     XmStringTable list_items;
2965     int i;
2966     Arg arg;
2967     _DtWidgetToAppContext(combow);
2968     _DtAppLock(app);
2969
2970     /* Try to help confused applications. */
2971     if (XmIsComboBox(combow))
2972       {
2973         XmComboBoxAddItem(combow, item, pos, unique);
2974         _DtAppUnlock(app);
2975         return;
2976       }
2977
2978 /* MotifBc
2979  */
2980     XtSetArg(arg, XmNitems, &list_items);
2981     XtGetValues(((Widget)List(combo)), &arg, 1);
2982
2983     if (item && list_items) {
2984         for (i = 0; i < ItemCount(combo); i++)
2985             if (XmStringCompare(item, list_items[i]))
2986                 break;
2987         if ((i < ItemCount(combo)) && unique)
2988           {
2989             _DtAppUnlock(app);
2990             return;
2991           }
2992     }
2993
2994     XmListAddItemUnselected(List(combo), item, pos);
2995     SyncWithList(combo_p);
2996
2997     if (Label(combo)) {
2998         SetMaximumLabelSize(combo_p);
2999         if (Type(combo) == DtDROP_DOWN_LIST) {
3000             ClearShadow(combo, TRUE);
3001             if (RecomputeSize(combo))
3002                 SetComboBoxSize(combo);
3003             LayoutChildren(combo);
3004             DrawShadow(combo);
3005         }
3006     }
3007     if (Type(combo) == DtDROP_DOWN_COMBO_BOX)
3008         SetTextFieldData(combo_p, NULL);
3009     else
3010         SetLabelData(combo_p, NULL, FALSE);
3011
3012     _DtAppUnlock(app);
3013 }
3014
3015
3016
3017 void
3018 DtComboBoxDeletePos(    Widget combow,
3019                         int pos)
3020 {
3021     DtComboBoxWidget combo = (DtComboBoxWidget)combow;
3022     DtComboBoxPart *combo_p = (DtComboBoxPart*)
3023         &(XmField(combo,ipot,DtComboBox,arrow,Widget));
3024     int selection_changed = 0;
3025     _DtWidgetToAppContext(combow);
3026     _DtAppLock(app);
3027
3028     /* Try to help confused applications. */
3029     if (XmIsComboBox(combow))
3030       {
3031         XmComboBoxDeletePos(combow, pos);
3032         _DtAppUnlock(app);
3033         return;
3034       }
3035
3036     if ( pos <= 0 || pos >combo_p->item_count ) {
3037         XtWarning(CB_DEL_POS);
3038         _DtAppUnlock(app);
3039         return;
3040     }
3041
3042     XmListDeletePos(List(combo), pos);
3043     if ( pos == (combo_p->selected_position+1) ) {
3044         /* Since we delete the current item, we have to set one */
3045         if ( pos == combo_p->item_count && combo_p->selected_position>0) {
3046             combo_p->selected_position--;
3047             selection_changed ++;
3048         }
3049         XmListSelectPos(List(combo), combo_p->selected_position+1, True);
3050     }
3051     else if ( pos <= combo_p->selected_position) {
3052         combo_p->selected_position--;
3053         selection_changed ++;
3054     }   
3055     SyncWithList(combo_p);
3056     if ( selection_changed ) {
3057         if ( combo_p->selected_item )
3058             XmStringFree(combo_p->selected_item );
3059         combo_p->selected_item = 
3060             ItemCount(combo)?
3061                 XmStringCopy(combo_p->list_items[combo_p->selected_position]):
3062                 (XmString) NULL;
3063     }
3064
3065     if (Label(combo)) {
3066         SetMaximumLabelSize(combo_p);
3067         if (Type(combo) == DtDROP_DOWN_LIST) {
3068             ClearShadow(combo, TRUE);
3069             if (RecomputeSize(combo))
3070                 SetComboBoxSize(combo);
3071             LayoutChildren(combo);
3072             DrawShadow(combo);
3073         }
3074     }
3075     if (Type(combo) == DtDROP_DOWN_COMBO_BOX)
3076         SetTextFieldData(combo_p, NULL);
3077     else
3078         SetLabelData(combo_p, NULL, FALSE);
3079
3080     _DtAppUnlock(app);
3081 }
3082
3083 void
3084 DtComboBoxSetItem(      Widget combow,
3085                         XmString item)
3086 {
3087     DtComboBoxWidget combo = (DtComboBoxWidget)combow;
3088     DtComboBoxPart *combo_p = (DtComboBoxPart*)
3089         &(XmField(combo,ipot,DtComboBox,arrow,Widget));
3090     XmStringTable list_items;
3091     int i;
3092     Arg arg;
3093     _DtWidgetToAppContext(combow);
3094     _DtAppLock(app);
3095
3096     /* Try to help confused applications. */
3097     if (XmIsComboBox(combow))
3098       {
3099         XmComboBoxSetItem(combow, item);
3100         _DtAppUnlock(app);
3101         return;
3102       }
3103
3104 /* MotifBc
3105  */
3106     XtSetArg(arg, XmNitems, &list_items);
3107     XtGetValues(((Widget)List(combow)), &arg, 1);
3108
3109     if (item && list_items) {
3110         for (i = 0; i < ItemCount(combo); i++)
3111             if (XmStringCompare(item, list_items[i]))
3112                 break;
3113         if (i < ItemCount(combo)) {
3114             SelectedPosition(combo) = i;
3115             if (SelectedItem(combo))
3116                 XmStringFree(SelectedItem(combo));
3117             SelectedItem(combo) = XmStringCopy(item);
3118             if (Type(combo) == DtDROP_DOWN_COMBO_BOX)
3119                 SetTextFieldData(combo_p, NULL);
3120             else
3121                 SetLabelData(combo_p, NULL, FALSE);
3122             XmListSetItem(List(combo), item);
3123             XmListSelectItem(List(combo), item, FALSE);
3124             SyncWithList(combo_p);
3125         }
3126         else
3127             XtWarning(CB_SET_ITEM);
3128     }
3129     else
3130         XtWarning(CB_SET_ITEM);
3131
3132     _DtAppUnlock(app);
3133 }
3134
3135 void
3136 DtComboBoxSelectItem(   Widget combow,
3137                         XmString item)
3138 {
3139     DtComboBoxWidget combo = (DtComboBoxWidget)combow;
3140     DtComboBoxPart *combo_p = (DtComboBoxPart*)
3141         &(XmField(combo,ipot,DtComboBox,arrow,Widget));
3142     XmStringTable list_items;
3143     XmString tmpStr;
3144     int i;
3145     Arg arg;
3146     _DtWidgetToAppContext(combow);
3147     _DtAppLock(app);
3148
3149     /* Try to help confused applications. */
3150     if (XmIsComboBox(combow))
3151       {
3152         XmComboBoxSelectItem(combow, item);
3153         _DtAppUnlock(app);
3154         return;
3155       }
3156
3157 /* MotifBc
3158  */
3159     XtSetArg(arg, XmNitems, &list_items);
3160     XtGetValues(((Widget)List(combo)), &arg, 1);
3161
3162     if (item && list_items) {
3163         for (i = 0; i < ItemCount(combo); i++)
3164             if (XmStringCompare(item, list_items[i]))
3165                 break;
3166         if (i < ItemCount(combo)) {
3167             SelectedPosition(combo) = i;
3168             tmpStr=SelectedItem(combo);
3169             SelectedItem(combo) = XmStringCopy(item);
3170             if (Type(combo) == DtDROP_DOWN_COMBO_BOX)
3171                 SetTextFieldData(combo_p, NULL);
3172             else
3173                 SetLabelData(combo_p, NULL, FALSE);
3174             XmListDeselectAllItems(List(combo));
3175             XmListSelectItem(List(combo), item, FALSE);
3176             if(tmpStr)
3177                 XmStringFree(tmpStr);
3178             SyncWithList(combo_p);
3179         }
3180         else
3181             XtWarning(CB_SELECT_ITEM);
3182     }
3183     else
3184         XtWarning(CB_SELECT_ITEM);
3185
3186     _DtAppUnlock(app);
3187 }
3188
3189
3190 /*
3191  * Synthetic GetValues for List resources.
3192  */
3193
3194 static XmImportOperator
3195 _XmSetSyntheticResForChild(     Widget widget,
3196                                 int offset,
3197                                 XtArgVal * value)
3198
3199     return(XmSYNTHETIC_LOAD);
3200 }
3201
3202 void
3203 _DtComboBoxGetArrowSize(Widget w,
3204                         int resource_offset,
3205                         XtArgVal *value)
3206 {
3207     DtComboBoxWidget combo = (DtComboBoxWidget)w;
3208     Dimension data;
3209     Arg arg;
3210
3211     XtSetArg(arg, XmNheight, &data);
3212     XtGetValues(Arrow(combo), &arg, 1);
3213     *value = (XtArgVal)data;
3214 }
3215
3216 void
3217 _DtComboBoxGetLabelString(      Widget w,
3218                                 int resource_offset,
3219                                 XtArgVal *value)
3220 {
3221     DtComboBoxWidget combo = (DtComboBoxWidget)w;
3222
3223     if (LabelString(combo))
3224         *value = (XtArgVal)XmStringCopy(LabelString(combo));
3225     else
3226         *value = (XtArgVal)NULL;
3227 }
3228
3229 void
3230 _DtComboBoxGetListItemCount(    Widget w,
3231                                 int resource_offset,
3232                                 XtArgVal *value)
3233 {
3234     DtComboBoxWidget combo = (DtComboBoxWidget)w;
3235     int data;
3236     Arg arg;
3237
3238     XtSetArg(arg, XmNitemCount, &data);
3239     XtGetValues(List(combo), &arg, 1);
3240     *value = (XtArgVal)data;
3241 }
3242
3243 void
3244 _DtComboBoxGetListItems(Widget w,
3245                         int resource_offset,
3246                         XtArgVal *value)
3247 {
3248     DtComboBoxWidget combo = (DtComboBoxWidget)w;
3249     XmStringTable data;
3250     Arg arg;
3251
3252     XtSetArg(arg, XmNitems, &data);
3253     XtGetValues(List(combo), &arg, 1);
3254     *value = (XtArgVal)data;
3255 }
3256
3257 void
3258 _DtComboBoxGetListFontList(     Widget w,
3259                                 int resource_offset,
3260                                 XtArgVal *value)
3261 {
3262     DtComboBoxWidget combo = (DtComboBoxWidget)w;
3263     XmFontList data;
3264     Arg arg;
3265
3266     XtSetArg(arg, XmNfontList, &data);
3267     XtGetValues(List(combo), &arg, 1);
3268     *value = (XtArgVal)data;
3269 }
3270
3271 void
3272 _DtComboBoxGetListMarginHeight( Widget w,
3273                                 int resource_offset,
3274                                 XtArgVal *value)
3275 {
3276     DtComboBoxWidget combo = (DtComboBoxWidget)w;
3277     Dimension data;
3278     Arg arg;
3279
3280     XtSetArg(arg, XmNmarginHeight, &data);
3281     XtGetValues(List(combo), &arg, 1);
3282     *value = (XtArgVal)data;
3283 }
3284
3285 void
3286 _DtComboBoxGetListMarginWidth(  Widget w,
3287                                 int resource_offset,
3288                                 XtArgVal *value)
3289 {
3290     DtComboBoxWidget combo = (DtComboBoxWidget)w;
3291     Dimension data;
3292     Arg arg;
3293
3294     XtSetArg(arg, XmNmarginWidth, &data);
3295     XtGetValues(List(combo), &arg, 1);
3296     *value = (XtArgVal)data;
3297 }
3298
3299 void
3300 _DtComboBoxGetListSpacing(      Widget w,
3301                                 int resource_offset,
3302                                 XtArgVal *value)
3303 {
3304     DtComboBoxWidget combo = (DtComboBoxWidget)w;
3305     Dimension data;
3306     Arg arg;
3307
3308     XtSetArg(arg, XmNspacing, &data);
3309     XtGetValues(List(combo), &arg, 1);
3310     *value = (XtArgVal)data;
3311 }
3312
3313 void
3314 _DtComboBoxGetListTopItemPosition(      Widget w,
3315                                         int resource_offset,
3316                                         XtArgVal *value)
3317 {
3318     DtComboBoxWidget combo = (DtComboBoxWidget)w;
3319     int data;
3320     Arg arg;
3321
3322     XtSetArg(arg, XmNtopItemPosition, &data);
3323     XtGetValues(List(combo), &arg, 1);
3324     *value = (XtArgVal)data;
3325 }
3326
3327 void
3328 _DtComboBoxGetListVisibleItemCount(     Widget w,
3329                                         int resource_offset,
3330                                         XtArgVal *value)
3331 {
3332     DtComboBoxWidget combo = (DtComboBoxWidget)w;
3333     int data;
3334     Arg arg;
3335
3336     XtSetArg(arg, XmNvisibleItemCount, &data);
3337     XtGetValues(List(combo), &arg, 1);
3338     *value = (XtArgVal)data;
3339 }
3340
3341 static Boolean
3342 _CvtStringToType(
3343 Display *dpy,
3344 XrmValuePtr args,
3345 Cardinal *num_args,
3346 XrmValuePtr from, 
3347 XrmValuePtr to,
3348 XtPointer *data)
3349 {
3350     char *from_str;
3351     static unsigned char to_value;
3352
3353     if(*num_args !=0 ) {
3354         XtError(CB_CVTSTRING);
3355     }
3356
3357     from_str = (char *)from->addr;
3358     if(strcmp(from_str, "DROP_DOWN_LIST")==0 ||
3359        strcmp(from_str, "drop_down_list")==0 ||
3360        strcmp(from_str, "DtDROP_DOWN_LIST")==0)
3361         to_value = DtDROP_DOWN_LIST;
3362     else if (strcmp(from_str, "DROP_DOWN_COMBO_BOX")==0 ||
3363              strcmp(from_str, "drop_down_combo_box")==0 ||
3364              strcmp(from_str, "DtDROP_DOWN_COMBO_BOX")==0)
3365         to_value = DtDROP_DOWN_COMBO_BOX;
3366     else {
3367         XtDisplayStringConversionWarning(dpy, from->addr, "ComboBoxType");
3368         return False;
3369     }
3370
3371     if (to->addr == NULL) to->addr = (caddr_t) &to_value;
3372     else if (to->size <sizeof(unsigned char)) {
3373         XtDisplayStringConversionWarning(dpy, from->addr, "ComboBoxType");
3374         return False;
3375     }
3376     else
3377         *(unsigned char *) to->addr = to_value;
3378
3379     to->size = sizeof(unsigned char);
3380
3381     return True;
3382 }
3383
3384 static void     
3385 input_ungrab ( DtComboBoxWidget combo, int ungrab_mask)
3386 {
3387     XmDisplay disp = (XmDisplay) XmGetXmDisplay(XtDisplay(combo));
3388
3389     if ( ungrab_mask & GRAB_POINTER )
3390         XtUngrabPointer(Shell(combo), CurrentTime);
3391     if ( ungrab_mask & GRAB_KEYBOARD )
3392         XtUngrabKeyboard(List(combo), CurrentTime);
3393     _XmRemoveGrab(Shell(combo));
3394     
3395     /* We move XtPopdown() here and do _XmRemoveGrab first.
3396      * This is a fix to solve an MR in Desktop which over a time period
3397      * develope a possible core-dump due to duplicated removeGrab() calls
3398      */
3399     PoppedUp(combo) = FALSE;
3400     XtPopdown(Shell(combo));
3401     if (Type(combo) == DtDROP_DOWN_COMBO_BOX)
3402         XmProcessTraversal(Text(combo), XmTRAVERSE_CURRENT);
3403
3404     /* This is to enable the Drag-and-Drop operation */
3405     disp->display.userGrabbed = False;
3406 }