home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / xfe / DtWidgets / ComboBox.c next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  87.1 KB  |  2,631 lines

  1. /*
  2.  * ComboBox.c, Interleaf, 16aug93 2:37pm Version 1.1.
  3.  */
  4.  
  5. /***********************************************************
  6. Copyright 1993 Interleaf, Inc.
  7.  
  8. Permission to use, copy, modify, and distribute this software
  9. and its documentation for any purpose without fee is granted,
  10. provided that the above copyright notice appear in all copies
  11. and that both copyright notice and this permission notice appear
  12. in supporting documentation, and that the name of Interleaf not
  13. be used in advertising or publicly pertaining to distribution of
  14. the software without specific written prior permission.
  15.  
  16. Interleaf makes no representation about the suitability of this
  17. software for any purpose. It is provided "AS IS" without any
  18. express or implied warranty. 
  19. ******************************************************************/
  20.  
  21. /*
  22.  * (C) Copyright 1991,1992, 1993
  23.  * Interleaf, Inc.
  24.  * 9 Hillside Avenue, 
  25.  * Waltham, MA  02154
  26.  *
  27.  * ComboBox.c (DtComboBoxWidget):
  28.  *
  29.  * I wanted a margin around the widget (outside the shadow, like buttons), 
  30.  * so that the combo-box could be made the same size as a 
  31.  * push-button, etc.  The bulletin-board widget always puts the shadow at 
  32.  * the outside edge of the widget, so combo-box is a sublcass of
  33.  * manager, and we do everything ourselves.
  34.  * 
  35.  * One must be carefull when using Dimension (for core width and height).
  36.  * Dimension is an unsigned short.  This causes problems when subtracting
  37.  * and ending up with what should be a negative number (but it doesn't).
  38.  * All child widget positioning is done by the combo_box.  We don't
  39.  * use any heavy-weight forms, etc. to help us out.
  40.  *
  41.  * There is no padding when editable.  If using a label given it a
  42.  * small margin, so it doesn't run up against the side of our
  43.  * shadow or the arrow.
  44.  * 
  45.  * Make some of the ComboBox functions common, so they can be shared
  46.  * with SpinButton.
  47.  *
  48.  * The label-string resource got out of control.  Its role kept getting
  49.  * expanded; now the whole thing is a mess.  Currently it shadows the
  50.  * label's label-string.  If the user sets it explicitly it will 
  51.  * take affect for as long as update-label is false.  If update-label
  52.  * is true, it will take affect until the end-user makes a selection
  53.  * off the list.
  54.  * 
  55.  * Known bugs:
  56.  *        Changing margin_width or margin_height resources when the
  57.  *        combo_box has focus will probably result in display glitches.
  58.  *
  59.  */
  60. #include "ComboBoxP.h"
  61. #include <Xm/VendorSP.h>
  62. #include <Xm/DrawP.h>
  63. #include <Xm/MenuUtilP.h>
  64.  
  65. #include <Xm/DisplayP.h>
  66. #define DisplayUserGrabbed(w) \
  67. ((XmDisplayRec*) XmGetXmDisplay(XtDisplay(w)))->display.userGrabbed
  68.  
  69. static void    ClassInitialize (void);
  70. static void    Initialize (DtComboBoxWidget request, 
  71.                    DtComboBoxWidget new, ArgList given_args, 
  72.                    Cardinal *num_args);
  73. static XmNavigability WidgetNavigable (DtComboBoxWidget combo);
  74. static void    _ComboBoxFocusIn (DtComboBoxWidget combo, XEvent *event, 
  75.                      char **params, Cardinal *num_params);
  76. static void    _ComboBoxFocusOut (DtComboBoxWidget combo, XEvent *event,
  77.                       char **params, Cardinal *num_params);
  78. static void    DrawHighlight (DtComboBoxWidget combo, Boolean clear);
  79. static void    _ComboBoxActivate (Widget w, XEvent *event, char **params,
  80.                       Cardinal *num_params);
  81. static void    _ComboBoxKbdCancel (Widget w, XEvent *event, char **params,
  82.                        Cardinal *num_params);
  83. static void    CheckResources (DtComboBoxWidget combo);
  84. static void    Destroy (DtComboBoxWidget combo);
  85. static void    Resize (DtComboBoxWidget combo);
  86. static void    Redisplay (DtComboBoxWidget w, XEvent *event, 
  87.                   Region region);
  88. static XtGeometryResult GeometryManager (Widget w, 
  89.                         XtWidgetGeometry *request, 
  90.                         XtWidgetGeometry *reply);
  91. static void    SetComboBoxSize (DtComboBoxWidget combo);
  92. static void    ForceChildSizes (DtComboBoxWidget combo);
  93. static void    LayoutChildren (DtComboBoxWidget combo);
  94. static Boolean    SetValues (DtComboBoxWidget current, 
  95.                   DtComboBoxWidget request, DtComboBoxWidget new);
  96. static void    ClearShadow (DtComboBoxWidget w, Boolean all);
  97. static void    DrawShadow (DtComboBoxWidget w);
  98. static char*    GetTextString (XmString xm_string);
  99. static void    SetTextFieldData (DtComboBoxPart *combo_p, XmString item);
  100. static void    SetMaximumLabelSize (DtComboBoxPart *combo_p);
  101. static void    SetLabelData (DtComboBoxPart *combo_p, XmString item,
  102.                  Boolean force_label_string);
  103. static void    select_cb (Widget w, XtPointer client_data, 
  104.                   XtPointer call_data);
  105. static void    shell_event_handler (Widget widget, XtPointer client_data,
  106.                     XEvent* event, Boolean *dispatch);
  107. static void    list_event_handler (Widget widget, XtPointer client_data,
  108.                        XEvent* event, Boolean *dispatch);
  109. static void    TextFieldActivate (DtComboBoxPart *combo_p);
  110. static void    activate_cb (Widget w, XtPointer client_data,
  111.                 XtPointer call_data);
  112. static void    arrow_expose_cb (Widget w, XtPointer client_data,
  113.                     XtPointer call_data);
  114. static void    text_losing_focus_cb (Widget w, XtPointer client_data,
  115.                      XtPointer call_data);
  116. static void    text_activate_cb (Widget w, XtPointer client_data,
  117.                      XtPointer call_data);
  118. static void    text_focus_cb (Widget w, XtPointer client_data,
  119.                   XtPointer call_data);
  120. static void    SyncWithList (DtComboBoxPart *combo_p);
  121. static XmImportOperator _XmSetSyntheticResForChild (Widget widget,
  122.                                int offset, 
  123.                                XtArgVal * value);
  124.  
  125. static XmString InitLabel = NULL;
  126. extern void DtComboBoxSelectItemMoveup(DtComboBoxWidget combo, XmString item);
  127.  
  128. /*
  129.  * DtComboBoxWidget specific defines.
  130.  */
  131. #define COMBO_SHADOW(w)        w->manager.shadow_thickness
  132. #define COMBO_MARGIN_W(w)   w->combo_box.margin_width
  133. #define COMBO_MARGIN_H(w)   w->combo_box.margin_height
  134. #define COMBO_H_SPACING(w)  w->combo_box.horizontal_spacing
  135. #define COMBO_V_SPACING(w)  w->combo_box.vertical_spacing
  136. #define LIST_EVENTS        (ButtonPressMask | ButtonReleaseMask | \
  137.                  FocusChangeMask | EnterWindowMask | \
  138.                  LeaveWindowMask)
  139. #define SHELL_EVENTS        ButtonPressMask
  140. #define INVALID_DIMENSION   (0xFFFF)
  141. #define MAXINT 2147483647  /* Taken from TextF.c */
  142.  
  143.  
  144. static char ComboBoxTranslationTable[] = "\
  145.     <FocusIn>:         ComboBoxFocusIn() \n\
  146.     <FocusOut>:         ComboBoxFocusOut() \n\
  147.         <Key>osfDown:        ComboBoxActivate() \n\
  148.         <Btn1Down>,<Btn1Up>: ComboBoxActivate() \n\
  149.         <Key>osfSelect:      ComboBoxActivate() \n\
  150.         ~s ~m ~a <Key>space: ComboBoxActivate() \n\
  151. ";
  152.  
  153. static char ComboBoxLabelTranslationTable[] = "\
  154.         <Key>osfDown:        ComboBoxActivate(label) \n\
  155.         <Btn1Down>,<Btn1Up>: ComboBoxActivate(label) \n\
  156.         <Key>osfSelect:      ComboBoxActivate(label) \n\
  157.         ~s ~m ~a <Key>space: ComboBoxActivate(label) \n\
  158. ";
  159.  
  160. static char ComboBoxListTranslationTable[] = "\
  161.         <Key>osfCancel:      ListKbdCancel() ComboBoxKbdCancel() \n\
  162. ";
  163.  
  164. static XtActionsRec ComboBoxActionTable[] = {
  165.        {"ComboBoxFocusIn",   (XtActionProc)_ComboBoxFocusIn},
  166.        {"ComboBoxFocusOut",  (XtActionProc)_ComboBoxFocusOut},
  167.        {"ComboBoxActivate",  (XtActionProc)_ComboBoxActivate},
  168.        {"ComboBoxKbdCancel", (XtActionProc)_ComboBoxKbdCancel},
  169. };
  170.  
  171.  
  172. /* 
  173.  * DtComboBoxWidget resources 
  174.  */
  175. #define offset(field) XtOffset(DtComboBoxWidget, field)
  176. static XtResource resources[] = {
  177.     {XmNshadowThickness, XmCShadowThickness, XmRHorizontalDimension, 
  178.      sizeof(Dimension), offset(manager.shadow_thickness),
  179.      XmRImmediate, (XtPointer)TEXT_FIELD_SHADOW},
  180.  
  181.     /* 
  182.      * ComboBox specific resources
  183.      */
  184.     {XmNactivateCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
  185.      offset(combo_box.activate_callback), XmRCallback, 
  186.      (XtPointer)NULL},
  187.     {XmNalignment, XmCAlignment, XmRAlignment, sizeof(unsigned char),
  188.      offset(combo_box.alignment), XmRImmediate, 
  189.      (XtPointer)XmALIGNMENT_BEGINNING},
  190.     {XmNarrowSpacing, XmCArrowSpacing, XmRHorizontalDimension,
  191.      sizeof(Dimension), offset(combo_box.arrow_spacing),
  192.      XmRImmediate, (XtPointer)0},
  193.     {XmNarrowType, XmCArrowType, XmRArrowType, sizeof(unsigned char),
  194.      offset(combo_box.arrow_type), XmRImmediate, (XtPointer)XmWINDOWS},
  195.     {XmNcolumns, XmCColumns, XmRShort, sizeof(short),
  196.      offset(combo_box.text_columns), XmRImmediate, (XtPointer)20},
  197.     {XmNfocusCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
  198.      offset(combo_box.focus_callback), XmRCallback, 
  199.      (XtPointer)NULL},
  200.     {XmNhorizontalSpacing, XmCHorizontalSpacing, XmRHorizontalDimension,
  201.      sizeof(Dimension), offset(combo_box.horizontal_spacing),
  202.      XmRImmediate, (XtPointer)INVALID_DIMENSION},
  203.     {XmNitemCount, XmCItemCount, XmRInt, sizeof(int), 
  204.      offset(combo_box.item_count), XmRImmediate, (XtPointer)0},
  205.     /*
  206.      * items is used only for seeing if the user changed the list.  It
  207.      * is only a pointer that reflects the current list's items.
  208.      */
  209.     {XmNitems, XmCItems, XmRXmStringTable, sizeof(XmStringTable),
  210.      offset(combo_box.items), XmRImmediate, (XtPointer)NULL},
  211.     {XmNlabelString, XmCXmString, XmRXmString, sizeof(XmString),
  212.      offset(combo_box.label_string), XmRImmediate, (XtPointer)NULL},
  213.     {XmNlist, XmCList, XmRWidget, sizeof(Widget),
  214.      offset(combo_box.list), XmRImmediate, (XtPointer)NULL},
  215.     {XmNlistFontList, XmCListFontList, XmRFontList, sizeof(XmFontList), 
  216.      offset(combo_box.list_font_list), XmRImmediate, (XtPointer)NULL},
  217.     {XmNlistMarginHeight, XmCListMarginHeight, XmRVerticalDimension, 
  218.      sizeof(Dimension), offset(combo_box.list_margin_height),
  219.      XmRImmediate, (XtPointer)MARGIN},
  220.     {XmNlistMarginWidth, XmCListMarginWidth, XmRHorizontalDimension,
  221.      sizeof(Dimension), offset(combo_box.list_margin_width),
  222.      XmRImmediate, (XtPointer)MARGIN},
  223.     {XmNlistSpacing, XmCListSpacing, XmRDimension,sizeof(Dimension), 
  224.      offset(combo_box.list_spacing), XmRImmediate, (XtPointer)0},
  225.     {XmNlosingFocusCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
  226.      offset(combo_box.losing_focus_callback), XmRCallback, 
  227.      (XtPointer)NULL},
  228.     {XmNmarginHeight, XmCMarginHeight, XmRVerticalDimension,
  229.      sizeof(Dimension), offset(combo_box.margin_height),
  230.      XmRImmediate, (XtPointer)MARGIN},
  231.     {XmNmarginWidth, XmCMarginWidth, XmRHorizontalDimension, sizeof(Dimension),
  232.      offset(combo_box.margin_width), XmRImmediate, (XtPointer)MARGIN},
  233.     {XmNmaxLength, XmCMaxLength, XmRInt, sizeof(unsigned int),
  234.      offset(combo_box.text_max_length), XmRImmediate, (XtPointer)MAXINT},
  235.     {XmNmenuPostCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
  236.      offset(combo_box.menu_post_callback), XmRCallback, (XtPointer)NULL},
  237.     {XmNorientation, XmCOrientation, XmROrientation, sizeof(unsigned char),
  238.      offset(combo_box.orientation), XmRImmediate, (XtPointer)XmRIGHT},
  239.     {XmNpoppedUp, XmCPoppedUp, XmRBoolean, sizeof(Boolean),
  240.      offset(combo_box.popped_up), XmRImmediate, (XtPointer)FALSE},
  241.     {XmNrecomputeSize, XmCRecomputeSize, XmRBoolean, sizeof(Boolean),
  242.      offset(combo_box.recompute_size), XmRImmediate, (XtPointer)TRUE},
  243.     {XmNselectedItem, XmCXmString, XmRXmString, sizeof(XmString),
  244.      offset(combo_box.selected_item), XmRImmediate, (XtPointer)NULL},
  245.     {XmNselectedPosition, XmCSelectedPosition, XmRInt, sizeof(unsigned int),
  246.      offset(combo_box.selected_position), XmRImmediate, (XtPointer)0},
  247.     {XmNselectionCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList),
  248.      offset(combo_box.selection_callback), XmRCallback, (XtPointer)NULL},
  249.     {XmNtextField, XmCTextField, XmRWidget, sizeof(Widget),
  250.      offset(combo_box.text), XmRImmediate, (XtPointer)NULL},
  251.     {XmNtopItemPosition, XmCTopItemPosition, XmRInt, sizeof(int), 
  252.      offset(combo_box.top_item_position), XmRImmediate, (XtPointer)1},
  253.     {XmNtype, XmCType, XmRType, sizeof(unsigned char),
  254.      offset(combo_box.type), XmRImmediate,
  255.      (XtPointer)XmDROP_DOWN_LIST_BOX},
  256.     {XmNupdateLabel, XmCUpdateLabel, XmRBoolean, sizeof(Boolean),
  257.      offset(combo_box.update_label), XmRImmediate, (XtPointer)TRUE},
  258.     {XmNvisibleItemCount, XmCVisibleItemCount, XmRInt, sizeof(int),
  259.      offset(combo_box.visible_item_count), XmRImmediate, (XtPointer)10},
  260.     {XmNverticalSpacing, XmCVerticalSpacing, XmRVerticalDimension,
  261.      sizeof(Dimension), offset(combo_box.vertical_spacing),
  262.      XmRImmediate, (XtPointer)INVALID_DIMENSION},
  263.     {XmNmoveSelectedItemUp, XmCMoveSelectedItemUp, XmRBoolean, sizeof(Boolean),
  264.          offset(combo_box.move_selecteditem_up), XmRImmediate, (XtPointer)FALSE},
  265.     {XmNnoCallbackForArrow, XmCNoCallbackForArrow, XmRBoolean, sizeof(Boolean),
  266.      offset(combo_box.no_callback_for_arrow), XmRImmediate, (XtPointer)FALSE}
  267. };
  268.  
  269. /*
  270.  * List resources (used for GetValues).
  271.  */
  272. static XmSyntheticResource syn_resources[] = {
  273.     {XmNarrowSize, sizeof(Dimension), offset(combo_box.arrow_size), 
  274.      _DtComboBoxGetArrowSize, _XmSetSyntheticResForChild},
  275.     {XmNlabelString, sizeof(XmString), offset(combo_box.label_string), 
  276.      _DtComboBoxGetLabelString, _XmSetSyntheticResForChild},
  277.     {XmNitemCount, sizeof(int), offset(combo_box.item_count), 
  278.      _DtComboBoxGetListItemCount, _XmSetSyntheticResForChild},
  279.     {XmNitems, sizeof(XmStringTable), offset(combo_box.items), 
  280.      _DtComboBoxGetListItems, _XmSetSyntheticResForChild},
  281.     {XmNlistFontList, sizeof(XmFontList), offset(combo_box.list_font_list), 
  282.      _DtComboBoxGetListFontList, _XmSetSyntheticResForChild},
  283.     {XmNlistMarginHeight, sizeof(Dimension), 
  284.      offset(combo_box.list_margin_height),
  285.      _DtComboBoxGetListMarginHeight, _XmSetSyntheticResForChild},
  286.     {XmNlistMarginWidth, sizeof(Dimension),offset(combo_box.list_margin_width),
  287.      _DtComboBoxGetListMarginWidth, _XmSetSyntheticResForChild},
  288.     {XmNlistSpacing, sizeof(Dimension), offset(combo_box.list_spacing),
  289.      _DtComboBoxGetListSpacing, _XmSetSyntheticResForChild},
  290.     {XmNtopItemPosition, sizeof(int), offset(combo_box.top_item_position),
  291.      _DtComboBoxGetListTopItemPosition, _XmSetSyntheticResForChild},
  292.     {XmNvisibleItemCount, sizeof(int), offset(combo_box.visible_item_count),
  293.      _DtComboBoxGetListVisibleItemCount, _XmSetSyntheticResForChild},
  294. };
  295. #undef offset
  296.  
  297. /* Need Class Extension for widget navigation */
  298. static XmBaseClassExtRec baseClassExtRec = {
  299.     NULL,
  300.     NULLQUARK,
  301.     XmBaseClassExtVersion,
  302.     sizeof(XmBaseClassExtRec),
  303.     (XtInitProc)NULL,            /* InitializePrehook    */
  304.     (XtSetValuesFunc)NULL,        /* SetValuesPrehook    */
  305.     (XtInitProc)NULL,            /* InitializePosthook    */
  306.     (XtSetValuesFunc)NULL,        /* SetValuesPosthook    */
  307.     NULL,                /* secondaryObjectClass    */
  308.     (XtInitProc)NULL,            /* secondaryCreate    */
  309.     (XmGetSecResDataFunc)NULL,         /* getSecRes data    */
  310.     { 0 },                  /* fastSubclass flags    */
  311.     (XtArgsProc)NULL,            /* getValuesPrehook    */
  312.     (XtArgsProc)NULL,            /* getValuesPosthook    */
  313.     (XtWidgetClassProc)NULL,            /* classPartInitPrehook */
  314.     (XtWidgetClassProc)NULL,            /* classPartInitPosthook*/
  315.     NULL,                               /* ext_resources        */
  316.     NULL,                               /* compiled_ext_resources*/
  317.     0,                                  /* num_ext_resources    */
  318.     FALSE,                              /* use_sub_resources    */
  319.     (XmWidgetNavigableProc) WidgetNavigable,                    /* widgetNavigable      */
  320.     (XmFocusChangeProc)NULL,            /* focusChange          */
  321.     (XmWrapperData)NULL            /* wrapperData         */
  322. };
  323.  
  324. /*
  325.  * Define Class Record.
  326.  */
  327. DtComboBoxClassRec dtComboBoxClassRec =
  328. {
  329.     {        /* core_class fields      */
  330.     (WidgetClass)&(xmManagerClassRec),        /* superclass         */    
  331.     (String)"DtComboBox",            /* class_name         */    
  332.     (Cardinal)sizeof(DtComboBoxRec),        /* widget_size        */    
  333.     (XtProc)ClassInitialize,            /* class_initialize   */    
  334.     (XtWidgetClassProc)NULL,            /* class_part_init    */    
  335.     (XtEnum)FALSE,                /* class_inited       */    
  336.     (XtInitProc)Initialize,            /* initialize         */    
  337.     (XtArgsProc)NULL,                /* initialize_hook    */    
  338.     (XtRealizeProc)XtInheritRealize,        /* realize            */    
  339.     (XtActionList)ComboBoxActionTable,        /* actions           */    
  340.     (Cardinal)XtNumber(ComboBoxActionTable),    /* num_actions        */    
  341.     (XtResourceList)resources,            /* resources          */    
  342.     (Cardinal)XtNumber(resources),        /* num_resources      */    
  343.     (XrmClass)NULLQUARK,            /* xrm_class          */    
  344.     (Boolean)TRUE,                /* compress_motion    */    
  345.     (XtEnum)XtExposeCompressMaximal,        /* compress_exposure  */    
  346.     (Boolean)TRUE,                /* compress_enterleave*/    
  347.     (Boolean)FALSE,                /* visible_interest   */    
  348.     (XtWidgetProc)Destroy,            /* destroy            */    
  349.     (XtWidgetProc)Resize,            /* resize             */    
  350.     (XtExposeProc)Redisplay,            /* expose             */    
  351.     (XtSetValuesFunc)SetValues,            /* set_values         */    
  352.     (XtArgsFunc)NULL,                /* set values hook    */    
  353.     (XtAlmostProc)XtInheritSetValuesAlmost,    /* set values almost  */    
  354.     (XtArgsProc)NULL,                /* get values hook    */    
  355.     (XtAcceptFocusProc)NULL,            /* accept_focus       */    
  356.     (XtVersionType)XtVersion,            /* Version            */    
  357.     (XtPointer)NULL,                /* PRIVATE cb list    */
  358.     (String)XtInheritTranslations,        /* tm_table           */
  359.     (XtGeometryHandler)XtInheritQueryGeometry,    /* query_geom         */
  360.     (XtStringProc)XtInheritDisplayAccelerator,    /* display_accelerator*/
  361.     (XtPointer)&baseClassExtRec            /* extension          */
  362.     },
  363.     {        /* composite_class fields */
  364.     (XtGeometryHandler)GeometryManager,        /* geometry_manager   */     
  365.     (XtWidgetProc)XtInheritChangeManaged,    /* change_managed     */     
  366.     (XtWidgetProc)XtInheritInsertChild,        /* insert_child          */     
  367.     (XtWidgetProc)XtInheritDeleteChild,        /* delete_child          */     
  368.     (XtPointer)NULL                /* extension          */     
  369.     },
  370.     {        /* constraint_class fields */
  371.     (XtResourceList)NULL,            /* resources          */     
  372.     (Cardinal)0,                /* num_resources      */     
  373.     (Cardinal)0,                /* constraint_size    */     
  374.     (XtInitProc)NULL,                /* initialize          */     
  375.     (XtWidgetProc)NULL,                /* destroy          */     
  376.     (XtSetValuesFunc)NULL,            /* set_values          */     
  377.     (XtPointer)NULL                /* extension          */     
  378.     },
  379.     {        /* manager class     */
  380.     (String)XtInheritTranslations,        /* translations       */     
  381.     (XmSyntheticResource*)syn_resources,    /* syn resources      */     
  382.     (int)XtNumber(syn_resources),        /* num syn_resources  */     
  383.     (XmSyntheticResource*)NULL,            /* get_cont_resources */     
  384.     (int)0,                    /* num_get_cont_resources */ 
  385.     (XmParentProcessProc)XmInheritParentProcess,/* parent_process     */     
  386.     (XtPointer)NULL                /* extension          */     
  387.     },
  388.     {        /* combo_box_class fields */     
  389.     (Boolean)0,
  390.     }
  391. };
  392.  
  393. WidgetClass dtComboBoxWidgetClass = (WidgetClass)&dtComboBoxClassRec;
  394.  
  395. /* 
  396.  * Must set up the record type for the class extensions to work.
  397.  */
  398. static void
  399. ClassInitialize(void)
  400. {
  401.     baseClassExtRec.record_type = XmQmotif;
  402. }
  403.  
  404. /*
  405.  * ComboBox initialization function.  This builds the widgets inside
  406.  * our widget, to get the correct layout.  If the type resource
  407.  * is XmDROP_DOWN_COMBO_BOX, we create a textField; if FALSE, we create a
  408.  * label.  If the user changes this resource later, we will create the
  409.  * other widget (textField or Label).  We don't want to carry backage from
  410.  * both widgets if the user never changes the type resource.
  411.  */
  412. static void
  413. Initialize(DtComboBoxWidget request,
  414.        DtComboBoxWidget new,
  415.        ArgList given_args,
  416.        Cardinal *num_args)
  417. {
  418.     int k;
  419.     XtTranslations trans = XtParseTranslationTable(ComboBoxTranslationTable);
  420.     XtTranslations list_trans = 
  421.     XtParseTranslationTable(ComboBoxListTranslationTable);
  422.     DtComboBoxPart *combo_p = (DtComboBoxPart*)&(new->combo_box);
  423.     Boolean force_label_string = FALSE;
  424.     Arg args[15];
  425.     int n;
  426.  
  427.     /* Overwrite the manager's focusIn and focusOut translations */
  428.     XtOverrideTranslations((Widget)new, trans);
  429.  
  430.     if (InitLabel == NULL)
  431.     InitLabel = XmStringCreateSimple("");
  432.  
  433.     /* 
  434.      * force_label_string usage if it is specified and items is not.
  435.      * This will be the perminant label string only if update-label
  436.      * is false, else it is only used until the user picks something
  437.      * new off the list.
  438.      */
  439.     if (combo_p->label_string == NULL)
  440.     combo_p->label_string = InitLabel;
  441.     else if (!combo_p->items)
  442.     force_label_string = TRUE;
  443.  
  444.  
  445.     combo_p->text = (Widget)NULL;
  446.     combo_p->label = (Widget)NULL;
  447.     combo_p->sep = (Widget)NULL;
  448.     combo_p->old_width = 0;
  449.     combo_p->old_height = 0;
  450.  
  451.     CheckResources(new);
  452.  
  453.     /*
  454.      * Create the text or label depending on the type resource.
  455.      * When part of X-Designer, we create both at initialization to
  456.      * avoid later crashes.
  457.      */
  458. #ifndef XDESIGNER
  459.     if (combo_p->type == XmDROP_DOWN_COMBO_BOX)
  460. #endif
  461.     {
  462.     n = 0;
  463.     XtSetArg(args[n], XmNcolumns, combo_p->text_columns); n++;
  464.     XtSetArg(args[n], XmNmaxLength, combo_p->text_max_length); n++;
  465.     XtSetArg(args[n], XmNmarginWidth, 2); n++;
  466.     XtSetArg(args[n], XmNmarginHeight, 2); n++;
  467.     combo_p->text = XtCreateManagedWidget("Text", 
  468.                           xmTextFieldWidgetClass,
  469.                           (Widget)new, args, n);
  470.     XtAddCallback(combo_p->text, XmNlosingFocusCallback, 
  471.               text_losing_focus_cb, (XtPointer)new);
  472.     XtAddCallback(combo_p->text, XmNactivateCallback, 
  473.               text_activate_cb, (XtPointer)new);
  474.     XtAddCallback(combo_p->text, XmNfocusCallback, 
  475.               text_focus_cb, (XtPointer)new);
  476.     if (combo_p->horizontal_spacing == INVALID_DIMENSION)
  477.         combo_p->horizontal_spacing = 0;
  478.     if (combo_p->vertical_spacing == INVALID_DIMENSION)
  479.         combo_p->vertical_spacing = 0;
  480.     }
  481. #ifndef XDESIGNER
  482.     else
  483. #endif
  484.     {
  485.     XtTranslations label_trans = 
  486.         XtParseTranslationTable(ComboBoxLabelTranslationTable);
  487.  
  488.     COMBO_SHADOW(new) = LABEL_SHADOW;
  489.     n = 0;
  490.     XtSetArg(args[n], XmNalignment, combo_p->alignment); n++;
  491.     XtSetArg(args[n], XmNrecomputeSize, FALSE); n++;
  492.     XtSetArg(args[n], XmNlabelString, InitLabel); n++;
  493.     XtSetArg(args[n], XmNmarginLeft, LABEL_PADDING); n++;
  494.     XtSetArg(args[n], XmNmarginRight, LABEL_PADDING); n++;
  495.     XtSetArg(args[n], XmNmarginWidth, 0); n++;
  496.     XtSetArg(args[n], XmNmarginHeight, 0); n++;
  497.     XtSetArg(args[n], XmNstringDirection,
  498.          new->manager.string_direction); n++;
  499.     combo_p->label = XtCreateManagedWidget("Label", 
  500.                            xmLabelWidgetClass,
  501.                            (Widget)new, args, n);
  502.     XtOverrideTranslations((Widget)combo_p->label, label_trans);
  503.     if (combo_p->horizontal_spacing == INVALID_DIMENSION)
  504.         combo_p->horizontal_spacing = 1;
  505.     if (combo_p->vertical_spacing == INVALID_DIMENSION)
  506.         combo_p->vertical_spacing = 2;
  507.     }
  508.  
  509. #ifdef XDESIGNER
  510.     /* Unmanage the one we don't use */
  511.     if (combo_p->type == XmDROP_DOWN_COMBO_BOX)
  512.     XtUnmanageChild(combo_p->label);
  513.     else
  514.     XtUnmanageChild(combo_p->text);
  515. #endif
  516.  
  517.     /*
  518.      * Create the separator used if non-editable combo-box.
  519.      */
  520. #ifndef XDESIGNER
  521.     if (combo_p->type == XmDROP_DOWN_LIST_BOX) 
  522. #endif
  523.     {
  524.     n = 0;
  525.     XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
  526.     combo_p->sep = XtCreateManagedWidget("ComboBoxSeparator", 
  527.                          xmSeparatorWidgetClass,
  528.                          (Widget)new, args, n);
  529.     }
  530.  
  531.     /*
  532.      * Create the ArrowWidget.
  533.      */
  534.     n = 0;
  535.     XtSetArg(args[n], XmNtraversalOn, FALSE); n++;
  536.     XtSetArg(args[n], XmNhighlightThickness, 0); n++;
  537.     XtSetArg(args[n], XmNshadowThickness, 0); n++;
  538.     if (combo_p->arrow_type == XmMOTIF) {
  539.     XtSetArg(args[n], XmNarrowDirection, XmARROW_DOWN); n++;
  540.     XtSetArg(args[n], XmNforeground, new->core.background_pixel); n++;
  541.     combo_p->arrow = XtCreateManagedWidget("ComboBoxArrow", 
  542.                            xmArrowButtonWidgetClass,
  543.                            (Widget)new, args, n);
  544.     }
  545.     else {
  546.     combo_p->arrow = XtCreateManagedWidget("ComboBoxArrow", 
  547.                            xmDrawnButtonWidgetClass,
  548.                            (Widget)new, args, n);
  549.     XtAddCallback(combo_p->arrow, XmNexposeCallback, arrow_expose_cb, 
  550.               (XtPointer)new);
  551.     }
  552.     XtAddCallback(combo_p->arrow, XmNactivateCallback, activate_cb, 
  553.           (XtPointer)new);
  554.  
  555.     /*
  556.      *  Create the shell and associated list widgets.
  557.      */
  558.     n = 0;
  559.     for ( k = 0; k < *num_args; k++ )
  560.     {
  561.              if ( (strcmp(given_args[k].name, XmNvisual) == 0 ) ||
  562.                   (strcmp(given_args[k].name, XmNcolormap) == 0 ) ||
  563.                   (strcmp(given_args[k].name, XmNdepth) == 0) )
  564.              {
  565.                     args[n].name  = given_args[k].name;
  566.                     args[n].value = given_args[k].value;
  567.                     n++;
  568.               }
  569.     }
  570.  
  571.     XtSetArg(args[n], XtNoverrideRedirect, TRUE); n++;
  572.     XtSetArg(args[n], XtNallowShellResize, TRUE); n++;
  573.     XtSetArg(args[n], XtNsaveUnder, TRUE); n++;
  574.     combo_p->shell = XtCreatePopupShell("ComboBoxMenuShell", 
  575.                     topLevelShellWidgetClass,
  576.                     (Widget)new, args, n);
  577.     
  578.     n = 0;
  579.     combo_p->frame = XtCreateManagedWidget("ComboBoxRowColumn",
  580.                        xmFrameWidgetClass,
  581.                        combo_p->shell, args, n);
  582.  
  583.     n = 0;
  584.     /* Store combo widget in list for later use */
  585.     XtSetArg(args[n], XmNuserData, (XtPointer)new); n++;
  586.     if (combo_p->list_font_list) {
  587.     XtSetArg(args[n], XmNfontList, combo_p->list_font_list); n++;
  588.     }
  589.     XtSetArg(args[n], XmNitemCount, combo_p->item_count); n++;
  590.     XtSetArg(args[n], XmNitems, combo_p->items); n++;
  591.     XtSetArg(args[n], XmNlistMarginHeight, combo_p->list_margin_height); n++;
  592.     XtSetArg(args[n], XmNlistMarginWidth, combo_p->list_margin_width); n++;
  593.     XtSetArg(args[n], XmNlistSpacing, combo_p->list_spacing); n++;
  594.     XtSetArg(args[n], XmNstringDirection, new->manager.string_direction); n++;
  595.     XtSetArg(args[n], XmNtopItemPosition, combo_p->top_item_position); n++;
  596.     XtSetArg(args[n], XmNvisibleItemCount, combo_p->visible_item_count); n++;
  597.     XtSetArg(args[n], XmNlistSizePolicy, XmRESIZE_IF_POSSIBLE); n++;
  598.     combo_p->list = XmCreateScrolledList(combo_p->frame, "List",
  599.                      args, n);
  600.     XtOverrideTranslations((Widget)combo_p->list, list_trans);
  601.  
  602.     /* selected_item resource used before selected_position */
  603.     if (combo_p->selected_item)
  604.     DtComboBoxSelectItem((Widget)new, combo_p->selected_item);
  605.     else
  606.     XmListSelectPos(combo_p->list, combo_p->selected_position + 1, FALSE);
  607.  
  608.     SyncWithList(combo_p);
  609.     XtManageChild(combo_p->list);
  610.     XtRealizeWidget(combo_p->shell);
  611.  
  612.     combo_p->max_shell_width = combo_p->shell->core.width;
  613.     combo_p->max_shell_height = combo_p->shell->core.height;
  614.  
  615.     XtAddCallback(combo_p->list, XmNdefaultActionCallback, select_cb, new);
  616.     XtAddCallback(combo_p->list, XmNbrowseSelectionCallback, select_cb, new);
  617.  
  618.     /*
  619.      * Set up event handlers needed for handling grab states.
  620.      */
  621.     XtInsertEventHandler(combo_p->list, LIST_EVENTS, TRUE,
  622.              (XtEventHandler)list_event_handler, 
  623.              (XtPointer)new, XtListHead);
  624.     XtInsertEventHandler(combo_p->shell, SHELL_EVENTS, TRUE,
  625.              (XtEventHandler)shell_event_handler, 
  626.              (XtPointer)new, XtListHead);
  627.  
  628.     /*
  629.      * Set initial value in text or label if items was specified
  630.      * Copy given label-string.
  631.      */
  632.     if (combo_p->label_string)
  633.     combo_p->label_string = XmStringCopy(combo_p->label_string);
  634.     if (combo_p->type == XmDROP_DOWN_LIST_BOX) {
  635.     SetMaximumLabelSize(combo_p);
  636.     SetLabelData(combo_p, NULL, force_label_string);
  637.     }
  638.     else
  639.     SetTextFieldData(combo_p, NULL);
  640.  
  641.     SetComboBoxSize(new);
  642.     LayoutChildren(new);
  643. }
  644.  
  645.  
  646. /*
  647.  * Allow the manager to gain focus if not editable.  If editable (using
  648.  * text-field), then let the toolkit give focus to the text-field.
  649.  */
  650. static XmNavigability
  651. WidgetNavigable(DtComboBoxWidget combo)
  652. {   
  653.     XmNavigationType nav_type = ((XmManagerWidget)combo)->manager.navigation_type;
  654.  
  655.     if (combo->core.sensitive &&  combo->core.ancestor_sensitive &&
  656.     ((XmManagerWidget)combo)->manager.traversal_on) {
  657.     if ((nav_type == XmSTICKY_TAB_GROUP) ||
  658.         (nav_type == XmEXCLUSIVE_TAB_GROUP) ||
  659.         ((nav_type == XmTAB_GROUP) && 
  660.          !_XmShellIsExclusive((Widget)combo))) {
  661.         if (combo->combo_box.type == XmDROP_DOWN_COMBO_BOX)
  662.         return(XmDESCENDANTS_TAB_NAVIGABLE);
  663.         else
  664.         return(XmTAB_NAVIGABLE);
  665.     }
  666.     return(XmDESCENDANTS_NAVIGABLE);
  667.     }
  668.     return(XmNOT_NAVIGABLE);
  669. }
  670.  
  671. /* 
  672.  * The combo_box gets focus.
  673.  */
  674. static void 
  675. _ComboBoxFocusIn(DtComboBoxWidget combo,
  676.          XEvent *event,
  677.          String *params,
  678.          Cardinal *num_params)
  679. {
  680.     DrawHighlight(combo, FALSE);
  681. }
  682.  
  683. /* 
  684.  * The combo_box loses focus. Only happens if not editable.
  685.  */
  686. static void 
  687. _ComboBoxFocusOut(DtComboBoxWidget combo,
  688.           XEvent *event,
  689.           String *params,
  690.           Cardinal *num_params)
  691. {
  692.     DrawHighlight(combo, TRUE);
  693. }
  694.  
  695. /*
  696.  * This function gets called whenever we draw or clear the shadow (to
  697.  * redraw highlight during resize, etc), as well as during focus_in
  698.  * and focus_out events.
  699.  */
  700. static void
  701. DrawHighlight(DtComboBoxWidget combo,
  702.           Boolean clear)
  703. {
  704.     XRectangle rect[4] ;
  705.  
  706.     if (XtIsRealized(combo)) {
  707.     if (clear) {
  708.         rect[0].x = rect[1].x = rect[2].x = 0;
  709.         rect[3].x = combo->combo_box.old_width - COMBO_MARGIN_W(combo);
  710.         rect[0].y = rect[2].y = rect[3].y = 0 ;
  711.         rect[1].y = combo->combo_box.old_height - COMBO_MARGIN_H(combo);
  712.         rect[0].width = rect[1].width = combo->combo_box.old_width;
  713.         rect[2].width = rect[3].width = COMBO_MARGIN_W(combo);
  714.         rect[0].height = rect[1].height = COMBO_MARGIN_H(combo);
  715.         rect[2].height = rect[3].height = combo->combo_box.old_height;
  716.         XFillRectangles(XtDisplayOfObject((Widget)combo),
  717.                 XtWindowOfObject((Widget)combo), 
  718.                 combo->manager.background_GC, rect, 4);
  719.     }
  720.     else if (XmGetFocusWidget((Widget)combo) == (Widget)combo) {
  721.         rect[0].x = rect[1].x = rect[2].x = 0;
  722.         rect[3].x = XtWidth(combo) - COMBO_MARGIN_W(combo);
  723.         rect[0].y = rect[2].y = rect[3].y = 0 ;
  724.         rect[1].y = XtHeight(combo) - COMBO_MARGIN_H(combo);
  725.         rect[0].width = rect[1].width = XtWidth(combo);
  726.         rect[2].width = rect[3].width = COMBO_MARGIN_W(combo);
  727.         rect[0].height = rect[1].height = COMBO_MARGIN_H(combo);
  728.         rect[2].height = rect[3].height = XtHeight(combo);
  729.         XFillRectangles(XtDisplayOfObject((Widget)combo),
  730.                 XtWindowOfObject((Widget)combo), 
  731.                 combo->manager.highlight_GC, rect, 4);
  732.     }
  733.     }
  734. }
  735.  
  736. /*
  737.  * osfSelect virtual key hit.  Simulate hitting the arrow.
  738.  */
  739. static void 
  740. _ComboBoxActivate(Widget w,
  741.           XEvent *event,
  742.           String *params,
  743.           Cardinal *num_params)
  744. {
  745.     DtComboBoxWidget combo;
  746.  
  747.     if (*num_params == 0) /* no params means combo */
  748.     combo = (DtComboBoxWidget)w;
  749.     else /* params means label */
  750.     combo = (DtComboBoxWidget)XtParent(w);
  751.  
  752.     activate_cb((Widget)combo->combo_box.arrow, (XtPointer)combo, NULL);
  753. }
  754.  
  755. /*
  756.  * osfCancel virtual key hit.
  757.  */
  758. static void 
  759. _ComboBoxKbdCancel(Widget w,
  760.            XEvent *event,
  761.            String *params,
  762.            Cardinal *num_params)
  763. {
  764.     DtComboBoxWidget combo;
  765.     DtComboBoxPart *combo_p;
  766.     XtPointer data;
  767.     Arg args[1];
  768.  
  769.     /* Get combo-box off list data */
  770.     XtSetArg(args[0], XmNuserData, &data);
  771.     XtGetValues(w, args, 1);
  772.     
  773.     combo = (DtComboBoxWidget)data;
  774.     combo_p = (DtComboBoxPart*)&(combo->combo_box);
  775.  
  776.     combo_p->popped_up = FALSE;
  777.     XtPopdown(combo_p->shell);
  778.     XtUngrabPointer(combo_p->shell, CurrentTime);
  779.     XtUngrabKeyboard(combo_p->list, CurrentTime);
  780.     /*
  781.      * _XmRemoveGrab() was causing trouble on irix and linux.  The navigator
  782.      * stopped responding to clicks cause of it.
  783.      *
  784.      */
  785. #if 0
  786.     _XmRemoveGrab(combo_p->shell);
  787. #else
  788.     XtRemoveGrab(combo_p->shell);
  789.     
  790.     DisplayUserGrabbed(w) = False;
  791. #endif
  792.     if (combo_p->type == XmDROP_DOWN_COMBO_BOX)
  793.     XmProcessTraversal(combo_p->text, XmTRAVERSE_CURRENT);
  794. }
  795.  
  796. /*
  797.  * This function goes through most of the resources and makes sure 
  798.  * they have legal values.
  799.  */
  800. static void
  801. CheckResources(DtComboBoxWidget combo)
  802. {
  803.     DtComboBoxPart *combo_p = (DtComboBoxPart*)&(combo->combo_box);
  804.  
  805.     if ((combo_p->alignment != XmALIGNMENT_CENTER) && 
  806.     (combo_p->alignment != XmALIGNMENT_BEGINNING) &&
  807.     (combo_p->alignment != XmALIGNMENT_END)) {
  808.     XtWarning(COMBO_ALIGNMENT);
  809.     combo_p->alignment = XmALIGNMENT_CENTER;
  810.     }
  811.     if (combo_p->margin_height < 0.0) {
  812.     XtWarning(COMBO_MARGIN_HEIGHT);
  813.     combo_p->margin_height = 2;
  814.     }
  815.     if (combo_p->margin_width < 0.0) {
  816.     XtWarning(COMBO_MARGIN_WIDTH);
  817.     combo_p->margin_width = 2;
  818.     }
  819.     if (combo_p->horizontal_spacing < 0.0) {
  820.     XtWarning(COMBO_HORIZONTAL_SPACING);
  821.     combo_p->horizontal_spacing = 0;
  822.     }
  823.     if (combo_p->vertical_spacing < 0.0) {
  824.     XtWarning(COMBO_VERTICAL_SPACING);
  825.     combo_p->vertical_spacing = 0;
  826.     }
  827.     if ((combo_p->orientation != XmLEFT) &&
  828.     (combo_p->orientation != XmRIGHT)) {
  829.     XtWarning(COMBO_ORIENTATION);
  830.     combo_p->orientation = XmRIGHT;
  831.     }
  832.     if (combo_p->item_count < 0) {
  833.     XtWarning(COMBO_ITEM_COUNT);
  834.     combo_p->item_count = 0;
  835.     }
  836.     if ((combo_p->selected_position < 0) ||
  837.     ((combo_p->selected_position >= combo_p->item_count) && 
  838.      (combo_p->item_count > 0))) {
  839.     XtWarning(COMBO_VISIBLE_ITEM);
  840.     combo_p->selected_position = 0;
  841.     }
  842. }
  843.  
  844. /*
  845.  * Destroy procedure called by the toolkit.  Remove all callbacks and
  846.  * event-handlers. 
  847.  */
  848. static void 
  849. Destroy(DtComboBoxWidget combo)
  850. {
  851.     DtComboBoxPart *combo_p = (DtComboBoxPart*)&(combo->combo_box);
  852.  
  853.     if (combo_p->label_string)
  854.     XmStringFree(combo_p->label_string);
  855.  
  856.     DisplayUserGrabbed(combo) = False;
  857.  
  858. #if whydotheydothis
  859.     if (combo_p->text) {
  860.     XtRemoveCallback(combo_p->text, XmNlosingFocusCallback, 
  861.              text_losing_focus_cb, (XtPointer)combo);
  862.     XtRemoveCallback(combo_p->text, XmNactivateCallback, 
  863.              text_activate_cb, (XtPointer)combo);
  864.     XtRemoveCallback(combo_p->text, XmNfocusCallback, 
  865.              text_focus_cb, (XtPointer)combo);
  866.     }
  867.  
  868. #if i_hope_it_has_been_ungrabbed_cuz_this_memory_has_already_been_freed
  869.     if (((ShellWidget)(combo_p->shell))->shell.popped_up) {
  870.     combo_p->popped_up = FALSE;
  871.     XtPopdown(combo_p->shell);
  872.     XtUngrabPointer(combo_p->shell, CurrentTime);
  873.     XtUngrabKeyboard(combo_p->list, CurrentTime);
  874.     _XmRemoveGrab(combo_p->shell);
  875.     }
  876. #endif /* i_hope_it_has_been_ungrabbed_cuz_this_memory_has_already_been_freed */
  877.  
  878.     XtRemoveCallback(combo_p->arrow, XmNactivateCallback, activate_cb, 
  879.              (XtPointer)combo);
  880.     if (combo_p->arrow_type == XmWINDOWS)
  881.     XtRemoveCallback(combo_p->arrow, XmNexposeCallback,
  882.              arrow_expose_cb, (XtPointer)combo);
  883.     XtRemoveCallback(combo_p->list, XmNdefaultActionCallback, 
  884.              select_cb, combo);
  885.     XtRemoveCallback(combo_p->list, XmNbrowseSelectionCallback, 
  886.              select_cb, combo);
  887.  
  888.     XtRemoveEventHandler(combo_p->list, LIST_EVENTS, TRUE,
  889.              (XtEventHandler)list_event_handler, 
  890.              (XtPointer)combo);
  891.  
  892.     XtRemoveEventHandler(combo_p->shell, SHELL_EVENTS, TRUE,
  893.              (XtEventHandler)shell_event_handler, 
  894.              (XtPointer)combo);
  895. #endif /* whydotheydothis */
  896. }
  897.  
  898.  
  899. /*
  900.  * Resize function called by toolkit.  The size of our combo-box
  901.  * has already been changed.  That is why we must store 
  902.  * old_width and old_height.
  903.  */
  904. static void
  905. Resize(DtComboBoxWidget combo)
  906. {
  907.     DtComboBoxPart *combo_p = (DtComboBoxPart*)&(combo->combo_box);
  908.  
  909.     ClearShadow(combo, TRUE);
  910.     LayoutChildren(combo);
  911.     DrawShadow(combo);
  912.     combo_p->old_width = combo->core.width;
  913.     combo_p->old_height = combo->core.height;
  914. }
  915.  
  916.  
  917. /*
  918.  * Redisplay function called by toolkit. The widget didn't change size, 
  919.  * so just redisplay the shadow.
  920.  */
  921. static void
  922. Redisplay(DtComboBoxWidget w,
  923.       XEvent *event,
  924.       Region region)
  925. {
  926.   /* Wow..  These guys _released_ this shit. */
  927. #if 0
  928.     DrawShadow(w, COMBO_MARGIN_W(w), COMBO_MARGIN_H(w), COMBO_SHADOW(w));
  929. #else
  930.     DrawShadow(w);
  931. #endif
  932. }
  933.  
  934.  
  935. /*
  936.  * GeometryManager function called by toolkit when a child resizes/moves.
  937.  * We are not allowing any changes but width/height of the text-field.
  938.  * this is because the user can retrieve the text-field and make changes
  939.  * that we want to honor.  If they mess around with the label or arrow,
  940.  * then we won't honor the request.
  941.  * If the text-field requests a change, then make the change, and allow
  942.  * our SetComboBoxSize() and LayoutChildren() figure out what size will
  943.  * be allowed.  
  944.  * Returning GeometryDone was suppose to tell the toolkit
  945.  * that we resized the child ourselves, but the text-field had trouble
  946.  * with this (its' geometry_manager wasn't called or working right?), so
  947.  * we return GeometryYes.
  948.  */
  949. static XtGeometryResult
  950. GeometryManager(Widget w,
  951.         XtWidgetGeometry *request,
  952.         XtWidgetGeometry *reply)
  953. {
  954.     DtComboBoxWidget combo = (DtComboBoxWidget)(w->core.parent);
  955.  
  956.     /* Ignore everything but text-field */
  957.     if (w != combo->combo_box.text)
  958.     return(XtGeometryNo);
  959.  
  960.     /* Only allow width/height changes */
  961.     if (!(request->request_mode & (CWWidth | CWHeight)))
  962.     return(XtGeometryNo);
  963.     
  964.     /* Set the text-field to the requested size */
  965.     if (request->request_mode & CWWidth)
  966.     w->core.width = request->width;
  967.     if (request->request_mode & CWHeight)
  968.     w->core.height = request->height;
  969.     XtResizeWidget(w, w->core.width, w->core.height, w->core.border_width);
  970.     
  971.     ClearShadow(combo, TRUE);
  972.     if (combo->combo_box.recompute_size)
  973.     SetComboBoxSize(combo);
  974.     LayoutChildren(combo);
  975.     DrawShadow(combo);
  976.     return(XtGeometryYes);
  977. }
  978.  
  979. /* 
  980.  * This function sets the size of the combo_box widget based on the
  981.  * current size of the children.  Don't worry if it doesn't work, the
  982.  * children will be squeezed in later.
  983.  */
  984. static void
  985. SetComboBoxSize(DtComboBoxWidget combo)
  986. {
  987.     DtComboBoxPart *combo_p = (DtComboBoxPart*)&(combo->combo_box);
  988.     Widget text_holder = ((combo_p->type == XmDROP_DOWN_COMBO_BOX) ? 
  989.               combo_p->text : combo_p->label);
  990.     Dimension shadow = COMBO_SHADOW(combo) * 2;
  991.     Dimension h_spacing = COMBO_H_SPACING(combo) * 2;
  992.     Dimension v_spacing = COMBO_V_SPACING(combo) * 2;
  993.     short arrow_width;
  994.     short sep_width = 0;
  995.  
  996.     /* 
  997.      * Find out how big the arrow can be (needed to get 
  998.      * available_width for text_holder).
  999.      */
  1000.     arrow_width = (Dimension)(text_holder->core.height * ARROW_MULT);
  1001.     arrow_width = (arrow_width < ARROW_MIN) ? ARROW_MIN : arrow_width;
  1002.  
  1003.     if (combo_p->type == XmDROP_DOWN_LIST_BOX)
  1004.     sep_width = combo_p->sep->core.width;
  1005.  
  1006.     (void)XtMakeResizeRequest((Widget)combo, arrow_width + sep_width +
  1007.                   combo_p->arrow_spacing +
  1008.                   text_holder->core.width + shadow + h_spacing +
  1009.                   (COMBO_MARGIN_W(combo) * 2), 
  1010.                   text_holder->core.height + shadow + v_spacing +
  1011.                   (COMBO_MARGIN_H(combo) * 2), 
  1012.                   NULL, NULL);
  1013.     combo_p->old_width = combo->core.width;
  1014.     combo_p->old_height = combo->core.height;
  1015. }
  1016.  
  1017. /*
  1018.  * This function makes the text_holder (label or text-field) smaller
  1019.  * if the combo_box couldn't grow to the needed full size.  It will
  1020.  * also make the text_holder grow if there is space.  The textfield will
  1021.  * grow with the combo_box, but the label will only grow to its' 
  1022.  * maximum size.  The label will also shrink down to nothing, but the
  1023.  * text-field will always keep its' core height.
  1024.  */
  1025. static void
  1026. ForceChildSizes(DtComboBoxWidget combo)
  1027. {
  1028.     DtComboBoxPart *combo_p = (DtComboBoxPart*)&(combo->combo_box);
  1029.     Dimension full_available_height, available_height, available_width;
  1030.     Dimension arrow_width;
  1031.     Dimension sep_width = 0;
  1032.  
  1033.     /* Calculate available height for children */
  1034.     if ((available_height = combo->core.height - (COMBO_SHADOW(combo) * 2) - 
  1035.      (COMBO_MARGIN_H(combo) * 2) - (COMBO_V_SPACING(combo) * 2)) <= 0) {
  1036.     full_available_height = available_height = 1;
  1037.     }
  1038.     else {
  1039.     /* Seperator need available_height plus the vertical_spacing */
  1040.     full_available_height = (available_height + 
  1041.                  (COMBO_V_SPACING(combo) * 2));
  1042.     }
  1043.  
  1044.     /* Get initial available width for children */
  1045.     available_width = (combo->core.width - (COMBO_SHADOW(combo) * 2) - 
  1046.                (COMBO_MARGIN_W(combo) * 2) - 
  1047.                (COMBO_H_SPACING(combo) * 2));
  1048.     
  1049.     /* label only grows to maximum width needed */
  1050.     if ((combo_p->type == XmDROP_DOWN_LIST_BOX) && 
  1051.     ((int)available_height > (int)combo_p->label_max_height))
  1052.     available_height = combo_p->label_max_height;
  1053.     else if (combo_p->type == XmDROP_DOWN_COMBO_BOX) 
  1054.     available_height = combo_p->text->core.height;
  1055.     
  1056.     /* 
  1057.      * Find out how big the arrow can be (needed to get 
  1058.      * available_width for text_holder).
  1059.      */
  1060.     arrow_width = (Dimension)(available_height * ARROW_MULT);
  1061.     arrow_width = (arrow_width < ARROW_MIN) ? ARROW_MIN : arrow_width;
  1062.     
  1063.     if (combo_p->type == XmDROP_DOWN_LIST_BOX)
  1064.     sep_width = combo_p->sep->core.width;
  1065.  
  1066.     /* Make sure width isn't too small or too big */
  1067.     if ((int)(available_width -= 
  1068.           (arrow_width + sep_width + combo_p->arrow_spacing)) <= 0)
  1069.     available_width = 1;
  1070.  
  1071.     if (combo_p->type == XmDROP_DOWN_LIST_BOX) {  /** label **/
  1072.     if ((int)available_width > (int)combo_p->label_max_length)
  1073.         available_width = combo_p->label_max_length;
  1074.  
  1075.     if ((available_width != combo_p->label->core.width) ||
  1076.         (available_height != combo_p->label->core.height))
  1077.         XtResizeWidget(combo_p->label, available_width, available_height,
  1078.                combo_p->label->core.border_width);
  1079.  
  1080.     if (full_available_height != combo_p->sep->core.height)
  1081.         XtResizeWidget(combo_p->sep, combo_p->sep->core.width,
  1082.                full_available_height,
  1083.                combo_p->sep->core.border_width);
  1084.     }
  1085.     else if (combo_p->text->core.width != available_width)  /** TextField **/
  1086.     XtResizeWidget(combo_p->text, available_width,
  1087.                combo_p->text->core.height,
  1088.                combo_p->text->core.border_width);
  1089.     if ((arrow_width != combo_p->arrow->core.width) ||
  1090.     (combo_p->arrow->core.height != available_height)) {
  1091.     available_height = (available_height < ARROW_MIN) ? ARROW_MIN : 
  1092.                             available_height;
  1093.     XtResizeWidget(combo_p->arrow, arrow_width, available_height,
  1094.                combo_p->arrow->core.border_width);
  1095.     }
  1096. }
  1097.  
  1098. /*
  1099.  * This function positions the children within the combo_box widget.
  1100.  * It calls ForceChildSizes() to make sure the children fit within the
  1101.  * combo_box widget, but it will not try to resize the combo_box widget.
  1102.  */
  1103. static void
  1104. LayoutChildren(DtComboBoxWidget combo)
  1105. {
  1106.     DtComboBoxPart *combo_p = (DtComboBoxPart*)&(combo->combo_box);
  1107.     Widget text_holder = ((combo_p->type == XmDROP_DOWN_COMBO_BOX)
  1108.               ? combo_p->text : combo_p->label);
  1109.     Position start_x = (COMBO_SHADOW(combo) + COMBO_MARGIN_W(combo) +
  1110.             COMBO_H_SPACING(combo));
  1111.     Position start_y = (COMBO_SHADOW(combo) + COMBO_MARGIN_H(combo) +
  1112.             COMBO_V_SPACING(combo));
  1113.     short available_height = combo->core.height - (start_y * 2);
  1114.     Position y, arrow_y;
  1115.     
  1116.     ForceChildSizes(combo);
  1117.  
  1118.     /* Center text_holder within combo_box */
  1119.     y = available_height - text_holder->core.height;
  1120.     y = ((y < 0) ? 0 : y)/2 + start_y;
  1121.  
  1122.     /* Center arrow within combo_box */
  1123.     arrow_y = available_height - combo_p->arrow->core.height;
  1124.     arrow_y = ((arrow_y < 0) ? 0 : arrow_y)/2 + start_y;
  1125.  
  1126.     if (combo_p->orientation == XmLEFT) {
  1127.     XtMoveWidget(combo_p->arrow, start_x, arrow_y);
  1128.     start_x += combo_p->arrow->core.width;
  1129.     if (combo_p->type == XmDROP_DOWN_LIST_BOX) {
  1130.         XtMoveWidget(combo_p->sep, start_x, start_y - 
  1131.              COMBO_V_SPACING(combo));
  1132.         start_x += combo_p->sep->core.width;
  1133.     }
  1134.     start_x += combo_p->arrow_spacing;
  1135.     XtMoveWidget(text_holder, start_x, y);
  1136.     }
  1137.     else {
  1138.     XtMoveWidget(text_holder, start_x, y);
  1139.     /*  
  1140.      * We want the arrow at the end of the combo_box, so
  1141.      * the user can use recompute_size more effectively.
  1142.      */
  1143.     start_x = combo->core.width - start_x - combo_p->arrow->core.width;
  1144.     if (combo_p->type == XmDROP_DOWN_LIST_BOX) {
  1145.         start_x -= combo_p->sep->core.width;
  1146.         XtMoveWidget(combo_p->sep, start_x, start_y -
  1147.              COMBO_V_SPACING(combo));
  1148.         start_x += combo_p->sep->core.width;
  1149.     }
  1150.     XtMoveWidget(combo_p->arrow, start_x, arrow_y);
  1151.     }
  1152. }
  1153.  
  1154. /*
  1155.  * SetValues() routine for ComboBox widget. 
  1156.  */
  1157. static Boolean
  1158. SetValues(DtComboBoxWidget current,
  1159.       DtComboBoxWidget request,
  1160.       DtComboBoxWidget new)
  1161. {
  1162.     DtComboBoxPart *new_p = (DtComboBoxPart*)&(new->combo_box);
  1163.     DtComboBoxPart *cur_p = (DtComboBoxPart*)&(current->combo_box);
  1164.     Boolean label_size_changed = FALSE;
  1165.     Boolean force_label_string = FALSE;
  1166.     Arg args[10];
  1167.     int n;
  1168.  
  1169.     CheckResources(new);
  1170.  
  1171.     if (new_p->text != cur_p->text) {
  1172.     XtWarning(COMBO_TEXT);
  1173.     new_p->text = cur_p->text;
  1174.     }
  1175.  
  1176.     /*
  1177.      * Pass any list specific resources on to our List Widget.
  1178.      * Check each one, since it's too costly to always set them.
  1179.      */
  1180.     n = 0;
  1181.     if (new_p->item_count != cur_p->item_count){
  1182.     if (new_p->items && (new_p->item_count < 0)) {
  1183.         XtWarning(COMBO_ITEM_COUNT);
  1184.         new_p->item_count = 0;
  1185.     }
  1186.     XtSetArg(args[n], XmNitemCount, new_p->item_count); n++;
  1187.     }
  1188.     if (new_p->items != cur_p->items) {
  1189.     XtSetArg(args[n], XmNitems, new_p->items); n++;
  1190.     /* Make sure itemCount will get sent to list */
  1191.     if (new_p->item_count == cur_p->item_count) {
  1192.         XtSetArg(args[n], XmNitemCount, new_p->item_count); n++;
  1193.     }
  1194.     }
  1195.     if (new_p->list_font_list != cur_p->list_font_list) {
  1196.     XtSetArg(args[n], XmNfontList, new_p->list_font_list); n++;
  1197.     }
  1198.     if (new_p->list_margin_height != cur_p->list_margin_height) {
  1199.     XtSetArg(args[n], XmNlistMarginHeight, new_p->list_margin_height); n++; 
  1200.     }
  1201.     if (new_p->list_margin_width != cur_p->list_margin_width) {
  1202.     XtSetArg(args[n], XmNlistMarginWidth, new_p->list_margin_width); n++;
  1203.     }
  1204.     if (new_p->list_spacing != cur_p->list_spacing) {
  1205.     XtSetArg(args[n], XmNlistSpacing, new_p->list_spacing); n++;
  1206.     }
  1207.     if (new->manager.string_direction != current->manager.string_direction) {
  1208.     XtSetArg(args[n], XmNstringDirection, new->manager.string_direction); n++;
  1209.     }
  1210.     if (new_p->top_item_position != cur_p->top_item_position) {
  1211.     XtSetArg(args[n], XmNtopItemPosition, new_p->top_item_position); n++;
  1212.     }
  1213.     if (new_p->visible_item_count != cur_p->visible_item_count) {
  1214.     XtSetArg(args[n], XmNvisibleItemCount, new_p->visible_item_count); n++;
  1215.     }
  1216.     if (n > 0) {
  1217.     XtSetValues(new_p->list, args, n);
  1218.     new_p->max_shell_width = new_p->shell->core.width;
  1219.     new_p->max_shell_height = new_p->shell->core.height;
  1220.     }
  1221.  
  1222.     /* If arrow type changes delete the old one and create the new one */
  1223.     if (new_p->arrow_type != cur_p->arrow_type) {
  1224.     XtRemoveCallback(new_p->arrow, XmNactivateCallback, activate_cb, 
  1225.              (XtPointer)new);
  1226.     if (cur_p->arrow_type == XmWINDOWS)
  1227.         XtRemoveCallback(new_p->arrow, XmNexposeCallback,
  1228.                  arrow_expose_cb, (XtPointer)new);
  1229.     XtDestroyWidget(new_p->arrow);
  1230.  
  1231.     n = 0;
  1232.     XtSetArg(args[n], XmNtraversalOn, FALSE); n++;
  1233.     XtSetArg(args[n], XmNhighlightThickness, 0); n++;
  1234.     XtSetArg(args[n], XmNshadowThickness, 0); n++;
  1235.     if (new_p->arrow_type == XmMOTIF) {
  1236.         XtSetArg(args[n], XmNarrowDirection, XmARROW_DOWN); n++;
  1237.         XtSetArg(args[n], XmNforeground, new->core.background_pixel); n++;
  1238.         new_p->arrow = XtCreateManagedWidget("ComboBoxArrow", 
  1239.                          xmArrowButtonWidgetClass,
  1240.                          (Widget)new, args, n);
  1241.     }
  1242.     else {
  1243.         new_p->arrow = XtCreateManagedWidget("ComboBoxArrow", 
  1244.                          xmDrawnButtonWidgetClass,
  1245.                          (Widget)new, args, n);
  1246.         XtAddCallback(new_p->arrow, XmNexposeCallback, arrow_expose_cb, 
  1247.               (XtPointer)new);
  1248.     }
  1249.     XtAddCallback(new_p->arrow, XmNactivateCallback, activate_cb, 
  1250.               (XtPointer)new);
  1251.     }
  1252.  
  1253.     /*
  1254.      * Type resource changed.  If the widget (textField or Label)
  1255.      * doesn't exist, then create it.  Always reset orientation
  1256.      * constraint resources when type changes; otherwise, the
  1257.      * text_holder widget positioning could be screwed up.  We don't
  1258.      * reset both widgets if the orientation changes (because we might
  1259.      * not have created both widgets).
  1260.      * If label must be created, also create the separator widget.
  1261.      */
  1262.     if (new_p->type != cur_p->type) {
  1263.     if (new_p->type == XmDROP_DOWN_COMBO_BOX) {
  1264.         if (new_p->text == NULL) {
  1265.         n = 0;
  1266.         XtSetArg(args[n], XmNcolumns, new_p->text_columns); n++;
  1267.         XtSetArg(args[n], XmNmaxLength, new_p->text_max_length); n++;
  1268.         XtSetArg(args[n], XmNmarginWidth, 2); n++;
  1269.         XtSetArg(args[n], XmNmarginHeight, 2); n++;
  1270.         new_p->text = XtCreateWidget("ComboBoxTextField", 
  1271.                          xmTextFieldWidgetClass,
  1272.                          (Widget)new, args, n);
  1273.         XtAddCallback(new_p->text, XmNlosingFocusCallback, 
  1274.                   text_losing_focus_cb, (XtPointer)new);
  1275.         XtAddCallback(new_p->text, XmNactivateCallback, 
  1276.                   text_activate_cb, (XtPointer)new);
  1277.         XtAddCallback(new_p->text, XmNfocusCallback, 
  1278.                   text_focus_cb, (XtPointer)new);
  1279.         if (new_p->horizontal_spacing == cur_p->horizontal_spacing)
  1280.             new_p->horizontal_spacing = 0;
  1281.         if (new_p->vertical_spacing == cur_p->vertical_spacing)
  1282.             new_p->vertical_spacing = 0;
  1283.         }
  1284.         XtUnmanageChild(new_p->sep);
  1285.         XtUnmanageChild(new_p->label);
  1286.         XtManageChild(new_p->text);
  1287.     }
  1288.     else {
  1289.         if (new_p->label == NULL) {
  1290.         XtTranslations label_trans = 
  1291.             XtParseTranslationTable(ComboBoxLabelTranslationTable);
  1292.  
  1293.         n = 0;
  1294.         XtSetArg(args[n], XmNalignment, new_p->alignment); n++;
  1295.         XtSetArg(args[n], XmNrecomputeSize, FALSE); n++;
  1296.         XtSetArg(args[n], XmNmarginLeft, LABEL_PADDING); n++;
  1297.         XtSetArg(args[n], XmNmarginRight, LABEL_PADDING); n++;
  1298.         XtSetArg(args[n], XmNmarginWidth, 0); n++;
  1299.         XtSetArg(args[n], XmNmarginHeight, 0); n++;
  1300.         XtSetArg(args[n], XmNstringDirection, 
  1301.              new->manager.string_direction); n++;
  1302.         new_p->label = XtCreateWidget("ComboBoxLabel", 
  1303.                           xmLabelWidgetClass,
  1304.                           (Widget)new, args, n);
  1305.         XtOverrideTranslations((Widget)new_p->label, label_trans);
  1306.         if (new_p->horizontal_spacing == cur_p->horizontal_spacing)
  1307.             new_p->horizontal_spacing = 1;
  1308.         if (new_p->vertical_spacing == cur_p->vertical_spacing)
  1309.             new_p->vertical_spacing = 2;
  1310.  
  1311.         n = 0;
  1312.         XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
  1313.         new_p->sep = XtCreateWidget("ComboBoxSeparator", 
  1314.                         xmSeparatorWidgetClass,
  1315.                         (Widget)new, args, n);
  1316.         }
  1317.         else if (new->manager.string_direction != 
  1318.              current->manager.string_direction) {
  1319.         XtSetArg(args[0], XmNstringDirection, 
  1320.              new->manager.string_direction);
  1321.         XtSetValues(new_p->label, args, 1);
  1322.         }
  1323.         XtUnmanageChild(new_p->text);
  1324.         XtManageChild(new_p->label);
  1325.         XtManageChild(new_p->sep);
  1326.     }
  1327.     /* 
  1328.      * Text-fields and labels have different shadows.  Only
  1329.      * change if user didn't change the shadow resource.
  1330.      */
  1331.     if (COMBO_SHADOW(new) == COMBO_SHADOW(current))
  1332.         COMBO_SHADOW(new) = ((new_p->type == XmDROP_DOWN_COMBO_BOX) ?
  1333.                  TEXT_FIELD_SHADOW : LABEL_SHADOW);
  1334.     }
  1335.  
  1336.     if (new_p->text && (new_p->text == cur_p->text)) {
  1337.     n = 0;
  1338.     if (new_p->text_columns != cur_p->text_columns) {
  1339.         XtSetArg(args[n], XmNcolumns, new_p->text_columns); n++;
  1340.     }
  1341.     if (new_p->text_max_length != cur_p->text_max_length) {
  1342.         XtSetArg(args[n], XmNmaxLength, new_p->text_max_length); n++;
  1343.     }
  1344.     if (n > 0)
  1345.         XtSetValues(new_p->text, args, n);
  1346.     }
  1347.  
  1348.     /*
  1349.      * LabelWidget alignment has changed.
  1350.      */
  1351.     if (new_p->label && (new_p->alignment != cur_p->alignment)) {
  1352.     XtSetArg(args[0], XmNalignment, new_p->alignment);
  1353.     XtSetValues(new_p->label, args, 1);
  1354.     }
  1355.  
  1356.     if (new_p->label && ((new_p->items != cur_p->items) || 
  1357.              (new_p->item_count != cur_p->item_count) ||
  1358.              (new_p->label != cur_p->label))) {
  1359.     SetMaximumLabelSize(new_p);
  1360.     label_size_changed = TRUE;
  1361.     }
  1362.  
  1363.     /* Copy and free label-string */
  1364.     if (new_p->label_string != cur_p->label_string) {
  1365.     if (new_p->label_string)
  1366.         new_p->label_string = XmStringCopy(new_p->label_string);
  1367.     if (cur_p->label_string)
  1368.         XmStringFree(cur_p->label_string);    
  1369.     /* 
  1370.      * force_label_string usage if it is specified and items is not.
  1371.      * This will be the perminant label string only if update-label
  1372.      * is false, else it is only used until the user picks something
  1373.      * new off the list.
  1374.      */
  1375.     if (new_p->items == cur_p->items)
  1376.         force_label_string = TRUE;
  1377.     }
  1378.  
  1379.     if ((new_p->items != cur_p->items) ||
  1380.     (new_p->alignment != cur_p->alignment) ||
  1381.     (new_p->type != cur_p->type) ||
  1382.     (new_p->item_count != cur_p->item_count) ||
  1383.     (new_p->selected_position != cur_p->selected_position) ||
  1384.     (new_p->selected_item != cur_p->selected_item) ||
  1385.     (new_p->label != cur_p->label) ||
  1386.     (new_p->update_label != cur_p->update_label) ||
  1387.     (new_p->label_string != cur_p->label_string)) {
  1388.  
  1389.     /* selected_item resource used before selected_position */
  1390.     if (new_p->selected_item &&
  1391.         (new_p->selected_item != cur_p->selected_item))
  1392.         DtComboBoxSelectItem((Widget)new, new_p->selected_item);
  1393.     else
  1394.         XmListSelectPos(new_p->list, new_p->selected_position + 1, FALSE);
  1395.  
  1396.  
  1397.     if (new_p->type == XmDROP_DOWN_COMBO_BOX)
  1398.         SetTextFieldData(new_p, NULL);
  1399.     else
  1400.         SetLabelData(new_p, NULL, force_label_string);
  1401.     }
  1402.    
  1403.     /*
  1404.      * Must recalculate the combo_box and re-layout the children.
  1405.      * If this is not editable, then set the label to its' maximum
  1406.      * size; it will get chopped if it is too big.  This is needed 
  1407.      * because we shrink the label down, and SetComboBoxSize() uses
  1408.      * the label's core sizes to figure what size to become.
  1409.      */
  1410.     if ((new_p->type != cur_p->type) ||
  1411.     (new_p->arrow_type != cur_p->arrow_type) ||
  1412.     (COMBO_MARGIN_W(new) != COMBO_MARGIN_W(current)) ||
  1413.     (COMBO_MARGIN_H(new) != COMBO_MARGIN_H(current)) ||
  1414.     (COMBO_H_SPACING(new) != COMBO_H_SPACING(current)) ||
  1415.     (COMBO_V_SPACING(new) != COMBO_V_SPACING(current)) ||
  1416.     (COMBO_SHADOW(new) != COMBO_SHADOW(current)) ||
  1417.     (new_p->orientation != cur_p->orientation) ||
  1418.     (new_p->arrow_spacing != cur_p->arrow_spacing) ||
  1419.     ((new_p->type == XmDROP_DOWN_LIST_BOX) && label_size_changed)) {
  1420.     ClearShadow(current, TRUE);
  1421.     if (new_p->recompute_size)
  1422.         SetComboBoxSize(new);
  1423.     LayoutChildren(new);
  1424.     DrawShadow(new);
  1425.     }
  1426.  
  1427.     SyncWithList(new_p);
  1428.     return(FALSE);
  1429. }
  1430.  
  1431.  
  1432. /*
  1433.  * This function clears the shadow around our widget.  If all is TRUE,
  1434.  * then clear all 4 sides; otherwise, only clear the right and bottom
  1435.  * sides (during resize). 
  1436.  */ 
  1437. static void
  1438. ClearShadow(DtComboBoxWidget w,
  1439.         Boolean all)
  1440. {
  1441.     Dimension shadow = COMBO_SHADOW(w);
  1442.     Dimension margin_w = COMBO_MARGIN_W(w);
  1443.     Dimension margin_h = COMBO_MARGIN_H(w);
  1444.  
  1445.     if ((shadow > 0) && XtIsRealized(w)) {
  1446.     if (all) {
  1447.         XClearArea(XtDisplayOfObject((Widget)w),
  1448.                XtWindowOfObject((Widget)w), 
  1449.                margin_w, margin_h,
  1450.                w->combo_box.old_width - (margin_w * 2),
  1451.                shadow, FALSE);
  1452.         XClearArea(XtDisplayOfObject((Widget)w),
  1453.                XtWindowOfObject((Widget)w), 
  1454.                margin_w, margin_h, shadow, 
  1455.                w->combo_box.old_height - (margin_h * 2), FALSE);
  1456.     }
  1457.     XClearArea(XtDisplayOfObject((Widget)w), 
  1458.            XtWindowOfObject((Widget)w), margin_w,
  1459.            w->combo_box.old_height - margin_h - shadow,
  1460.            w->combo_box.old_width - (margin_w * 2), shadow, FALSE);
  1461.     XClearArea(XtDisplayOfObject((Widget)w), XtWindowOfObject((Widget)w),
  1462.            w->combo_box.old_width - margin_w - shadow,
  1463.            margin_h, shadow, 
  1464.            w->combo_box.old_height - (margin_h * 2), FALSE);
  1465.     }
  1466.     DrawHighlight(w, TRUE);
  1467. }
  1468.  
  1469. /* 
  1470.  * This functions draws the shadow around our combo-box.
  1471.  */
  1472. static void
  1473. DrawShadow(DtComboBoxWidget w)
  1474. {
  1475.     Dimension shadow = COMBO_SHADOW(w);
  1476.     Dimension margin_w = COMBO_MARGIN_W(w);
  1477.     Dimension margin_h = COMBO_MARGIN_H(w);
  1478.     
  1479.     if ((shadow > 0) && XtIsRealized(w)) {
  1480.     _XmDrawShadows(XtDisplayOfObject((Widget)w),
  1481.                XtWindowOfObject((Widget)w),
  1482.                w->manager.top_shadow_GC,
  1483.                w->manager.bottom_shadow_GC, 
  1484.                margin_w, margin_h,
  1485.                w->core.width - (margin_w * 2),
  1486.                w->core.height - (margin_h * 2),
  1487.                shadow, XmSHADOW_OUT);
  1488.     }
  1489.     DrawHighlight(w, FALSE);
  1490. }
  1491.  
  1492. /*
  1493.  * Take the string out of the list and put it into the text-field.
  1494.  * text-fields don't handle xm-strings, so we must get the char*
  1495.  * out of it (only getting the first segment).  This is slower than
  1496.  * storing the text-strings (char*) ourselves, but that would take
  1497.  * up a lot of memory.  Since this setting happens during a user
  1498.  * action, speed isn't a problem.
  1499.  */
  1500. static void
  1501. SetTextFieldData(DtComboBoxPart *combo_p,
  1502.          XmString item)
  1503. {
  1504.     XmListWidget list = (XmListWidget)combo_p->list;
  1505.     Arg arg;
  1506.  
  1507.  
  1508.     if (!item && list->list.itemCount)
  1509.         item = list->list.items[combo_p->selected_position];
  1510.  
  1511.     if (!item) 
  1512.     {
  1513.         combo_p->selected_item = NULL;
  1514.         XtSetArg(arg, XmNvalue, "");
  1515.         XtSetValues(combo_p->text, &arg, 1);
  1516.     }
  1517.     else 
  1518.     {
  1519.         XmStringContext            context = NULL;
  1520.         char *                    text = NULL;
  1521.         XmStringCharSet            charset = NULL;
  1522.  
  1523.         XmStringDirection        direction;
  1524.         XmStringComponentType    unknown_tag;
  1525.         XmStringComponentType    type;
  1526.  
  1527.         unsigned short            ul = 0;
  1528.         unsigned char *            uv = NULL;
  1529.  
  1530.         Boolean                    done = FALSE;
  1531.  
  1532.         combo_p->selected_item = item;
  1533.  
  1534.         XmStringInitContext(&context, item);
  1535.     
  1536.         /* Loop until 1st char* found */
  1537.         while (!done) 
  1538.         {
  1539.             type = XmStringGetNextComponent(context, 
  1540.                                             &text, 
  1541.                                             &charset,
  1542.                                             &direction, 
  1543.                                             &unknown_tag, 
  1544.                                             &ul, 
  1545.                                             &uv);
  1546.             switch (type) 
  1547.             {
  1548.             case XmSTRING_COMPONENT_END:
  1549.                 done = TRUE;
  1550.                 break;
  1551.  
  1552.             case XmSTRING_COMPONENT_TEXT:
  1553.             case XmSTRING_COMPONENT_LOCALE_TEXT:
  1554.                 XtSetArg(arg, XmNvalue, text);
  1555.                 XtSetValues(combo_p->text, &arg, 1);
  1556.  
  1557.             if (text)
  1558.                 XtFree((char *) text);
  1559.  
  1560.                 done = TRUE;
  1561.                 break;
  1562.  
  1563.             case XmSTRING_COMPONENT_CHARSET:
  1564.                 if (charset)
  1565.                     XtFree((char *) charset);
  1566.                 break;
  1567.  
  1568.             default:
  1569.                 if (uv)
  1570.                     XtFree((char *) uv);
  1571.                 break;
  1572.             }
  1573.  
  1574.  
  1575.  
  1576.         }
  1577.  
  1578.         if (context)
  1579.             XmStringFreeContext(context);
  1580.     }
  1581.  
  1582. }
  1583.  
  1584.  
  1585. /*
  1586.  * Set the maximum size of the label, depending on the
  1587.  * characteristics of the list of items.
  1588.  */
  1589. static void
  1590. SetMaximumLabelSize(DtComboBoxPart *combo_p)
  1591. {
  1592.     XmListWidget list = (XmListWidget)combo_p->list;
  1593.     XmFontList font_list;
  1594.     Dimension width, height;
  1595.     Dimension longest = 0;
  1596.     Dimension highest = 0;
  1597.     Arg args[5];
  1598.     int i;
  1599.  
  1600.     /* Get font info from the widget */
  1601.     XtSetArg(args[0], XmNfontList, &font_list);
  1602.     XtGetValues(combo_p->label, args, 1);
  1603.  
  1604.     if ( list->list.itemCount && combo_p->update_label) {
  1605.     /*
  1606.      * Loop through all the items to find the biggest dimensions
  1607.      */
  1608.     for (i = 0; i < combo_p->item_count; i++) {
  1609.         XmStringExtent(font_list, list->list.items[i], &width, &height);
  1610.         longest = (width > longest) ? width : longest;
  1611.         highest = (height > highest) ? height : highest;
  1612.     }
  1613.     }
  1614.     else {
  1615.     XmStringExtent(font_list, combo_p->label_string, &longest, &highest);
  1616.     }
  1617.     
  1618.     combo_p->label_max_length = longest + (LABEL_PADDING * 2);
  1619.     combo_p->label_max_height = highest;
  1620.     XtResizeWidget(combo_p->label, combo_p->label_max_length, highest, 
  1621.            combo_p->label->core.border_width);
  1622. }
  1623.  
  1624.  
  1625. /*
  1626.  * Put the current list item into the label.
  1627.  * This could probably be faster if we see if the label is the
  1628.  * same as the new item?
  1629.  */
  1630. static void
  1631. SetLabelData(DtComboBoxPart *combo_p,
  1632.          XmString item,
  1633.          Boolean force_label_string)
  1634. {
  1635.     XmListWidget list = (XmListWidget)combo_p->list;
  1636.     int index = combo_p->selected_position;
  1637.     Arg arg;
  1638.  
  1639.     /*
  1640.      * If the item is empty, get the current item from the list, or
  1641.      * use label_string if update_label is FALSE.  If that is empty, 
  1642.      * use InitLabel.
  1643.      */
  1644.     if (force_label_string || (combo_p->update_label == FALSE))
  1645.     item = combo_p->label_string ? combo_p->label_string : InitLabel;
  1646.     else {
  1647.     if (!item) {
  1648.         if (list->list.itemCount)
  1649.         item = list->list.items[index];
  1650.         else
  1651.         item = InitLabel;
  1652.     }
  1653.     
  1654.     /* Keep label_string in sync with item picked */
  1655.     if (combo_p->label_string)
  1656.         XmStringFree(combo_p->label_string);
  1657.     combo_p->label_string = XmStringCopy(item);
  1658.     }
  1659.  
  1660.     combo_p->selected_item = item;
  1661.     XtSetArg(arg, XmNlabelString, item);
  1662.     XtSetValues(combo_p->label, &arg, 1);
  1663. }
  1664.  
  1665. /*
  1666.  * This is the browseSelect and defaultAction callback handler for the
  1667.  * ListWidget.  If using the textWidget, we only take the first 
  1668.  * segment of the XmString (TextWidgets don't handle XmStrings).  If we
  1669.  * are using a label, then just set the labelString resource.
  1670.  */
  1671. static void
  1672. select_cb(Widget w,
  1673.       XtPointer client_data,
  1674.       XtPointer call_data)
  1675. {
  1676.     DtComboBoxWidget combo_w = (DtComboBoxWidget)client_data;
  1677.     DtComboBoxPart *combo_p = (DtComboBoxPart*)&(combo_w->combo_box);
  1678.     XmListCallbackStruct *info = (XmListCallbackStruct*)call_data;
  1679.     DtComboBoxCallbackStruct cb;
  1680.     
  1681.     combo_p->selected_position = info->item_position - 1;
  1682.     if (combo_p->type == XmDROP_DOWN_COMBO_BOX) {
  1683.     SetTextFieldData(combo_p, info->item);
  1684.     }
  1685.     else {    /* Set the labelWidget string */
  1686.     SetLabelData(combo_p, info->item, FALSE);
  1687.     }
  1688.     
  1689.     /*
  1690.      * Only popdown if this is the defaultAction callback.  We don't
  1691.      * want to popdown with browseSelect callback; that would cause the
  1692.      * menu to popdown when the user moved selection with the keyboard.
  1693.      * Doing it this way, allows the menu to stay up during 
  1694.      * keyboard navigation.  When menu goes away, make sure input
  1695.      * focus goes back into the textField (if editable).
  1696.      */
  1697.     if (info->reason == XmCR_DEFAULT_ACTION) {
  1698.     combo_p->popped_up = FALSE;
  1699.     XtPopdown(combo_p->shell);
  1700.     XtUngrabPointer(combo_p->shell, CurrentTime);
  1701.     XtUngrabKeyboard(combo_p->list, CurrentTime);
  1702.     /*
  1703.      * _XmRemoveGrab() was causing trouble on irix and linux.  The navigator
  1704.      * stopped responding to clicks cause of it.
  1705.      *
  1706.      */
  1707. #if 0
  1708.     _XmRemoveGrab(combo_p->shell);
  1709. #else
  1710.     XtRemoveGrab(combo_p->shell);
  1711.  
  1712.     DisplayUserGrabbed(w) = False;
  1713. #endif
  1714.     XFlush(XtDisplay(combo_p->shell));
  1715.     if (combo_p->type == XmDROP_DOWN_COMBO_BOX)
  1716.         XmProcessTraversal(combo_p->text, XmTRAVERSE_CURRENT);
  1717.     }
  1718.  
  1719.     if (((ShellWidget)(combo_p->shell))->shell.popped_up == FALSE) {
  1720.     /* The list will free info->item */
  1721.     cb.reason = XmCR_SELECT;
  1722.     cb.event = info->event;
  1723.     cb.item_or_text = info->item;
  1724.     cb.item_position = combo_p->selected_position;
  1725.     XtCallCallbackList((Widget)w, combo_p->selection_callback, 
  1726.                (XtPointer)&cb);
  1727.     }
  1728. }
  1729.  
  1730.  
  1731. /*
  1732.  * This is the event_handler for our shell widget.  The grab happens
  1733.  * on the shell while the user is not doing anything inside the list.
  1734.  * This allows us to know if the user pressed a button outside our
  1735.  * application.  If the user pressed a button anywhere but inside
  1736.  * the shell, then popdown the menu and ungrab everything.
  1737.  */
  1738. static void
  1739. shell_event_handler(Widget widget,
  1740.             XtPointer client_data,
  1741.             XEvent *event,
  1742.             Boolean *dispatch)
  1743. {
  1744.     DtComboBoxWidget combo_w = (DtComboBoxWidget)client_data;
  1745.     DtComboBoxPart *combo_p = (DtComboBoxPart*)&(combo_w->combo_box);
  1746.     XmScrolledWindowWidget sw = (XmScrolledWindowWidget)XtParent(combo_p->list);
  1747.     XmScrollBarWidget v_scrollbar = sw->swindow.vScrollBar;
  1748.     XmScrollBarWidget h_scrollbar = sw->swindow.hScrollBar;
  1749.     Window window = event->xbutton.window;
  1750.  
  1751.     if (((ShellWidget)(combo_p->shell))->shell.popped_up &&
  1752.     (window != XtWindowOfObject(combo_p->list)) &&
  1753.     (h_scrollbar && (window != XtWindowOfObject((Widget)h_scrollbar))) &&
  1754.     (v_scrollbar && (window != XtWindowOfObject((Widget)v_scrollbar)))) {
  1755.     combo_p->popped_up = FALSE;
  1756.     XtPopdown(combo_p->shell);
  1757.     XtUngrabPointer(combo_p->shell, CurrentTime);
  1758.     XtUngrabKeyboard(combo_p->list, CurrentTime);
  1759.     /*
  1760.      * _XmRemoveGrab() was causing trouble on irix and linux.  The navigator
  1761.      * stopped responding to clicks cause of it.
  1762.      *
  1763.      */
  1764. #if 0
  1765.     _XmRemoveGrab(combo_p->shell);
  1766. #else
  1767.     XtRemoveGrab(combo_p->shell);
  1768.  
  1769.     DisplayUserGrabbed(widget) = False;
  1770. #endif
  1771.     if (combo_p->type == XmDROP_DOWN_COMBO_BOX)
  1772.         XmProcessTraversal(combo_p->text, XmTRAVERSE_CURRENT);
  1773.     }
  1774. }
  1775.  
  1776.  
  1777. /*
  1778.  * This is the event_handler for our list widget.  Getting the pointer
  1779.  * grabbing to work correctly was not very easy.  In order for everything
  1780.  * to work correctly, we only do grab-pointer, for the shell, while not
  1781.  * doing anything inside the list.  If doing something inside the list
  1782.  * we remove the grab on the shell.  This is the only way that the 
  1783.  * list will get the ButtonRelease if doing browse while outside the
  1784.  * list.  The toolkit automatically does a grab in between ButtonPress
  1785.  * and ButtonRelease; therefore, the shell ungrab can't be done inside
  1786.  * the ButtonPress event.
  1787.  */
  1788. static void
  1789. list_event_handler(Widget widget,
  1790.            XtPointer client_data,
  1791.            XEvent *event,
  1792.            Boolean *dispatch)
  1793. {
  1794.     DtComboBoxWidget combo_w = (DtComboBoxWidget)client_data;
  1795.     DtComboBoxPart *combo_p = (DtComboBoxPart*)&(combo_w->combo_box);
  1796.     static int btn_down = False;
  1797.  
  1798.     switch (event->type) {
  1799.     case ButtonPress:
  1800.     /* 
  1801.      * Can't ungrab shell because of toolkit interaction (the toolkit
  1802.      * automatically does a grab in between ButtonPress and
  1803.      * ButtonRelease).
  1804.      */
  1805.     btn_down = True;
  1806.     break;
  1807.     case ButtonRelease:
  1808.     /*
  1809.      * Get rid of menu when Button is released.
  1810.      */
  1811.     combo_p->popped_up = FALSE;
  1812.     XtPopdown(combo_p->shell);
  1813.     XtUngrabKeyboard(combo_p->list, CurrentTime);
  1814.     /*
  1815.      * _XmRemoveGrab() was causing trouble on irix and linux.  The navigator
  1816.      * stopped responding to clicks cause of it.
  1817.      *
  1818.      */
  1819. #if 0
  1820.     _XmRemoveGrab(combo_p->shell);
  1821. #else
  1822.     XtRemoveGrab(combo_p->shell);
  1823.  
  1824.     DisplayUserGrabbed(widget) = False;
  1825.  
  1826. #endif
  1827.     if (combo_p->type == XmDROP_DOWN_COMBO_BOX)
  1828.         XmProcessTraversal(combo_p->text, XmTRAVERSE_CURRENT);
  1829.     btn_down = False;
  1830.     break;
  1831.     case FocusOut:
  1832.     /*
  1833.      * There are interaction problems between the list and the
  1834.      * scrollbars in terms of Focus.  We always want our list
  1835.      * to have focus, so grab it back if we lose it.
  1836.      */
  1837.     if (((ShellWidget)(combo_p->shell))->shell.popped_up) {
  1838.         _XmGrabKeyboard(widget, False, GrabModeAsync, GrabModeAsync, 
  1839.                 CurrentTime);
  1840.         XtSetKeyboardFocus(combo_p->list, RevertToNone);
  1841.     }
  1842.     break;
  1843.     case EnterNotify:
  1844.     /*
  1845.      * Don't let the shell have the pointer grabbed while
  1846.      * we are inside the list.
  1847.      */
  1848.     if (btn_down == False) {
  1849.         XtUngrabPointer(combo_p->shell, CurrentTime);
  1850.     }
  1851.     break;
  1852.     case LeaveNotify:
  1853.     /*
  1854.      * Only let the shell have the grab if the menu is up
  1855.      * and the btn isn't down.  We don't want the shell to
  1856.      * have the grab while the user is interacting in any way
  1857.      * with the list.
  1858.      */
  1859.     if ((((ShellWidget)(combo_p->shell))->shell.popped_up) &&
  1860.         (btn_down == FALSE)) {
  1861.         _XmGrabPointer(combo_p->shell, True, ButtonPressMask,
  1862.                GrabModeAsync, GrabModeAsync, None, 
  1863.                XmGetMenuCursor(XtDisplayOfObject(combo_p->shell)),
  1864.                CurrentTime);
  1865.     }
  1866.     break;
  1867.     }
  1868. }
  1869.  
  1870.  
  1871. /* Caller must free string */
  1872. static char*
  1873. GetTextString(XmString xm_string)
  1874. {
  1875.     XmStringContext context;
  1876.     XmStringComponentType type;
  1877.     XmStringCharSet charset;
  1878.     XmStringDirection direction;
  1879.     XmStringComponentType unknown_tag;
  1880.     unsigned short ul;
  1881.     unsigned char *uv;
  1882.     char *text = NULL;
  1883.     Boolean done = FALSE;
  1884.  
  1885.     XmStringInitContext(&context, xm_string);
  1886.     
  1887.     /* Loop until 1st char* found */
  1888.     while (!done) {
  1889.     type = XmStringGetNextComponent(context, &text, &charset,
  1890.                     &direction, &unknown_tag, 
  1891.                     &ul, &uv);
  1892.     switch (type) {
  1893.     case XmSTRING_COMPONENT_END:
  1894.         done = TRUE;
  1895.         break;
  1896.     case XmSTRING_COMPONENT_TEXT:
  1897.     case XmSTRING_COMPONENT_LOCALE_TEXT:
  1898.         done = TRUE;
  1899.         break;
  1900.     default:
  1901.         break;
  1902.     }
  1903.     }
  1904.     XmStringFreeContext(context);
  1905.     return(text);
  1906. }
  1907.  
  1908. static void
  1909. TextFieldActivate(DtComboBoxPart *combo_p)
  1910. {
  1911.     XmTextFieldWidget w = (XmTextFieldWidget)(combo_p->text);
  1912.     XmListWidget list = (XmListWidget)combo_p->list;
  1913.     XmAnyCallbackStruct cb;
  1914.     char *data = NULL;
  1915.     char *text = NULL;
  1916.     Arg arg;
  1917.     
  1918.     XtSetArg(arg, XmNvalue, &data);
  1919.     XtGetValues((Widget)w, &arg, 1);
  1920.  
  1921.     if ( list->list.itemCount)
  1922.     text = GetTextString(list->list.items[combo_p->selected_position]);
  1923.  
  1924.     if (text && data && (strcmp(text, data) == 0)) {
  1925.     XtFree(text);
  1926.     return;
  1927.     }
  1928.     /* Only send callback if both are not NULL */
  1929.     else if (!((text == NULL) && (data == NULL))) {
  1930.     cb.reason = XmCR_ACTIVATE;
  1931.     cb.event  = NULL;
  1932.     XtCallCallbackList((Widget)w, w->text.activate_callback,
  1933.                (XtPointer) &cb);
  1934.     if (text)   
  1935.         XtFree(text);
  1936.     }
  1937. }
  1938.  
  1939. /*
  1940.  * This is the activate callback for the arrow button.  This 
  1941.  * sets the shell position and width, does the correct grabs, and
  1942.  * puts the shell on the screen.
  1943.  */
  1944. static void
  1945. activate_cb(Widget w,
  1946.         XtPointer client_data,
  1947.         XtPointer call_data)
  1948. {
  1949.     DtComboBoxWidget combo_w = (DtComboBoxWidget)client_data;
  1950.     DtComboBoxPart *combo_p = (DtComboBoxPart*)&(combo_w->combo_box);
  1951.     Display *disp = XtDisplayOfObject((Widget)combo_w);
  1952.     int screen;
  1953.     Dimension width, height;
  1954.     Dimension disp_width, disp_height;
  1955.     Position root_x, root_y;
  1956.     Arg args[5];
  1957.     int n;
  1958.     char *text;
  1959.     XmString item;
  1960.  
  1961.     if ((combo_p->type == XmDROP_DOWN_COMBO_BOX) && 
  1962.         !combo_p->no_callback_for_arrow)
  1963.     {
  1964.         TextFieldActivate(combo_p);
  1965.     }
  1966.  
  1967.  
  1968.     /*
  1969.      * Don't popup if no items in the list.
  1970.      */
  1971.     if (!((XmListWidget)combo_p->list)->list.itemCount)
  1972.     return;
  1973.  
  1974.  
  1975.     if ( combo_p->move_selecteditem_up )
  1976.     {
  1977.       if ( combo_p->selected_item )
  1978.       {
  1979.       text = GetTextString(((XmListWidget)combo_p->list)->
  1980.                 list.items[combo_p->selected_position]);
  1981.  
  1982.       item = ((XmListWidget)combo_p->list)->
  1983.         list.items[combo_p->selected_position];
  1984.  
  1985.       DtComboBoxSelectItemMoveup(combo_w, item);
  1986.       }
  1987.       else 
  1988.       {
  1989.     XmListSelectPos(combo_p->list, 1, False);
  1990.     XmListSetPos (combo_p->list, 1 );
  1991.       }
  1992.     }
  1993.  
  1994.     screen = DefaultScreen(disp);
  1995.     disp_width = DisplayWidth(disp, screen);
  1996.     disp_height = DisplayHeight(disp, screen);
  1997.  
  1998.     /*
  1999.      * Call the menu-post callback if requested.  This allows the
  2000.      * user to change the items, instead of using the losing-focus callback.
  2001.      * If the user used the losing-focus callback to change the items, the
  2002.      * size of the list/shell will change while it is popped up.  We
  2003.      * could disallow SetValues while the menu is posted, but let's see
  2004.      * how things go first.
  2005.      */
  2006.     if (combo_p->menu_post_callback) {
  2007.     XmAnyCallbackStruct info;
  2008.  
  2009.     info.reason = XmCR_MENU_POST;
  2010.     info.event = (XEvent*)NULL;
  2011.     XtCallCallbackList((Widget)combo_w, combo_p->menu_post_callback, 
  2012.                (XtPointer)&info);
  2013.     }
  2014.  
  2015.     width = combo_p->max_shell_width;
  2016.     height = combo_p->max_shell_height;
  2017.  
  2018.     /* Get root coords of ComboBox */
  2019.     XtTranslateCoords((Widget)combo_w, combo_w->core.x, combo_w->core.y,
  2020.               &root_x, &root_y);
  2021.  
  2022.     /*
  2023.      * Make necessary adjustments for offset of our widget 
  2024.      * inside its' parent.  Calculate the width of the shell.
  2025.      * This must be done every time the shell gets popped up, because 
  2026.      * the x/y can change as well as the width (from list's visibleItemCount 
  2027.      * or geometry management changes).
  2028.      */
  2029.     root_x -= combo_w->core.x;
  2030.     root_y -= combo_w->core.y;
  2031.     root_y += (combo_w->core.height - COMBO_MARGIN_H(combo_w));
  2032.  
  2033.     /*
  2034.      * Make sure the shell is at least as big as our combo-box, and
  2035.      * make sure it stays on the screen.
  2036.      */
  2037.     if (width < combo_w->core.width)
  2038.     width = combo_w->core.width;
  2039.     if ((int)(root_x + width) > (int)disp_width)
  2040.     width = (disp_width - root_x);
  2041.     if ((int)(root_y + height) > (int)disp_height)
  2042.     height = (disp_height - root_y);
  2043.  
  2044.     n = 0;
  2045.     XtSetArg(args[n], XmNx, root_x); n++;
  2046.     XtSetArg(args[n], XmNy, root_y); n++;
  2047.     XtSetArg(args[n], XmNwidth, width); n++;
  2048.     XtSetArg(args[n], XmNheight, height); n++;
  2049.     XtSetValues(combo_p->shell, args, n);
  2050.  
  2051.     combo_p->popped_up = TRUE;
  2052.     XtPopup(combo_p->shell, XtGrabNone);
  2053.  
  2054.     /*
  2055.      * Set up the grab for the shell and list.  The shell gets the
  2056.      * pointer grab so that events will go into the list and scrollbars
  2057.      * correctly, but events outside the shell will go to the shell.
  2058.      * See shell and list event handlers for details about grabs.
  2059.      */
  2060.     _XmGrabPointer(combo_p->shell, True, ButtonPressMask,
  2061.            GrabModeAsync, GrabModeAsync, None, 
  2062.            XmGetMenuCursor(disp), CurrentTime);
  2063.     _XmGrabKeyboard(combo_p->list, False, GrabModeAsync, GrabModeAsync, 
  2064.            CurrentTime);
  2065.  
  2066.     /*
  2067.      * _XmAddGrab() was causing trouble on irix and linux.  The navigator
  2068.      * stopped responding to clicks cause of it.
  2069.      *
  2070.      */
  2071. #if 0
  2072.     _XmAddGrab(combo_p->shell, True, True);
  2073. #else
  2074.     XtAddGrab(combo_p->shell, True, True);
  2075.  
  2076.     DisplayUserGrabbed(w) = True;
  2077. #endif
  2078.  
  2079.     /*
  2080.      * Where to define the cursor for the list widget.  It would be
  2081.      * nice to do it in the list's realize function, but that's not
  2082.      * possible.  We can't use the ComboBox realize function, because
  2083.      * the list isn't realized at that point.  This is the simpliest
  2084.      * way to get this done.  This is needed to make sure the list has the
  2085.      * correct menu during browse scrolling, etc.
  2086.      */
  2087.     XDefineCursor(disp, XtWindowOfObject(combo_p->shell), 
  2088.           XmGetMenuCursor(disp));
  2089. }
  2090.  
  2091.  
  2092. /*
  2093.  * Make sure arrow is symetrical. 45 degree angle.  I'm not sure how
  2094.  * inefficient get/releasing the GC every time is (they are cached by
  2095.  * the toolkit)?
  2096.  */
  2097. static void
  2098. arrow_expose_cb(Widget w,
  2099.         XtPointer client_data,
  2100.         XtPointer call_data)
  2101. {
  2102.     Display *disp = XtDisplayOfObject(w);
  2103.     Window win = XtWindowOfObject(w);
  2104.     XGCValues values;
  2105.     short center_w = w->core.width/2;
  2106.     short center_h = ((int)(w->core.height - 3))/2;
  2107.     XPoint points[10];
  2108.     Arg arg;
  2109.     GC gc;
  2110.  
  2111.     XtSetArg(arg, XmNforeground, &(values.foreground));
  2112.     XtGetValues(w, &arg, 1);
  2113.  
  2114.     values.line_width = 0;
  2115.     values.line_style = LineSolid;
  2116.     values.fill_style = FillSolid;
  2117.     gc = XtGetGC(w, GCForeground | GCFillStyle | GCLineStyle | GCLineWidth,
  2118.          &values);
  2119.  
  2120.     XDrawLine(disp, win, gc, 1, center_h + center_w + 1, w->core.width - 2,
  2121.           center_h + center_w + 1);
  2122.  
  2123.     /* A - bottom point */
  2124.     points[0].x = center_w;
  2125.     points[0].y = center_h + (int)(center_w * .8);
  2126.  
  2127.     /* B - far left point */
  2128.     points[1].x = center_w - (int)(center_w * .8);
  2129.     points[1].y = center_h;
  2130.  
  2131.     /* C  - inner left point */
  2132.     points[2].x = center_w - (int)(center_w * .3);
  2133.     points[2].y = points[1].y;
  2134.  
  2135.     /* D - top left point */
  2136.     points[3].x = points[2].x;
  2137.     points[3].y = center_h - (int)(center_w * .8);
  2138.  
  2139.     /* E - top right point */
  2140.     points[4].x = center_w + (int)(center_w * .3);
  2141.     points[4].y = points[3].y;
  2142.  
  2143.     /* F - inner right point */
  2144.     points[5].x = points[4].x;
  2145.     points[5].y = points[1].y;
  2146.  
  2147.     /* G - far right point */
  2148.     points[6].x = center_w + (int)(center_w * .8);
  2149.     points[6].y = points[1].y;
  2150.  
  2151.     /* A - bottom point */
  2152.     points[7].x = points[0].x;
  2153.     points[7].y = points[0].y;
  2154.  
  2155.     XDrawLines(disp, win, gc, points, 8, CoordModeOrigin);
  2156.     XFillPolygon(disp, win, gc, points, 8, Convex, CoordModeOrigin);
  2157.     XtReleaseGC(w, gc);
  2158. }
  2159.  
  2160. /*
  2161.  * We get the text-field losing-focus callback, so pass it on to
  2162.  
  2163.  * the user if they requested it.  Our losing-focus callback 
  2164.  * is just a convenience callback, so that the user doesn't
  2165.  * have to get the text-field first.  This make our integration
  2166.  * with XDesigner a little easier.
  2167.  */
  2168. static void
  2169. text_losing_focus_cb(Widget w,
  2170.              XtPointer client_data,
  2171.              XtPointer call_data)
  2172. {
  2173.     DtComboBoxWidget combo = (DtComboBoxWidget)client_data;
  2174.     DtComboBoxPart *combo_p = (DtComboBoxPart*)&(combo->combo_box);
  2175.  
  2176.     if (combo_p->losing_focus_callback)
  2177.     XtCallCallbackList((Widget)combo, combo_p->losing_focus_callback, 
  2178.                (XtPointer)call_data);
  2179. }
  2180.  
  2181. /*
  2182.  * We get the text-field activate callback, so pass it on to
  2183.  * the user if they requested it.  Our activate callback 
  2184.  * is just a convenience callback, so that the user doesn't
  2185.  * have to get the text-field first.  This make our integration
  2186.  * with XDesigner a little easier.
  2187.  */
  2188. static void
  2189. text_activate_cb(Widget w,
  2190.          XtPointer client_data,
  2191.          XtPointer call_data)
  2192. {
  2193.     DtComboBoxWidget combo = (DtComboBoxWidget)client_data;
  2194.  
  2195.     if (combo->combo_box.activate_callback)
  2196.     XtCallCallbackList((Widget)combo, 
  2197.                combo->combo_box.activate_callback, 
  2198.                (XtPointer)call_data);
  2199. }
  2200.  
  2201.  
  2202. /*
  2203.  * We get the text-field focus callback, so pass it on to
  2204.  * the user if they requested it.  Our focus callback 
  2205.  * is just a convenience callback, so that the user doesn't
  2206.  * have to get the text-field first.  This make our integration
  2207.  * with XDesigner a little easier.
  2208.  */
  2209. static void
  2210. text_focus_cb(Widget w,
  2211.           XtPointer client_data,
  2212.           XtPointer call_data)
  2213. {
  2214.     DtComboBoxWidget combo = (DtComboBoxWidget)client_data;
  2215.     DtComboBoxPart *combo_p = (DtComboBoxPart*)&(combo->combo_box);
  2216.  
  2217.     if (combo_p->focus_callback)
  2218.     XtCallCallbackList((Widget)combo, combo_p->focus_callback, 
  2219.                (XtPointer)call_data);
  2220. }
  2221.  
  2222. /*
  2223.  * Try and keep our list related rsources in sync with the list widget.
  2224.  * This is not always possible, depending on if the programmer makes
  2225.  * list widget calls directly.  If we get out of sync with the
  2226.  * list widget, our SetValues() may not work correctly (when the
  2227.  * comparisons are done).  Should do get values in case list widget
  2228.  * names are changed?
  2229.  */
  2230. static void
  2231. SyncWithList(DtComboBoxPart *combo_p)
  2232. {
  2233.     XmListWidget list = (XmListWidget)combo_p->list;
  2234.  
  2235.     combo_p->items = list->list.items;
  2236.     combo_p->item_count = list->list.itemCount;
  2237.     combo_p->list_font_list = list->list.font;
  2238.     combo_p->list_margin_height = list->list.margin_height;
  2239.     combo_p->list_margin_width = list->list.margin_width;
  2240.     combo_p->list_spacing = list->list.ItemSpacing;
  2241.     combo_p->top_item_position = list->list.top_position;
  2242.     combo_p->visible_item_count = list->list.visibleItemCount;
  2243.     /* selected position must be into the items */
  2244.     if (!(combo_p->selected_position < combo_p->item_count))
  2245.         combo_p->selected_position = 0;
  2246. }
  2247.  
  2248. /*
  2249.  * Routines which manipulate the ComboBox list.  These are external
  2250.  * for use by users of our widget.
  2251.  */
  2252. Widget 
  2253. DtCreateComboBox(Widget parent,
  2254.          char *name,
  2255.          Arg *arglist,
  2256.          int num_args)
  2257. {
  2258.     return(XtCreateWidget(name, dtComboBoxWidgetClass, parent,
  2259.               arglist, num_args));
  2260. }
  2261.  
  2262. void
  2263. DtComboBoxAddItem(Widget combo_w,
  2264.           XmString item,
  2265.           int pos,
  2266.           Boolean unique)
  2267. {
  2268.     DtComboBoxWidget combo = (DtComboBoxWidget)combo_w;
  2269.     DtComboBoxPart *combo_p = (DtComboBoxPart*)&(combo->combo_box);
  2270.     XmStringTable list_items = ((XmListWidget)combo_p->list)->list.items;
  2271.     int i;
  2272.  
  2273.     if (item && ((XmListWidget)combo_p->list)->list.itemCount) {
  2274.     for (i = 0; i < combo_p->item_count; i++)
  2275.         if (XmStringCompare(item, list_items[i]))
  2276.         break;
  2277.     if ((i < combo_p->item_count) && unique)
  2278.         return;
  2279.     }
  2280.  
  2281.     XmListAddItem(combo_p->list, item, pos);
  2282.     SyncWithList(combo_p);
  2283.  
  2284.     if (combo_p->label) {
  2285.     SetMaximumLabelSize(combo_p);
  2286.     if (combo_p->type == XmDROP_DOWN_LIST_BOX) {
  2287.         ClearShadow(combo, TRUE);
  2288.         if (combo_p->recompute_size)
  2289.         SetComboBoxSize(combo);
  2290.         LayoutChildren(combo);
  2291.         DrawShadow(combo);
  2292.     }
  2293.     }
  2294.     if (combo_p->type == XmDROP_DOWN_COMBO_BOX)
  2295.     SetTextFieldData(combo_p, NULL);
  2296.     else
  2297.     SetLabelData(combo_p, NULL, FALSE);
  2298. }
  2299.  
  2300. void
  2301. DtComboBoxAddItemSelected(Widget combo_w,
  2302.               XmString item,
  2303.               int pos,
  2304.               Boolean unique)
  2305. {
  2306.     DtComboBoxWidget combo = (DtComboBoxWidget)combo_w;
  2307.     DtComboBoxPart *combo_p = (DtComboBoxPart*)&(combo->combo_box);
  2308.     XmStringTable list_items = ((XmListWidget)combo_p->list)->list.items;
  2309.     int i;
  2310.  
  2311.     if (item && ((XmListWidget)combo_p->list)->list.itemCount) {
  2312.     for (i = 0; i < combo_p->item_count; i++)
  2313.         if (XmStringCompare(item, list_items[i]))
  2314.         break;
  2315.     if ((i < combo_p->item_count) && unique)
  2316.         return;
  2317.     }
  2318.  
  2319.     XmListAddItem(combo_p->list, item, pos);
  2320.     XmListSelectPos(combo_p->list, pos, False);
  2321.     SyncWithList(combo_p);
  2322.  
  2323.     if (combo_p->label) {
  2324.     SetMaximumLabelSize(combo_p);
  2325.     if (combo_p->type == XmDROP_DOWN_LIST_BOX) {
  2326.         ClearShadow(combo, TRUE);
  2327.         if (combo_p->recompute_size)
  2328.         SetComboBoxSize(combo);
  2329.         LayoutChildren(combo);
  2330.         DrawShadow(combo);
  2331.     }
  2332.     }
  2333.     if (combo_p->type == XmDROP_DOWN_COMBO_BOX)
  2334.     SetTextFieldData(combo_p, NULL);
  2335.     else
  2336.     SetLabelData(combo_p, NULL, FALSE);
  2337. }
  2338.  
  2339.  
  2340. void
  2341. DtComboBoxDeleteAllItems(Widget combo_w)
  2342. {
  2343.   DtComboBoxWidget combo = (DtComboBoxWidget)combo_w;
  2344.   DtComboBoxPart *combo_p = (DtComboBoxPart*)&(combo->combo_box);
  2345.  
  2346.   XmListDeleteAllItems(combo_p->list);
  2347.   SyncWithList(combo_p);
  2348.   
  2349.   if (combo_p->label) {
  2350.     SetMaximumLabelSize(combo_p);
  2351.     if (combo_p->type == XmDROP_DOWN_LIST_BOX) {
  2352.       ClearShadow(combo, TRUE);
  2353.       if (combo_p->recompute_size)
  2354.     SetComboBoxSize(combo);
  2355.       LayoutChildren(combo);
  2356.       DrawShadow(combo);
  2357.     }
  2358.   }
  2359.   if (combo_p->type == XmDROP_DOWN_COMBO_BOX)
  2360.     SetTextFieldData(combo_p, NULL);
  2361.   else
  2362.     SetLabelData(combo_p, NULL, FALSE);
  2363. }
  2364.  
  2365.  
  2366. void
  2367. DtComboBoxDeletePos(Widget combo_w,
  2368.             int pos)
  2369. {
  2370.     DtComboBoxWidget combo = (DtComboBoxWidget)combo_w;
  2371.     DtComboBoxPart *combo_p = (DtComboBoxPart*)&(combo->combo_box);
  2372.  
  2373.     XmListDeletePos(combo_p->list, pos);
  2374.     SyncWithList(combo_p);
  2375.  
  2376.     if (combo_p->label) {
  2377.     SetMaximumLabelSize(combo_p);
  2378.     if (combo_p->type == XmDROP_DOWN_LIST_BOX) {
  2379.         ClearShadow(combo, TRUE);
  2380.         if (combo_p->recompute_size)
  2381.         SetComboBoxSize(combo);
  2382.         LayoutChildren(combo);
  2383.         DrawShadow(combo);
  2384.     }
  2385.     }
  2386.     if (combo_p->type == XmDROP_DOWN_COMBO_BOX)
  2387.     SetTextFieldData(combo_p, NULL);
  2388.     else
  2389.     SetLabelData(combo_p, NULL, FALSE);
  2390. }
  2391.  
  2392. void
  2393. DtComboBoxSetItem(Widget combo_w,
  2394.           XmString item)
  2395. {
  2396.     DtComboBoxWidget combo = (DtComboBoxWidget)combo_w;
  2397.     DtComboBoxPart *combo_p = (DtComboBoxPart*)&(combo->combo_box);
  2398.     XmStringTable list_items = ((XmListWidget)combo_p->list)->list.items;
  2399.     int i;
  2400.  
  2401.     if (item && ((XmListWidget)combo_p->list)->list.itemCount) {
  2402.     for (i = 0; i < combo_p->item_count; i++)
  2403.         if (XmStringCompare(item, list_items[i]))
  2404.         break;
  2405.     if (i < combo_p->item_count) {
  2406.         combo_p->selected_position = i;
  2407.         if (combo_p->type == XmDROP_DOWN_COMBO_BOX)
  2408.         SetTextFieldData(combo_p, NULL);
  2409.         else
  2410.         SetLabelData(combo_p, NULL, FALSE);
  2411.         XmListSetItem(combo_p->list, item);
  2412.         SyncWithList(combo_p);
  2413.     }
  2414.     else
  2415.         XtWarning(COMBO_SET_ITEM);
  2416.     }
  2417.     else
  2418.     XtWarning(COMBO_SET_ITEM);
  2419. }
  2420.  
  2421. void
  2422. DtComboBoxSelectItem(Widget combo_w,
  2423.              XmString item)
  2424. {
  2425.     DtComboBoxWidget combo = (DtComboBoxWidget)combo_w;
  2426.     DtComboBoxPart *combo_p = (DtComboBoxPart*)&(combo->combo_box);
  2427.     XmStringTable list_items = ((XmListWidget)combo_p->list)->list.items;
  2428.     int i;
  2429.  
  2430.     if (item && ((XmListWidget)combo_p->list)->list.itemCount) {
  2431.     for (i = 0; i < combo_p->item_count; i++)
  2432.         if (XmStringCompare(item, list_items[i]))
  2433.         break;
  2434.     if (i < combo_p->item_count) {
  2435.         combo_p->selected_position = i;
  2436.         if (combo_p->type == XmDROP_DOWN_COMBO_BOX)
  2437.         SetTextFieldData(combo_p, NULL);
  2438.         else
  2439.         SetLabelData(combo_p, NULL, FALSE);
  2440.         XmListDeselectAllItems(combo_p->list);
  2441.         XmListSelectItem(combo_p->list, item, FALSE);
  2442.         SyncWithList(combo_p);
  2443.     }
  2444.     else
  2445.         XtWarning(COMBO_SELECT_ITEM);
  2446.     }
  2447.     else
  2448.     XtWarning(COMBO_SELECT_ITEM);
  2449. }
  2450.  
  2451. void
  2452. DtComboBoxSelectItemMoveup(DtComboBoxWidget combo,
  2453.                XmString item)
  2454. {
  2455.     DtComboBoxPart *combo_p = (DtComboBoxPart*)&(combo->combo_box);
  2456.     XmStringTable list_items = ((XmListWidget)combo_p->list)->list.items;
  2457.     int i;
  2458.  
  2459.     if (item && ((XmListWidget)combo_p->list)->list.itemCount) {
  2460.         for (i = 0; i < combo_p->item_count; i++)
  2461.             if (XmStringCompare(item, list_items[i]))
  2462.                 break;
  2463.         if (i < combo_p->item_count) {
  2464.             combo_p->selected_position = i;
  2465.             if (combo_p->type == XmDROP_DOWN_COMBO_BOX)
  2466.                 SetTextFieldData(combo_p, NULL);
  2467.             else
  2468.                 SetLabelData(combo_p, NULL, FALSE);
  2469.             XmListDeselectAllItems(combo_p->list);
  2470.         XmListAddItem(combo_p->list, item, 1);
  2471.             XmListSelectItem(combo_p->list, item, FALSE);
  2472.         XmListDeletePos(combo_p->list, combo_p->selected_position+2);
  2473.         combo_p->selected_position = 0;
  2474.         XmListSetPos(combo_p->list, 1);
  2475.             SyncWithList(combo_p);
  2476.         }
  2477.         else
  2478.             XtWarning(COMBO_SELECT_ITEM);
  2479.     }
  2480.     else
  2481.         XtWarning(COMBO_SELECT_ITEM);
  2482. }
  2483.  
  2484.  
  2485. /*
  2486.  * Synthetic GetValues for List resources.
  2487.  */
  2488.  
  2489. static XmImportOperator
  2490. _XmSetSyntheticResForChild(Widget widget,
  2491.                int offset,
  2492.                XtArgVal *value)
  2493.     return(XmSYNTHETIC_LOAD);
  2494. }
  2495.  
  2496. void
  2497. _DtComboBoxGetArrowSize(Widget w,
  2498.             int resource_offset,
  2499.             XtArgVal *value)
  2500. {
  2501.     DtComboBoxWidget combo = (DtComboBoxWidget)w;
  2502.  
  2503.     *value = (XtArgVal)combo->combo_box.arrow->core.height;
  2504. }
  2505.  
  2506. void
  2507. _DtComboBoxGetLabelString(Widget w,
  2508.               int resource_offset,
  2509.               XtArgVal *value)
  2510. {
  2511.     DtComboBoxWidget combo = (DtComboBoxWidget)w;
  2512.  
  2513.     if (combo->combo_box.label_string)
  2514.     *value = (XtArgVal)XmStringCopy(combo->combo_box.label_string);
  2515.     else
  2516.     *value = (XtArgVal)NULL;
  2517. }
  2518.  
  2519. void
  2520. _DtComboBoxGetListItemCount(Widget w,
  2521.                 int resource_offset,
  2522.                 XtArgVal *value)
  2523. {
  2524.     DtComboBoxWidget combo = (DtComboBoxWidget)w;
  2525.     int data;
  2526.     Arg arg;
  2527.  
  2528.     XtSetArg(arg, XmNitemCount, &data);
  2529.     XtGetValues(combo->combo_box.list, &arg, 1);
  2530.     *value = (XtArgVal)data;
  2531. }
  2532.  
  2533. void
  2534. _DtComboBoxGetListItems(Widget w, 
  2535.             int resource_offset,
  2536.             XtArgVal *value)
  2537. {
  2538.     DtComboBoxWidget combo = (DtComboBoxWidget)w;
  2539.     XmStringTable data;
  2540.     Arg arg;
  2541.  
  2542.     XtSetArg(arg, XmNitems, &data);
  2543.     XtGetValues(combo->combo_box.list, &arg, 1);
  2544.     *value = (XtArgVal)data;
  2545. }
  2546.  
  2547. void
  2548. _DtComboBoxGetListFontList(Widget w,
  2549.                int resource_offset,
  2550.                XtArgVal *value)
  2551. {
  2552.     DtComboBoxWidget combo = (DtComboBoxWidget)w;
  2553.     XmFontList data;
  2554.     Arg arg;
  2555.  
  2556.     XtSetArg(arg, XmNfontList, &data);
  2557.     XtGetValues(combo->combo_box.list, &arg, 1);
  2558.     *value = (XtArgVal)data;
  2559. }
  2560.  
  2561. void
  2562. _DtComboBoxGetListMarginHeight(Widget w,
  2563.                    int resource_offset,
  2564.                    XtArgVal *value)
  2565. {
  2566.     DtComboBoxWidget combo = (DtComboBoxWidget)w;
  2567.     Dimension data;
  2568.     Arg arg;
  2569.  
  2570.     XtSetArg(arg, XmNmarginHeight, &data);
  2571.     XtGetValues(combo->combo_box.list, &arg, 1);
  2572.     *value = (XtArgVal)data;
  2573. }
  2574.  
  2575. void
  2576. _DtComboBoxGetListMarginWidth(Widget w,
  2577.                   int resource_offset,
  2578.                   XtArgVal *value)
  2579. {
  2580.     DtComboBoxWidget combo = (DtComboBoxWidget)w;
  2581.     Dimension data;
  2582.     Arg arg;
  2583.  
  2584.     XtSetArg(arg, XmNmarginWidth, &data);
  2585.     XtGetValues(combo->combo_box.list, &arg, 1);
  2586.     *value = (XtArgVal)data;
  2587. }
  2588.  
  2589. void
  2590. _DtComboBoxGetListSpacing(Widget w,
  2591.               int resource_offset,
  2592.               XtArgVal *value)
  2593. {
  2594.     DtComboBoxWidget combo = (DtComboBoxWidget)w;
  2595.     Dimension data;
  2596.     Arg arg;
  2597.  
  2598.     XtSetArg(arg, XmNspacing, &data);
  2599.     XtGetValues(combo->combo_box.list, &arg, 1);
  2600.     *value = (XtArgVal)data;
  2601. }
  2602.  
  2603. void
  2604. _DtComboBoxGetListTopItemPosition(Widget w,
  2605.                   int resource_offset,
  2606.                   XtArgVal *value)
  2607. {
  2608.     DtComboBoxWidget combo = (DtComboBoxWidget)w;
  2609.     int data;
  2610.     Arg arg;
  2611.  
  2612.     XtSetArg(arg, XmNtopItemPosition, &data);
  2613.     XtGetValues(combo->combo_box.list, &arg, 1);
  2614.     *value = (XtArgVal)data;
  2615. }
  2616.  
  2617. void
  2618. _DtComboBoxGetListVisibleItemCount(Widget w,
  2619.                    int resource_offset,
  2620.                    XtArgVal *value)
  2621. {
  2622.     DtComboBoxWidget combo = (DtComboBoxWidget)w;
  2623.     int data;
  2624.     Arg arg;
  2625.  
  2626.     XtSetArg(arg, XmNvisibleItemCount, &data);
  2627.     XtGetValues(combo->combo_box.list, &arg, 1);
  2628.     *value = (XtArgVal)data;
  2629. }
  2630.