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