#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#if defined(VMS) && !defined(__alpha)
#define mbstowcs(a,b,n) XiMbstowcs(a,b,n)
#endif
#include <Xm/Xm.h>
#include <Xm/XmP.h>
#include "XmI.h"
#include <Xm/VaSimpleP.h>
#include <Xm/DrawP.h>
#include <Xm/DropDownP.h>
#include <X11/Shell.h>
#include <Xm/ArrowB.h>
#include <Xm/Label.h>
#include <Xm/TextF.h>
#include <Xm/Text.h>
#include <Xm/List.h>
#include <Xm/GrabShellP.h>
#include <Xm/ExtP.h>
#define FIX_1371
#define FIX_1486
#define FIX_1170
#ifdef FIX_1486
#include "MenuShellI.h"
#endif
/*
* NOTE: I use the same syntax for popup and popdown that Xt Uses.
* so something is "up" if it is on the screen. With combo
* boxes this can often be backwards of how the user thinks,
* but it is all internal stuff anyway.
* Note: most uses are now unposted (up) (doesn't appear) and posted (down)
* (does appear)
*/
#ifndef XmNautoTraversal
#define XmNautoTraversal "autoTraversal"
#define XmCAutoTraversal "AutoTraversal"
#endif
#ifndef XmNactivateOnFill
#define XmNactivateOnFill "activateOnFill"
#define XmCActivateOnFill "ActivateOnFill"
#endif
#define XmTextFieldGetString(t) \
( XmIsTextField(t) ? XmTextFieldGetString(t) : XmTextGetString(t) )
#define XmTextFieldSetString(t,s) \
( XmIsTextField(t) ? XmTextFieldSetString(t,s) : XmTextSetString(t,s) )
#define XmTextFieldInsert(t,l,p) \
( XmIsTextField(t) ? XmTextFieldInsert(t,l,p) : XmTextInsert(t,l,p) )
#define XmTextFieldSetInsertionPosition(t,p) \
( XmIsTextField(t) ? XmTextFieldSetInsertionPosition(t,p) \
: XmTextSetInsertionPosition(t,p) )
/* From GrabShell.c */
#define Events (EnterWindowMask | LeaveWindowMask | ButtonPressMask | \
ButtonReleaseMask)
static void TextButtonPress(Widget, XtPointer, XEvent *, Boolean *);
static char combo_translations[] =
"#override \n\
Ctrl <Key>osfDown: XiComboListPost()\n\
Ctrl <Key>osfUp: XiComboListUnpost()\n\
Any <Key>osfCancel: XiComboListCancel()";
static void Resize(Widget), ChangeManaged(Widget), Destroy(Widget);
static void Initialize(Widget, Widget, ArgList, Cardinal *);
static void GetValuesHook(Widget, ArgList, Cardinal *);
static Boolean SetValues(Widget, Widget, Widget, ArgList, Cardinal *);
static XtGeometryResult GeometryManager(Widget,
XtWidgetGeometry*, XtWidgetGeometry*);
static XtGeometryResult QueryGeometry(Widget,
XtWidgetGeometry *, XtWidgetGeometry *);
static void ClassPartInitialize(WidgetClass);
static void ClassInitialize();
static void ExposeMethod(Widget, XEvent*, Region);
static Boolean ComboBoxParentProcess(Widget wid, XmParentProcessData event);
/************************
* Actions and callbacks.
************************/
static void VerifyTextField(Widget, XtPointer, XtPointer);
static void ModifyVerifyTextField(Widget, XtPointer, XtPointer);
static void ValueChangedTextField(Widget, XtPointer, XtPointer);
static void ListSelected(Widget, XtPointer, XtPointer);
static void ComboUnpost(Widget, XEvent *, String *, Cardinal *);
static void ComboPost(Widget, XEvent *, String *, Cardinal *);
static void ComboCancel(Widget, XEvent *, String *, Cardinal *);
static void SBBtnDownEH (Widget, XtPointer, XEvent *, Boolean *);
static void SBBtnUpEH (Widget, XtPointer, XEvent *, Boolean *);
/*********************
* Internal Routines.
*********************/
static XmDropDownWidget FindComboBox(Widget);
static void PopdownList(Widget);
static void LoseFocusHandler(Widget, XtPointer, XEvent *, Boolean *);
static void RegisterShellHandler(Widget);
static void CreateChildren(Widget, ArgList, Cardinal);
static void CreatePopup(Widget, ArgList, Cardinal);
static void PlaceChildren(Widget, Boolean, Widget);
static void FindDesiredSize(Widget, Widget, Dimension *, Dimension *,
XtWidgetGeometry *, XtWidgetGeometry *, XtWidgetGeometry *);
static void GetTextAndLabelWidth(Widget, Dimension, Dimension, Dimension,
Dimension, Dimension *, Dimension *);
static Boolean SetListFromText(Widget, Boolean), SetTextFromList(Widget);
static Boolean PopupList(Widget);
/************************************************************
* STATIC DECLARATIONS
*************************************************************/
static XtActionsRec actions[] =
{
{ "XiComboListDown", ComboPost },
{ "XiComboListPost", ComboPost },
{ "XiComboListUp", ComboUnpost },
{ "XiComboListUnpost", ComboUnpost },
{ "XiComboListCancel", ComboCancel },
};
static XtResource resources[] =
{
{
XmNhorizontalMargin, XmCMargin, XmRHorizontalDimension,
sizeof(Dimension), XtOffsetOf(XmDropDownRec, combo.h_space),
XmRImmediate, (XtPointer) 2
},
{
XmNverticalMargin, XmCMargin, XmRVerticalDimension,
sizeof(Dimension), XtOffsetOf(XmDropDownRec, combo.v_space),
XmRImmediate, (XtPointer) 2
},
{
XmNverify, XmCVerify, XmRBoolean,
sizeof(Boolean), XtOffsetOf(XmDropDownRec, combo.verify),
XmRImmediate, (XtPointer) True
},
{
XmNeditable, XmCEditable, XmRBoolean,
sizeof(Boolean), XtOffsetOf(XmDropDownRec, combo.editable),
XmRImmediate, (XtPointer) True
},
{
XmNcustomizedCombinationBox, XmCBoolean, XmRBoolean,
sizeof(Boolean), XtOffsetOf(XmDropDownRec, combo.customized_combo_box),
XmRImmediate, (XtPointer) False
},
{
XmNverifyTextCallback, XmCCallback, XmRCallback,
sizeof(XtCallbackList), XtOffsetOf(XmDropDownRec, combo.verify_text_callback),
XmRImmediate, (XtPointer) NULL
},
{
XmNupdateTextCallback, XmCCallback, XmRCallback,
sizeof(XtCallbackList), XtOffsetOf(XmDropDownRec, combo.update_text_callback),
XmRImmediate, (XtPointer) NULL
},
{
XmNupdateShellCallback, XmCCallback, XmRCallback,
sizeof(XtCallbackList), XtOffsetOf(XmDropDownRec, combo.update_shell_callback),
XmRImmediate, (XtPointer) NULL
},
{
XmNpopupShellWidget, XmCWidget, XmRWidget,
sizeof(Widget), XtOffsetOf(XmDropDownRec, combo.popup_shell),
XmRImmediate, (XtPointer) NULL
},
{
XmNshowLabel, XmCBoolean, XmRBoolean,
sizeof(Boolean), XtOffsetOf(XmDropDownRec, combo.show_label),
XmRImmediate, (XtPointer) True
},
{
XmNpopupOffset, XmCPopupOffset, XmRInt,
sizeof(int), XtOffsetOf(XmDropDownRec, combo.popup_offset),
XmRImmediate, (XtPointer) 15
},
{
XmNpopupCursor, XmCCursor, XmRCursor,
sizeof(Cursor), XtOffsetOf(XmDropDownRec, combo.popup_cursor),
XmRString, (XtPointer) "left_ptr"
},
{
XmNuseTextField, XmCUseTextField, XmRBoolean,
sizeof(Boolean), XtOffsetOf(XmDropDownRec, combo.use_text_field),
XmRImmediate, (XtPointer) True
},
{
XmNcomboTranslations, XmCTranslations, XmRTranslationTable,
sizeof(XtTranslations), XtOffsetOf(XmDropDownRec, combo.translations),
XmRString, (XtPointer) combo_translations
},
{
XmNvisibleItemCount, XmCVisibleItemCount, XmRInt,
sizeof(int), XtOffsetOf(XmDropDownRec, combo.visible_items),
XmRImmediate, (XtPointer) 5
},
{
XmNnewVisualStyle, XmCNewVisualStyle, XmRBoolean,
sizeof(Boolean), XtOffsetOf(XmDropDownRec, combo.new_visual_style),
XmRImmediate, (XtPointer)True
},
{
XmNshadowThickness, XmCShadowThickness, XmRHorizontalDimension,
sizeof (Dimension), XtOffsetOf(XmManagerRec, manager.shadow_thickness),
XmRImmediate, (XtPointer) 2
},
/* intentionally undocumented feature used by other ICS widgets */
{
XmNverifyTextFailedCallback, XmCCallback, XmRCallback,
sizeof(XtCallbackList), XtOffsetOf(XmDropDownRec, combo.verify_text_failed_callback),
XmRImmediate, (XtPointer) NULL
},
#ifdef XmNautoTraversal
{
XmNautoTraversal, XmCAutoTraversal, XmRBoolean,
sizeof(Boolean), XtOffsetOf(XmDropDownRec, combo.autoTraversal),
XmRImmediate, (XtPointer) True
},
#endif
#ifdef XmNactivateOnFill
{
XmNactivateOnFill, XmCActivateOnFill, XmRInt,
sizeof(int), XtOffsetOf(XmDropDownRec, combo.activateOnFill),
XmRImmediate, (XtPointer) 0
},
#endif
};
static XmSyntheticResource get_resources[] =
{
{
XmNhorizontalMargin, sizeof(Dimension),
XtOffsetOf(XmDropDownRec, combo.h_space),
XmeFromHorizontalPixels, (XmImportProc) XmeToHorizontalPixels
},
{
XmNverticalMargin, sizeof(Dimension),
XtOffsetOf(XmDropDownRec, combo.v_space),
XmeFromVerticalPixels, (XmImportProc) XmeToVerticalPixels
},
};
#undef offset
XmDropDownClassRec xmDropDownClassRec = {
{ /* core fields */
/* superclass */ (WidgetClass)&xmManagerClassRec,
/* class_name */ "XmDropDown",
/* widget_size */ sizeof(XmDropDownRec),
/* class_initialize */ ClassInitialize,
/* class_part_initialize */ ClassPartInitialize,
/* class_inited */ FALSE,
/* initialize */ Initialize,
/* initialize_hook */ NULL,
/* realize */ XtInheritRealize,
/* actions */ actions,
/* num_actions */ XtNumber(actions),
/* resources */ (XtResource*)resources,
/* num_resources */ XtNumber(resources),
/* xrm_class */ NULLQUARK,
/* compress_motion */ TRUE,
/* compress_exposure */ TRUE,
/* compress_enterleave */ TRUE,
/* visible_interest */ FALSE,
/* destroy */ Destroy,
/* resize */ Resize,
/* expose */ ExposeMethod,
/* set_values */ SetValues,
/* set_values_hook */ NULL,
/* set_values_almost */ XtInheritSetValuesAlmost,
/* get_values_hook */ GetValuesHook,
/* accept_focus */ NULL,
/* version */ XtVersion,
/* callback_private */ NULL,
/* tm_table */ XtInheritTranslations,
/* query_geometry */ (XtGeometryHandler) QueryGeometry,
/* display_accelerator */ XtInheritDisplayAccelerator,
/* extension */ NULL
},
{ /* composite_class fields */
/* geometry_manager */ GeometryManager,
/* change_managed */ ChangeManaged,
/* insert_child */ XtInheritInsertChild,
/* delete_child */ XtInheritDeleteChild,
/* extension */ NULL,
},
{ /* constraint_class fields */
/* resource list */ NULL,
/* num resources */ 0,
/* constraint size */ 0,
/* destroy proc */ NULL,
/* init proc */ NULL,
/* set values proc */ NULL,
/* extension */ NULL,
},
{ /* manager_class fields */
/* default translations */ XtInheritTranslations,
/* syn_resources */ get_resources,
/* num_syn_resources */ XtNumber(get_resources),
/* syn_cont_resources */ NULL,
/* num_syn_cont_resources */ 0,
/* parent_process */ XmInheritParentProcess,
/* extension */ NULL,
},
{ /* Combination Box fields */
NULL /* extension */
}
};
WidgetClass xmDropDownWidgetClass = (WidgetClass)&xmDropDownClassRec;
/************************************************************
* STATIC CODE
*************************************************************/
#if defined(VAX) && defined(VMS)
static char * OsiStrncpy( char *s1, char *s2, int len );
static size_t
XiMbstowcs(wchar_t* wcs, char* mbs, size_t n)
{
if (wcs)
{
memset((char*)wcs, 0, n);
OsiStrncpy((char*)wcs, mbs, n);
return((size_t) strlen((char*) wcs));
}
else
{
return (0);
}
}
/* Function:
* OsiStrncpy(s1, s2, len)
* Description:
* strncpy() with check for NULL strings
* Input:
* s1 - char * : copy to here
* s2 - char * : copy from here
* len - int : bytes to copy
*
* Output:
* s1
*/
static char *
OsiStrncpy( char *s1, char *s2, int len )
{
if (s2 == NULL) s2 = "";
if (s1 == NULL) return(NULL);
return(strncpy(s1,s2,len));
}
#endif
/* Function Name: ClassInitialize
* Description: class_initialize method for XmDropDown
* Arguments: none
* Returns: nothing
*/
static void
ClassInitialize()
{
/* do nothing */
}
/* Function Name: ClassPartInitialize
* Description: class_part_initialize method for XmDropDown
* Arguments: w_class - the widget class.
* Returns: nothing
*/
/*ARGSUSED*/
static void
ClassPartInitialize(WidgetClass w_class)
{
_XmFastSubclassInit (w_class, XmDROP_DOWN_BIT);
}
/* Function Name: Initialize
* Description: Called to initialize information specific
* to this widget.
* Arguments: req - what was originally requested.
* set - what will be created (our superclassed have
* already mucked with this)
* args, num_args - The arguments passed to
* the creation call.
* Returns: none.
*/
/*ARGSUSED*/
static void
Initialize(Widget req, Widget set, ArgList args, Cardinal * num_args)
{
XmDropDownWidget cbw = (XmDropDownWidget) set;
ArgList f_args;
Cardinal f_num_args;
Dimension desired_height, desired_width;
XmDropDown_list_state(cbw) = XmDropDown_POSTED;
XmDropDown_old_text(cbw) = NULL;
XmDropDown_doActivate(cbw) = False;
XmDropDown_inValueChanged(cbw) = False;
cbw->combo.hsb = NULL;
cbw->combo.vsb = NULL;
_XmFilterArgs(args, *num_args, xm_std_filter, &f_args, &f_num_args);
CreateChildren(set, f_args, f_num_args);
if (!XmDropDown_customized_combo_box(cbw))
CreatePopup(set, f_args, f_num_args);
RegisterShellHandler(set);
if (!XmDropDown_editable(cbw)) {
VerifyTextField(NULL, (XtPointer) cbw, (XtPointer) NULL);
XtAddEventHandler(XmDropDown_text(cbw), ButtonPressMask,
False, TextButtonPress, NULL);
}
/*
* Override the bad things that XmManager is doing to me.
*/
if ((req->core.height == 0) || (req->core.width == 0))
{
XtWidgetGeometry arrow_geom, text_geom, label_geom;
FindDesiredSize(set, NULL, &desired_width, &desired_height,
&label_geom, &text_geom, &arrow_geom);
}
if (req->core.height == 0)
set->core.height = desired_height;
else set->core.height = req->core.height;
if (req->core.width == 0)
set->core.width = desired_width;
else set->core.width = req->core.width;
XtFree((char *) f_args);
}
/* Function Name: Resize
* Description: Called when this widget has been resized.
* Arguments: w - Extended List Widget to realize.
* Returns: none.
*/
static void
Resize(Widget w)
{
if (XtIsRealized(w)) XClearWindow(XtDisplay(w), XtWindow(w));
PlaceChildren(w, False, NULL);
}
/*ARGSUSED*/
static void
GetValuesHook(Widget w, ArgList args, Cardinal *num_args)
{
XmDropDownWidget cbw = (XmDropDownWidget) w;
XrmQuark visible_quark;
int i;
visible_quark = XrmStringToQuark(XmNvisibleItemCount);
for (i = 0; i < ((int) *num_args); i++)
{
if (visible_quark == XrmStringToQuark(args[i].name))
{
XtVaGetValues(XmDropDown_list(cbw), args[i].name, args[i].value, NULL);
break;
}
}
}
/* Function Name: SetValues
* Description: Called when some widget data needs to be modified on-
* the-fly.
* Arguments: current - the current (old) widget values.
* request - before superclassed have changed things.
* set - what will acutally be the new values.
* args, num_args - the arguments in the list.
* Returns: none
*/
/*ARGSUSED*/
static Boolean
SetValues(Widget current, Widget request, Widget set,
ArgList args, Cardinal * num_args)
{
Boolean place_children = False;
XmDropDownWidget old_cbw = (XmDropDownWidget) current,
set_cbw = (XmDropDownWidget) set;
ArgList f_args;
Cardinal f_num_args;
Boolean retval = False;
/*
* Pass filtered setvalues requests down to children.
*/
_XmFilterArgs(args, *num_args, xm_std_filter, &f_args, &f_num_args);
if( !XmDropDown_customized_combo_box(set_cbw) )
{
/*
* It is possible that the new combo box does not have a list
* associated with it because if the old value for the
* resource "XmNcustomizedCombinationBox" is True. If this is
* the case then we need to build a popup list for the new
* combo box.
*/
if( XmDropDown_customized_combo_box(old_cbw) &&
!XmDropDown_popup_shell(set_cbw) )
{
/*
* It turns out that we need to create a new popup list
* for this widget so lets go ahead and do it.
*/
CreatePopup (set, f_args, f_num_args);
}
XtSetValues(XmDropDown_list(set_cbw), f_args, f_num_args);
}
/* make it Create/Get only */
if( XmDropDown_use_text_field(set_cbw) != XmDropDown_use_text_field(old_cbw) )
XmDropDown_use_text_field(set_cbw) = XmDropDown_use_text_field(old_cbw);
_XmSetValuesOnChildren(set, f_args, f_num_args);
if (XmDropDown_editable(set_cbw) != XmDropDown_editable(old_cbw)){
if (!XmDropDown_editable(set_cbw))
XtAddEventHandler(XmDropDown_text(set_cbw), ButtonPressMask, False,
TextButtonPress, NULL);
else
XtRemoveEventHandler(XmDropDown_text(set_cbw), ButtonPressMask, False,
TextButtonPress, NULL);
}
if ((XmDropDown_h_space(set_cbw) != XmDropDown_h_space(old_cbw)) ||
(XmDropDown_v_space(set_cbw) != XmDropDown_v_space(old_cbw)))
{
place_children = True;
}
if (XmDropDown_popup_shell(set_cbw) != XmDropDown_popup_shell(old_cbw)) {
if (!XmDropDown_customized_combo_box(old_cbw)) {
/*
* Non custom box, I created it, so I should destroy it.
*/
XtDestroyWidget(XmDropDown_popup_shell(old_cbw));
}
RegisterShellHandler(set);
}
/* note! the following causes a size change in the XmDropDown. It
** could be possible to redefine the visuals so that this isn't the case,
** though. As is, the effect is that the widget changes size when the
** resource changes. By itself, this isn't a problem -- it changes back
** when the resource is flipped the other way. But when used with a
** manager widget whose geometry management is the equivalent of
** XmRESIZE_GROW, the XmDropDown will not shrink back down in size.
*/
if (XmDropDown_new_visual_style(set_cbw) != XmDropDown_new_visual_style(old_cbw))
{
Arg targs[4];
int tn = 0;
if(XmDropDown_new_visual_style(set_cbw))
{
/* ArrowB doesn't track this information itself; it draws
** itself minus its highlightThickness
*/
Dimension width, height;
tn = 0;
XtSetArg(targs[tn], XmNwidth, &width); tn++;
XtSetArg(targs[tn], XmNheight, &height); tn++;
XtGetValues(XmDropDown_arrow(set_cbw),targs,tn);
tn = 0;
XtSetArg(targs[tn], XmNwidth, width - 4); tn++;
XtSetArg(targs[tn], XmNheight, height - 4); tn++;
XtSetArg(targs[tn], XmNhighlightThickness, 0); tn++;
XtSetValues(XmDropDown_arrow(set_cbw),targs,tn);
tn = 0;
XtSetArg(targs[tn], XmNhighlightThickness, 0); tn++;
XtSetArg(targs[tn], XmNshadowThickness, 0); tn++;
XtSetValues(XmDropDown_text(set_cbw),targs,tn);
}
else
{
Dimension width, height;
tn = 0;
XtSetArg(targs[tn], XmNwidth, &width); tn++;
XtSetArg(targs[tn], XmNheight, &height); tn++;
XtGetValues(XmDropDown_arrow(set_cbw),targs,tn);
tn = 0;
XtSetArg(targs[tn], XmNwidth, width + 4); tn++;
XtSetArg(targs[tn], XmNheight, height + 4); tn++;
XtSetArg(targs[tn], XmNhighlightThickness, 2); tn++;
XtSetValues(XmDropDown_arrow(set_cbw),targs,tn);
tn = 0;
XtSetArg(targs[tn], XmNhighlightThickness, 2); tn++;
XtSetArg(targs[tn], XmNshadowThickness, 2); tn++;
XtSetValues(XmDropDown_text(set_cbw),targs,tn);
}
retval = True; /* for shadows */
}
if (XmDropDown_show_label(set_cbw) != XmDropDown_show_label(old_cbw))
{
retval = True;
if (XmDropDown_show_label(old_cbw))
{
XtUnmanageChild(XmDropDown_label(old_cbw));
}
else
{
XtManageChild(XmDropDown_label(set_cbw));
}
}
XtFree((char *) f_args);
#ifdef FIX_1170
if (XtIsSensitive((Widget)set_cbw) != XtIsSensitive((Widget)old_cbw))
{
retval = True;
}
#endif
if (place_children)
{
/* figure out the new geometry needed */
XtWidgetGeometry arrow_geom, text_geom, label_geom;
FindDesiredSize(set, NULL, &(set->core.width), &(set->core.height),
&label_geom, &text_geom, &arrow_geom);
}
/* Fix for CR03893, not resizing once the */
/* label width is modified */
Resize((Widget)set_cbw);
return(retval);
}
/* Function Name: QueryGeometry
* Description: Called when my parent wants to know what size
* I would like to be.
* Arguments: w - the widget to check.
* indended - constriants imposed by the parent.
* preferred - what I would like.
* Returns: See Xt Manual.
*/
static XtGeometryResult
QueryGeometry(Widget w,XtWidgetGeometry *intended, XtWidgetGeometry *preferred)
{
XtWidgetGeometry arrow_geom, text_geom, label_geom;
FindDesiredSize(w, NULL, &(preferred->width), &(preferred->height),
&label_geom, &text_geom, &arrow_geom);
return(_XmHWQuery(w, intended, preferred));
}
/* Function Name: Destroy
* Description: Called when the widget dies.
* Arguments: w - the widget.
* Returns: none.
*/
static void
Destroy(Widget w)
{
XmDropDownWidget cbw = (XmDropDownWidget) w;
XtFree((char *) XmDropDown_old_text(cbw));
}
/************************************************************
*
* Semi - Public Routines for child management.
*
************************************************************/
/* Function Name: GeometryManager
* Description: handles requests from children for a size change.
* Arguments: child - the child to change.
* request - the geometry that the child wants.
* return - what we will allow if this is an almost.
* Returns: status.
*/
/*ARGSUSED*/
static XtGeometryResult
GeometryManager(Widget w, XtWidgetGeometry * request,
XtWidgetGeometry * result)
{
XmDropDownWidget cbw = (XmDropDownWidget) XtParent(w);
Dimension c_width, c_height, old_width, old_height, r_width, r_height;
XtGeometryResult ret_val;
XtWidgetGeometry arrow_geom, text_geom, label_geom;
Boolean w_req = request->request_mode & CWWidth;
Boolean h_req = request->request_mode & CWHeight;
if (!(w_req || h_req)) return(XtGeometryNo);
old_width = w->core.width;
old_height = w->core.height;
if (w_req)
w->core.width = request->width;
if (h_req)
w->core.height = request->height;
FindDesiredSize((Widget) cbw, w, &c_width, &c_height,
&label_geom, &text_geom, &arrow_geom);
_XmRequestNewSize((Widget) cbw, True,
c_width, c_height, &r_width, &r_height);
if (c_height == r_height) {
Dimension arrow_width, text_width, label_width, tbw, lbw;
result->height = w->core.height;
if (XmDropDown_show_label(cbw)) {
label_width = label_geom.width;
lbw = label_geom.border_width;
}
else {
label_width = 0;
lbw = 0;
}
text_width = text_geom.width;
tbw = text_geom.border_width;
arrow_width = arrow_geom.width + 2 * arrow_geom.border_width;
GetTextAndLabelWidth((Widget) cbw, r_width, arrow_width, lbw, tbw,
&text_width, &label_width);
if ((text_width != 1) &&
((label_width != 1) || XmDropDown_show_label(cbw)))
{
if (w == XmDropDown_text(cbw))
result->width = text_width;
else if (w == XmDropDown_label(cbw))
result->width = label_width;
else
result->width = w->core.width;
}
else {
result->width = old_width;
}
result->request_mode = CWWidth | CWHeight;
}
if ((!h_req || (result->height == request->height)) &&
(!w_req || (result->width == request->width)))
{
if (request->request_mode & XtCWQueryOnly)
ret_val = XtGeometryYes;
else {
/* PlaceChildren((Widget) cbw, True, w); */
_XmRequestNewSize((Widget) cbw, False,
c_width, c_height, &r_width, &r_height);
return(XtGeometryYes);
}
}
else if ((!h_req || (result->height == request->height)) ||
(!w_req || (result->width == request->width)))
{
ret_val = XtGeometryAlmost;
}
else
ret_val = XtGeometryNo;
w->core.height = old_height;
w->core.width = old_width;
return(ret_val);
}
/* Function Name: ChangeManaged
* Description: When a management change has occured...
* Arguments: w - the combination box widget.
* Returns: none.
*/
static void
ChangeManaged(Widget w)
{
if(XtIsRealized(w))
PlaceChildren(w, True, NULL);
else
PlaceChildren(w, False, NULL);
XmeNavigChangeManaged(w); /* for Motif navigation */
}
/*
* Function Name: ExposeMethod
* Description: Handles redisplay
* Arguments: w - the combobox
* event - The expose event in question
* r - The region to be exposed
*/
/*ARGSUSED*/
static void
ExposeMethod(Widget wid, XEvent *event, Region r)
{
Dimension x, y, w, h;
XmDropDownWidget cbw = (XmDropDownWidget)wid;
Widget text = XmDropDown_text(cbw);
Widget arrow = XmDropDown_arrow(cbw);
if(!XmDropDown_new_visual_style(cbw))
return;
if (LayoutIsRtoLM(cbw))
x = arrow->core.x - arrow->core.border_width -
cbw->manager.shadow_thickness;
else
x = text->core.x - text->core.border_width -
cbw->manager.shadow_thickness;
y = text->core.y - text->core.border_width -
cbw->manager.shadow_thickness;
w = text->core.width + arrow->core.width +
2*(text->core.border_width + arrow->core.border_width) +
2*cbw->manager.shadow_thickness;
h = text->core.height + 2*text->core.border_width +
2*cbw->manager.shadow_thickness;
XmeDrawShadows(XtDisplay(cbw), XtWindow(cbw),
cbw->manager.top_shadow_GC,
cbw->manager.bottom_shadow_GC,
x, y, w, h,
cbw->manager.shadow_thickness,
XmSHADOW_IN);
}
/************************************************************
*
* Actions and Callbacks.
*
************************************************************/
#ifdef FIX_1446
/* Function Name: CheckUnpost
* Description: This is called when the arrow button is armed.
* Arguments: w - the arrow button widget.
* combo_ptr - the combination box pointer.
* info_ptr - a pointer to the arrow button info.
* Returns: none.
*/
/* ARGSUSED */
static void
CheckUnpost(Widget w, XtPointer combo_ptr, XtPointer info_ptr)
{
XmDropDownWidget cbw = (XmDropDownWidget) combo_ptr;
XmArrowButtonCallbackStruct *arrow = (XmArrowButtonCallbackStruct *) info_ptr;
XmGrabShellWidget gs = (XmGrabShellWidget) XmDropDown_popup_shell(cbw) ;
if (gs && arrow && arrow->event->xbutton.time == gs->grab_shell.unpost_time)
XmDropDown_list_state(cbw) = XmDropDown_AFTER_UNPOST;
}
#endif
/* Function Name: ArrowClicked
* Description: This is called when the arrow button is selected.
* Arguments: w - the arrow button widget.
* combo_ptr - the combination box pointer.
* info_ptr - a pointer to the arrow button info.
* Returns: none.
*/
/* ARGSUSED */
static void
ArrowClicked(Widget w, XtPointer combo_ptr, XtPointer info_ptr)
{
XmDropDownWidget cbw = (XmDropDownWidget) combo_ptr;
Arg args[10];
Cardinal num_args;
Boolean is_unposted, success = True;
XmAnyCallbackStruct cbdata;
XmArrowButtonCallbackStruct *arrow = (XmArrowButtonCallbackStruct*)
info_ptr;
/*
* Do Nothing...
*/
if (XmDropDown_list_state(cbw) == XmDropDown_IN_PROGRESS)
return;
#ifdef FIX_1446
if (XmDropDown_list_state(cbw) == XmDropDown_AFTER_UNPOST ) {
XmDropDown_list_state(cbw) = XmDropDown_POSTED;
return;
}
#endif
/*
* DANGER: Do not return early from this function w/o setting
* XmDropDown_list_state(cbw) back to either XmDropDown_UNPOSTED or XmDropDown_POSTED or
* the combo box will never be able to pop up or down its
* list.
*
* You have been warned! CP 9/8/93.
*/
if (XmDropDown_list_state(cbw) == XmDropDown_UNPOSTED)
is_unposted = True;
else /* (XmDropDown_list_state(cbw) == XmDropDown_POSTED) */
is_unposted = False;
XmDropDown_list_state(cbw) = XmDropDown_IN_PROGRESS;
if (is_unposted) {
#ifndef FIX_1371
if (!XmIsGrabShell(XmDropDown_popup_shell(cbw)))
#endif
PopdownList((Widget) cbw);
if (!XmDropDown_customized_combo_box(cbw))
(void) SetTextFromList((Widget) cbw);
cbdata.reason = XmCR_UPDATE_TEXT;
cbdata.event = (arrow == NULL ? NULL : arrow->event);
XtCallCallbackList((Widget) cbw, XmDropDown_update_text_callback(cbw),
(XtPointer) &cbdata);
}
else {
if ((success = PopupList((Widget) cbw)) == True)
{
cbdata.reason = XmCR_UPDATE_SHELL;
cbdata.event = (arrow == NULL ? NULL : arrow->event);
XtCallCallbackList((Widget) cbw, XmDropDown_update_shell_callback(cbw),
(XtPointer) &cbdata);
/*
* Save the old text in case the user cancels.
*/
XtFree((char *) XmDropDown_old_text(cbw));
XmDropDown_old_text(cbw) = XmTextFieldGetString(XmDropDown_text(cbw));
if (!XmDropDown_customized_combo_box(cbw) &&
!SetListFromText((Widget) cbw, False) &&
XmDropDown_verify(cbw))
{
XmTextFieldSetString(XmDropDown_text(cbw), "");
}
}
}
/*
* 'success' will only be False if Popuplist failed.
*/
if (success)
{
num_args = 0;
XtSetArg(args[num_args], XmNarrowDirection,
is_unposted ? XmARROW_DOWN : XmARROW_UP); num_args++;
XtSetValues(w, args, num_args);
}
/*
* If we were up, we are now down, and visa-versa.
*/
if (is_unposted)
XmDropDown_list_state(cbw) = XmDropDown_POSTED;
else
XmDropDown_list_state(cbw) = XmDropDown_UNPOSTED;
}
#ifdef FIX_1446
/* Function Name: PopdownDone
* Description: This is called when the popup_shell is poped down.
* Arguments: w - the popup_shell widget.
* combo_ptr - the combination box pointer.
* info_ptr - a pointer to the popup_shell info.
* Returns: none.
*/
/* ARGSUSED */
static void
PopdownDone(Widget w, XtPointer combo_ptr, XtPointer info_ptr)
{
XmDropDownWidget cbw = (XmDropDownWidget) combo_ptr;
ArrowClicked(XmDropDown_arrow(cbw), (XtPointer) cbw, NULL);
}
#endif
/* Function Name: CheckExtensions
* Description: Verifies that the extension is of the correct
* format, with correct version number and
* record type
* Arguments: combo - XmDropDownWidgetClass
* Returns: returns a valid extension as a
* XmDropDownClassPartExtension pointer
*/
static XmDropDownClassPartExtension *
CheckExtensions( XmDropDownWidgetClass combo )
{
XmDropDownClassPartExtension *ret_extension=NULL, *extension;
_XmProcessLock();
extension= (XmDropDownClassPartExtension *)(combo->combo_class.extension);
_XmProcessUnlock();
while ((ret_extension == NULL) && (extension != NULL)){
if ((extension->record_type == NULLQUARK) &&
(extension->version == XmDropDownExtensionVersion)) {
ret_extension = (XmDropDownClassPartExtension *)extension;
}
extension=(XmDropDownClassPartExtension *)extension->next_extension;
}
return( ret_extension );
}
/* Function Name: IsTextOK
* Description: This is called to verify the text field.
* Arguments: w - the text field widget.
* combo_ptr - the combination box pointer.
* UNUSED info_ptr - a pointer to the arrow button info.
* Returns: none.
*/
/*ARGSUSED*/
static Boolean
IsTextOK(XmDropDownWidget cbw)
{
Boolean isOK = True;
XmDropDownClassPartExtension *addition;
addition = CheckExtensions( (XmDropDownWidgetClass)XtClass(cbw) );
if (addition && addition->verify) {
char *text = XmTextFieldGetString(XmDropDown_text(cbw));
/* let the subclass verify the string with the application */
isOK = (*addition->verify)((Widget)cbw, text);
XtFree(text);
} else {
isOK = SetListFromText((Widget) cbw, True);
}
return isOK;
}
/* Function Name: VerifyTextField
* Description: This is called to verify the text field.
* Arguments: w - the text field widget.
* combo_ptr - the combination box pointer.
* UNUSED info_ptr - a pointer to the arrow button info.
* Returns: none.
*/
/*ARGSUSED*/
static void
VerifyTextField(Widget w, XtPointer combo_ptr, XtPointer info_ptr)
{
XmDropDownWidget cbw = (XmDropDownWidget) combo_ptr;
XmTextVerifyCallbackStruct *field = (XmTextVerifyCallbackStruct*) info_ptr;
XmAnyCallbackStruct cbdata;
Boolean allowTraverse = True;
if (!XmDropDown_customized_combo_box(cbw))
{
if (XmDropDown_verify(cbw) && !IsTextOK(cbw))
{
/*
* Check to see if the extension is there
*/
XmDropDownClassPartExtension *addition;
addition =
CheckExtensions((XmDropDownWidgetClass)XtClass(cbw));
cbdata.reason = XmCR_VERIFY_TEXT_FAILED;
cbdata.event = (field == NULL ? NULL : field->event);
XtCallCallbackList((Widget)cbw,
XmDropDown_verify_text_failed_callback(cbw),
(XtPointer) &cbdata);
/* otherwise we handle the error; again must let the subclass
** know the string has been updated -- in response to the user's
** input although not to that value -- to some other value
*/
if (!XmDropDown_editable(cbw)) {
/* it is not clear how this case can be reached but fill it out
** for completeness
*/
XmListSelectPos(XmDropDown_list(cbw), 1, False);
SetTextFromList((Widget) cbw);
if (addition && addition->update)
{
char *text = XmTextFieldGetString(XmDropDown_text(cbw));
(void)(*addition->update)((Widget)cbw,text);
XtFree(text);
}
}
else
{
XmTextFieldSetString(XmDropDown_text(cbw), "");
if (addition && addition->update)
(void)(*addition->update)((Widget)cbw,"");
}
}
/* else blindly accept the value */
else
{
XmDropDownClassPartExtension *addition =
CheckExtensions( (XmDropDownWidgetClass)XtClass(cbw) );
if (addition && addition->update)
{
char *text = XmTextFieldGetString(XmDropDown_text(cbw));
(void)(*addition->update)((Widget)cbw,text);
XtFree(text);
}
}
}
if (w != NULL)
{
cbdata.reason = XmCR_VERIFY_TEXT;
cbdata.event = (field == NULL ? NULL : field->event);
XtCallCallbackList((Widget) cbw,
XmDropDown_verify_text_callback(cbw),
(XtPointer) &cbdata);
}
if(!XmDropDown_doActivate(cbw)) {
/* here if we were NOT called from the autofill code */
if(field == NULL || field->reason != XmCR_ACTIVATE) {
allowTraverse = False;
}
}
if(allowTraverse && XmDropDown_autoTraversal(cbw)) {
(void) XmProcessTraversal((Widget)cbw, XmTRAVERSE_NEXT_TAB_GROUP);
}
}
/* Function Name: ModifyVerifyTextField
* Description: This is called to check if text field is filled so
* we can autotraverse
* Arguments: w - the text field widget.
* combo_ptr - the combination box pointer.
* UNUSED info_ptr - a pointer to the arrow button info.
* Returns: none.
*/
/*ARGSUSED*/
static void
ModifyVerifyTextField(Widget w, XtPointer combo_ptr, XtPointer info_ptr)
{
XmDropDownWidget cbw = (XmDropDownWidget) combo_ptr;
XmTextVerifyCallbackStruct *field = (XmTextVerifyCallbackStruct*) info_ptr;
if (XmDropDown_activateOnFill(cbw) <= 0) return;
if(field == NULL || field->event == NULL ||
field->event->type != KeyPress) return;
/* printf("Text m/v callback, cur/new/start/end = %d %d %d %d\n",
* field->currInsert, field->newInsert, field->startPos, field->endPos);
*/
/* No make sure we are inserting a single character at the end */
if(field->currInsert != field->endPos) return;
if(field->currInsert != field->startPos) return;
if(field->text->length != 1) return;
if(field->currInsert + 1 == XmDropDown_activateOnFill(cbw)) {
XmDropDown_doActivate(cbw) = True;
}
}
/* Function Name: ValueChangedTextField
* Description: Called after value is changed, checks doActivate flag
* to see if we should try traversal
* Arguments: w - the text field widget.
* combo_ptr - the combination box pointer.
* UNUSED info_ptr - a pointer to the arrow button info.
* Returns: none.
*/
/*ARGSUSED*/
static void
ValueChangedTextField(Widget w, XtPointer combo_ptr, XtPointer info_ptr)
{
XmDropDownWidget cbw = (XmDropDownWidget) combo_ptr;
if(XmDropDown_inValueChanged(cbw)) return;
XmDropDown_inValueChanged(cbw) = True;
if(XmDropDown_doActivate(cbw)) {
VerifyTextField(NULL, (XtPointer) cbw, (XtPointer) info_ptr);
/* We clear this AFTER the call, because it is used to
* check inside VerifyText if we should do an autoTraversal
* or not
*/
XmDropDown_doActivate(cbw) = False;
}
XmDropDown_inValueChanged(cbw) = False;
}
/* Function Name: ListSelected
* Description: Called when the popdown list is selected.
* Arguments: w - the list widget.
* cbw_ptr - pointer to the combination box.
* list_data_ptr - data from the list widget.
* Returns: none.
*/
/* ARGSUSED */
static void
ListSelected(Widget w, XtPointer cbw_ptr, XtPointer list_data_ptr)
{
XmDropDownWidget cbw = (XmDropDownWidget) cbw_ptr;
XmListCallbackStruct *list_data;
list_data = (XmListCallbackStruct *) list_data_ptr;
if ((list_data->reason == XmCR_BROWSE_SELECT) &&
((list_data->event == NULL) ||
((list_data->event->xany.type != ButtonPress) &&
(list_data->event->xany.type != ButtonRelease))))
{
/*
* Do not popup list is browse select mode.
*/
if (!XmDropDown_customized_combo_box(cbw))
(void) SetTextFromList((Widget) cbw);
return;
}
/*
* Same thing happens as when the arrow is clicked.
*/
#ifndef FIX_1446
ArrowClicked(XmDropDown_arrow(cbw), (XtPointer) cbw, NULL);
#endif
}
/* Function Name: ShellButtonEvent
* Description: Called when a button press is passed to the shell
* from the grab that was activated.
* Arguments: w - the shell widget.
* cbw_ptr - the combo box widget pointer.
* event - the event that caused this action.
* junk - *** UNUSED.
* Returns: none.
*
* NOTE: Because this is popped up spring loaded we get all events
* that are delivered, so we need to not pop this down if we clicked
* on the arrow (the arrow click is handled by the arrow button)
* or if we click in the popped up combo box widget.
*/
/* ARGSUSED */
static void
ShellButtonEvent(Widget w, XtPointer cbw_ptr, XEvent *event, Boolean *dispatch)
{
XmDropDownWidget cbw = (XmDropDownWidget) cbw_ptr;
Widget event_widget;
switch (event->type)
{
case ButtonRelease:
if (cbw->combo.scrolling)
*dispatch = cbw->combo.scrolling = FALSE;
break;
case ButtonPress:
/* Press & release in the scrollbar shouldn't popdown the list. */
if ((cbw->combo.vsb &&
XtIsRealized(cbw->combo.vsb) &&
(event->xbutton.window == XtWindow(cbw->combo.vsb))) ||
(cbw->combo.hsb &&
XtIsRealized(cbw->combo.hsb) &&
(event->xbutton.window == XtWindow(cbw->combo.hsb))))
cbw->combo.scrolling = TRUE;
break;
default:
/* This shouldn't happen. */
break;
}
/* TODO: move the following into the switch statement above */
if (event->xany.type != ButtonPress) {
if ((event->xany.type == ButtonRelease) &&
!XmDropDown_customized_combo_box(cbw))
{
XtCallActionProc(XmDropDown_list(cbw), "ListEndSelect",
event, NULL, 0);
}
return;
}
event_widget = XtWindowToWidget(event->xany.display, event->xany.window);
if (event_widget == XmDropDown_arrow(cbw))
return;
else if ((event_widget == XmDropDown_text(cbw)) && !XmDropDown_editable(cbw))
{
TextButtonPress(event_widget, NULL, event, dispatch);
return;
}
else {
Widget event_shell = event_widget;
while (!XtIsShell(event_shell))
event_shell = XtParent(event_shell);
if ( (event_shell == (Widget) XmDropDown_popup_shell(cbw)) &&
(event_widget != (Widget) XmDropDown_popup_shell(cbw)))
{
return;
}
}
if (XmDropDown_list_state(cbw) != XmDropDown_POSTED) /* in case this popup shell is used for more than one combobox */
ArrowClicked(XmDropDown_arrow(cbw), cbw_ptr, NULL);
}
/* Function Name: LoseFocusHandler
* Description: This function is called whenever the shell loses focus
* in this case we should bring down the list.
* Arguments: w - the shell widget.
* cbw_ptr - the combo box widget pointer.
* event - the event that caused this action.
* junk - *** UNUSED ***.
* Returns: none.
*/
/* ARGSUSED */
static void
LoseFocusHandler(Widget w, XtPointer cbw_ptr, XEvent *event, Boolean *junk)
{
XmDropDownWidget cbw = (XmDropDownWidget) cbw_ptr;
XFocusChangeEvent *fevent = &(event->xfocus);
if ((event->xany.type != FocusOut) || (XmDropDown_list_state(cbw) != XmDropDown_UNPOSTED) ||
(fevent->detail == NotifyInferior))
{
return;
}
#ifndef FIX_1446
ArrowClicked(XmDropDown_arrow(cbw), cbw_ptr, NULL);
#endif
}
/* Function Name: ComboUnpost
* Description: Called when the user wants to remove the list from the
* screen.
* Arguments: w - a child widget of the combo box.
* event - the event that caused this action.
* params, num_params - action routine parameters.
* Returns: none.
*/
/*ARGSUSED*/
static void
ComboUnpost(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
XmDropDownWidget cbw = FindComboBox(w);
if (cbw == NULL)
return;
if (XmDropDown_list_state(cbw) == XmDropDown_UNPOSTED)
ArrowClicked(XmDropDown_arrow(cbw), (XtPointer) cbw, NULL);
}
/* Function Name: ComboPost
* Description: Called when the user wants to show the list on the
* screen.
* Arguments: w - a child widget of the combo box.
* event - the event that caused this action.
* params, num_params - action routine parameters.
* Returns: none.
*/
/*ARGSUSED*/
static void
ComboPost(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
XmDropDownWidget cbw = FindComboBox(w);
if (cbw == NULL)
return;
if (XmDropDown_list_state(cbw) != XmDropDown_UNPOSTED)
ArrowClicked(XmDropDown_arrow(cbw), (XtPointer) cbw, NULL);
}
/* Function Name: ComboCancel
* Description: Called when the user wants to remove the list from the
* screen, but not update the text.
* Arguments: w - a child widget of the combo box.
* event - the event that caused this action.
* params, num_params - action routine parameters.
* Returns: none.
*/
/*ARGSUSED*/
static void
ComboCancel(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
Arg args[10];
Cardinal num_args;
XmDropDownWidget cbw = FindComboBox(w);
if ((cbw == NULL) || XmDropDown_list_state(cbw) != XmDropDown_UNPOSTED)
return;
if (!XmIsGrabShell((Widget)cbw))
PopdownList((Widget) cbw);
XmDropDown_list_state(cbw) = XmDropDown_POSTED; /* List is now down (not visible). */
num_args = 0;
XtSetArg(args[num_args], XmNarrowDirection, XmARROW_DOWN); num_args++;
XtSetValues(XmDropDown_arrow(cbw), args, num_args);
if (XmDropDown_old_text(cbw) != NULL) {
XmTextFieldSetString(XmDropDown_text(cbw), XmDropDown_old_text(cbw));
XtFree((char *) XmDropDown_old_text(cbw));
XmDropDown_old_text(cbw) = NULL;
}
}
/************************************************************
*
* Internal routines.
*
************************************************************/
/* Function Name: FindComboBox
* Description: Finds the combo box given any one of its descendants.
* Arguments: w - any descendant of the combo box.
* Returns: the combo box widget or NULL.
*/
static XmDropDownWidget
FindComboBox(Widget w)
{
while (!XtIsSubclass(w, xmDropDownWidgetClass)) {
if ((w = XtParent(w)) == NULL)
break;
}
return((XmDropDownWidget) w);
}
/* Function Name: RegisterShellHandler
* Description: Registers an event handler on the shell.
* Arguments: w - the combo box widget.
* Returns: none.
*/
static void
RegisterShellHandler(Widget w)
{
XmDropDownWidget cbw = (XmDropDownWidget) w;
if (XmDropDown_popup_shell(cbw) == NULL)
return;
/*
* Don't register the translations if it's a customized shell; the
* actions referenced won't be there!
* This, of course, means that any actions specified in this
* translation table won't ever get called for a customized shell...
*/
if(!XmDropDown_customized_combo_box(cbw)) {
XtOverrideTranslations(XmDropDown_popup_shell(cbw),
XmDropDown_translations(cbw));
}
XtAddEventHandler(XmDropDown_popup_shell(cbw),
ButtonPressMask | ButtonReleaseMask, False,
ShellButtonEvent, (XtPointer) w);
}
/* Function Name: PlaceChildren
* Description: Places and sizes the children.
* Arguments: w - the combo box widget.
* allow_resize - allow the combo box to attempt a resize.
* child - Do not query this child for a width, just
* use its default size.
* Returns: none
*/
static void
PlaceChildren(Widget w, Boolean allow_resize, Widget child)
{
XmDropDownWidget cbw = (XmDropDownWidget) w;
Dimension width, height, rwidth, rheight, child_height;
Dimension text_width, label_width, label_bw;
Dimension shadow;
Position label_x, arrow_x, text_x;
XtWidgetGeometry arrow_geom, label_geom, text_geom;
Widget label = NULL;
Widget text = XmDropDown_text(cbw);
Widget arrow = XmDropDown_arrow(cbw);
FindDesiredSize(w, child, &width, &height,
&label_geom, &text_geom, &arrow_geom);
if (XmDropDown_show_label(cbw))
{
label = XmDropDown_label(cbw);
label_width = label_geom.width;
label_bw = label_geom.border_width;
}
else
{
label_width = 0;
label_bw = 0;
}
text_width = text_geom.width;
if (allow_resize)
{
_XmRequestNewSize(w, False, width, height, &rwidth, &rheight);
}
else
{
rwidth = w->core.width;
rheight = w->core.height;
}
if (width != rwidth)
{
Dimension arrow_width = arrow_geom.width + 2 * arrow_geom.border_width;
GetTextAndLabelWidth(w, rwidth, arrow_width,
label_bw, text_geom.border_width,
&text_width, &label_width);
}
child_height = rheight - 2 * XmDropDown_v_space(cbw);
if (LayoutIsRtoLM(cbw)) {
arrow_x = XmDropDown_h_space(cbw);
label_x = (rwidth - (label_width + 2 * label_geom.border_width) \
- XmDropDown_h_space(cbw));
text_x = label_x - text_width - 2*text_geom.border_width;
} else {
label_x = XmDropDown_h_space(cbw);
arrow_x = (rwidth - (arrow_geom.width + 2 * arrow_geom.border_width) \
- XmDropDown_h_space(cbw));
text_x = label_width + 2*label_geom.border_width + \
XmDropDown_h_space(cbw);
}
if (XmDropDown_show_label(cbw))
{
if (!LayoutIsRtoLM(cbw))
text_x += XmDropDown_h_space(cbw);
else
text_x -= XmDropDown_h_space(cbw);
}
else
{
text_geom.border_width = 0;
}
XmDropDown_text_x(cbw) = text_x;
if ( XmDropDown_new_visual_style(cbw) )
{
shadow = cbw->manager.shadow_thickness;
child_height -= 2 * shadow;
if (LayoutIsRtoLM(cbw))
{
arrow_x += shadow;
text_x -= shadow;
}
else
{
arrow_x -= shadow;
text_x += shadow;
}
}
else
{
shadow = 0;
}
/*
* Now resize the widgets
*/
if (XmDropDown_show_label(cbw))
{
_XmConfigureWidget(label, label_x, /* XmDropDown_h_space(cbw), */
XmDropDown_v_space(cbw),
label_width,
child_height - 2 * label_geom.border_width,
label_geom.border_width);
}
_XmConfigureWidget(text, text_x,
XmDropDown_v_space(cbw) + shadow,
text_width, child_height - 2 * text_geom.border_width,
text_geom.border_width);
_XmConfigureWidget(arrow, arrow_x,
XmDropDown_v_space(cbw) + shadow,
arrow_geom.width,
child_height - 2 * arrow_geom.border_width,
arrow_geom.border_width);
}
/* Function Name: GetTextAndLabelWidth
* Description: Finds the size for both the text and label widgets.
* Arguments: w - the combo box.
* combo_width - the new size of the combo box.
* arrow_width - the new width of the arrow button.
* lbw, tbw - the border widths of the label
* and text widgets.
* text_width, label_width - The desired size of the
* RETURNED text and label is passed in,
* and the new sizes are returned
* Returns: none
*/
static void
GetTextAndLabelWidth(Widget w, Dimension combo_width, Dimension arrow_width,
Dimension lbw, Dimension tbw,
Dimension *text_width, Dimension *label_width)
{
XmDropDownWidget cbw = (XmDropDownWidget) w;
int text_and_label;
text_and_label = combo_width - (arrow_width + 2 * (lbw + tbw));
text_and_label -= 3 * XmDropDown_h_space(cbw);
if (XmDropDown_show_label(cbw))
{
text_and_label -= XmDropDown_h_space(cbw);
}
if (XmDropDown_new_visual_style(cbw))
{
text_and_label -= 2 * cbw->manager.shadow_thickness;
text_and_label += XmDropDown_h_space(cbw);
}
if (text_and_label >= (int) (*text_width + *label_width))
{
*text_width = text_and_label - *label_width;
}
/*
* We need to shrink each a bit.
*/
else
{
if ( text_and_label < 2 )
{
*text_width = *label_width = 1;
return;
}
*text_width = ((int)(*text_width * text_and_label)/
(int)(*text_width + *label_width));
*label_width = text_and_label - *text_width;
}
if (*text_width < 1)
{
*text_width = 1;
}
if ((*label_width < 1) && (XmDropDown_show_label(cbw)))
{
*label_width = 1;
}
}
/* Function Name: FindDesiredSize
* Description: Finds the desired size of the combination box.
* Arguments: w - the combo box.
* RETURNED width_ret, height_ret - The desired size.
* Returns: none
*/
static void
FindDesiredSize(Widget w, Widget child,
Dimension * width_ret, Dimension * height_ret,
XtWidgetGeometry * label, XtWidgetGeometry * text,
XtWidgetGeometry * arrow)
{
XmDropDownWidget cbw = (XmDropDownWidget) w;
Dimension shadow;
int label_width, text_width, arrow_width, h_space;
if ( !XmDropDown_show_label(cbw) )
{
label->width = 0;
label->height = 0;
label->border_width = 0;
}
else if ( child != XmDropDown_label(cbw) ) {
(void) XtQueryGeometry(XmDropDown_label(cbw), NULL, label);
}
else
{
label->width = child->core.width;
label->height = child->core.height;
label->border_width = child->core.border_width;
}
if ( child != XmDropDown_text(cbw) )
{
(void) XtQueryGeometry(XmDropDown_text(cbw), NULL, text);
}
else
{
text->width = child->core.width;
text->height = child->core.height;
text->border_width = child->core.border_width;
}
if ( child != XmDropDown_arrow(cbw) )
{
(void) XtQueryGeometry(XmDropDown_arrow(cbw), NULL, arrow);
}
else
{
arrow->width = child->core.width;
arrow->height = child->core.height;
arrow->border_width = child->core.border_width;
}
label_width = label->width + 2 * label->border_width;
text_width = text->width + 2 * text->border_width;
arrow_width = arrow->width + 2 * arrow->border_width;
h_space = 3 * XmDropDown_h_space(cbw);
*width_ret = (Dimension )(label_width + text_width \
+ arrow_width + h_space);
if ( XmDropDown_show_label(cbw) )
{
*width_ret += XmDropDown_h_space(cbw);
}
if ( XmDropDown_new_visual_style(cbw) )
{
shadow = cbw->manager.shadow_thickness;
*width_ret += 2 * shadow;
*width_ret -= XmDropDown_h_space(cbw);
}
else
{
shadow = 0;
}
*height_ret = 0;
ASSIGN_MAX(*height_ret, label->height + 2 * label->border_width);
ASSIGN_MAX(*height_ret, text->height + \
2 * text->border_width + 2 * shadow);
/*
* can't use arrow sizes in the specification;
* it has no query_geometry procedure
*/
/*
* ASSIGN_MAX(*height_ret, arrow->height + 2 * arrow->border_width
* + 2 * shadow);
*/
*height_ret += 2 * XmDropDown_v_space(cbw);
}
/* Function Name: CreateChildren
* Description: Creates all normal children for the Combo Box.
* Arguments: w - the combo box.
* args, num_args - the args to create this widget with.
* Returns: none.
*
* NOTE(DKB:03/07/96):
* This function used to only created the needed children, i.e. if
* show label was False the label was not created, and the popup list
* was never created. This was changed due to the fact that this widget
* uses a resources pass-through method thus if the widgets are not
* created at initialization all resources that should be pass-through
* to those widgets are lost.
*/
static void
CreateChildren(Widget w, ArgList args, Cardinal num_args)
{
XmDropDownWidget cbw = (XmDropDownWidget) w;
Arg largs[10];
Cardinal num_largs;
Arg targs[10], *merge;
Cardinal tn = 0;
XmDropDown_label(cbw) = XtCreateWidget("label", xmLabelWidgetClass,
w, args, num_args);
XtVaSetValues(XmDropDown_label(cbw), XmNtraversalOn, False, NULL);
/*
* If we are supposed to show this label lets manage the widget.
*/
if( XmDropDown_show_label(cbw) )
{
XtManageChild(XmDropDown_label(cbw));
}
if( XmDropDown_use_text_field(cbw) )
{
tn = 0;
if(XmDropDown_new_visual_style(cbw))
{
XtSetArg(targs[tn], XmNshadowThickness, 0); tn++;
XtSetArg(targs[tn], XmNhighlightThickness, 0); tn++;
}
else
{
XtSetArg(targs[tn], XmNshadowThickness, 2); tn++;
XtSetArg(targs[tn], XmNhighlightThickness, 2); tn++;
}
merge = XtMergeArgLists(args, num_args, targs, tn);
XmDropDown_text(cbw) =
XtCreateManagedWidget("text", xmTextFieldWidgetClass,
w, merge, num_args+tn);
XtFree((XtPointer)merge);
}
else
{
tn = 0;
if(XmDropDown_new_visual_style(cbw))
{
XtSetArg(targs[tn], XmNshadowThickness, 0); tn++;
XtSetArg(targs[tn], XmNhighlightThickness, 0); tn++;
}
else
{
XtSetArg(targs[tn], XmNshadowThickness, 2); tn++;
XtSetArg(targs[tn], XmNhighlightThickness, 2); tn++;
}
XtSetArg(targs[tn], XmNeditMode, XmSINGLE_LINE_EDIT); tn++;
XtSetArg(targs[tn], XmNrows, 1); tn++;
XtSetArg(targs[tn], XmNwordWrap, False); tn++;
XtSetArg(targs[tn], XmNscrollHorizontal, False); tn++;
XtSetArg(targs[tn], XmNscrollVertical, False); tn++;
merge = XtMergeArgLists(args, num_args, targs, tn);
XmDropDown_text(cbw) = XtCreateManagedWidget("text", xmTextWidgetClass,
w, merge, num_args + tn);
XtFree((XtPointer)merge);
}
XtAddCallback(XmDropDown_text(cbw), XmNlosingFocusCallback,
VerifyTextField, (XtPointer) cbw);
XtAddCallback(XmDropDown_text(cbw), XmNactivateCallback,
VerifyTextField, (XtPointer) cbw);
XtAddCallback(XmDropDown_text(cbw), XmNmodifyVerifyCallback,
ModifyVerifyTextField, (XtPointer) cbw);
XtAddCallback(XmDropDown_text(cbw), XmNvalueChangedCallback,
ValueChangedTextField, (XtPointer) cbw);
XtOverrideTranslations(XmDropDown_text(cbw),
XmDropDown_translations(cbw));
if(XmDropDown_new_visual_style(cbw))
{
tn = 0;
XtSetArg(targs[tn], XmNhighlightThickness, 0); tn++;
XtSetArg(targs[tn], XmNshadowThickness, 2); tn++;
merge = XtMergeArgLists(args, num_args, targs, tn);
XmDropDown_arrow(cbw) =
XtCreateManagedWidget("arrow", xmArrowButtonWidgetClass,
w, merge, num_args+tn);
XtFree((XtPointer)merge);
}
else
{
tn = 0;
XtSetArg(targs[tn], XmNshadowThickness, 2); tn++;
XtSetArg(targs[tn], XmNhighlightThickness, 2); tn++;
XmDropDown_arrow(cbw) =
XtCreateManagedWidget("arrow", xmArrowButtonWidgetClass,
w, args, num_args);
}
num_largs = 0;
XtSetArg(largs[num_largs], XmNarrowDirection, XmARROW_DOWN); num_largs++;
XtSetValues(XmDropDown_arrow(cbw), largs, num_largs);
XtOverrideTranslations(XmDropDown_arrow(cbw),
XmDropDown_translations(cbw));
XtAddCallback(XmDropDown_arrow(cbw), XmNactivateCallback,
ArrowClicked, (XtPointer) w);
#ifdef FIX_1446
XtAddCallback(XmDropDown_arrow(cbw), XmNarmCallback, CheckUnpost, (XtPointer) w);
#endif
}
/*
* To deal with the problem, SBBtnDownEH will do an XtGrabPointer
* to transfer the grab to the scrollbar and SBBtnUpEH will cause
* the grab to return to the grab shell.
*/
/*ARGSUSED*/
static void
SBBtnDownEH(Widget w,
XtPointer client_data,
XEvent *event,
Boolean *cont) /* unused */
{
XmGrabShellWidget shell = (XmGrabShellWidget) client_data;
XtGrabPointer(w, False, Events | PointerMotionMask | ButtonMotionMask,
GrabModeAsync, GrabModeAsync,
None, shell->grab_shell.cursor, event->xbutton.time);
}
/*ARGSUSED*/
static void
SBBtnUpEH(Widget w, /* unused */
XtPointer client_data,
XEvent *event,
Boolean *cont) /* unused */
{
XmGrabShellWidget shell = (XmGrabShellWidget) client_data;
/* Note that this regrab to the grab shell will need to be changed
* if the kind of grab that the grabshell imposes changes.
*/
XtGrabPointer((Widget) shell, shell->grab_shell.owner_events,
Events,
shell->grab_shell.grab_style, GrabModeAsync,
None, shell->grab_shell.cursor, event->xbutton.time);
if (shell->grab_shell.grab_style == GrabModeSync)
XAllowEvents(XtDisplay(shell), SyncPointer, event->xbutton.time);
}
/* Function Name: CreatePopup
* Description: Create the popup shell that contains the list.
* Arguments: w - the combo box.
* args, num_args - the number of arguments in the list.
* Returns: none.
*/
static void
CreatePopup(Widget w, ArgList args, Cardinal num_args)
{
XmDropDownWidget cbw = (XmDropDownWidget) w;
Arg *new_list, largs[10];
Cardinal num_largs;
Widget sb;
num_largs = 0;
XtSetArg(largs[num_largs], XmNoverrideRedirect, True); num_largs++;
XtSetArg(largs[num_largs], XmNsaveUnder, True); num_largs++;
XtSetArg(largs[num_largs], XmNallowShellResize, True); num_largs++;
XtSetArg(largs[num_largs], XmNancestorSensitive, True); num_largs++;
XtSetArg(largs[num_largs], XmNownerEvents, True), num_largs++;
XtSetArg(largs[num_largs], XmNgrabStyle, GrabModeSync), num_largs++;
new_list = XtMergeArgLists(args, num_args, largs, num_largs);
XmDropDown_popup_shell(cbw) = XtCreatePopupShell("popupShell",
xmGrabShellWidgetClass, w,
new_list,
num_largs + num_args);
XtFree((char *) new_list);
#ifdef FIX_1446
XtAddCallback(XmDropDown_popup_shell(cbw), XmNpopdownCallback, PopdownDone , (XtPointer) w);
#endif
/*
* Set the visible item count of the list child widget
*/
num_largs = 0;
XtSetArg(largs[num_largs], XmNvisibleItemCount,
XmDropDown_visible_items(cbw)); num_largs++;
new_list = XtMergeArgLists(args, num_args, largs, num_largs);
XmDropDown_list(cbw) = XmCreateScrolledList(XmDropDown_popup_shell(cbw), "list",
new_list, num_args + num_largs);
XtFree((char *) new_list);
XtAddCallback(XmDropDown_list(cbw), XmNdefaultActionCallback,
ListSelected, (XtPointer) cbw);
XtAddCallback(XmDropDown_list(cbw), XmNsingleSelectionCallback,
ListSelected, (XtPointer) cbw);
XtAddCallback(XmDropDown_list(cbw), XmNbrowseSelectionCallback,
ListSelected, (XtPointer) cbw);
XtManageChild(XmDropDown_list(cbw));
num_largs = 0;
XtSetArg(largs[num_largs], XmNhorizontalScrollBar, &(cbw->combo.hsb)), num_largs++;
XtSetArg(largs[num_largs], XmNverticalScrollBar, &(cbw->combo.vsb)), num_largs++;
XtGetValues(XtParent(XmDropDown_list(cbw)), largs, num_largs);
sb = cbw->combo.vsb;
if (sb != (Widget) NULL) {
XtInsertEventHandler(sb, ButtonPressMask, False, SBBtnDownEH,
(XtPointer) XmDropDown_popup_shell(cbw), XtListHead);
XtInsertEventHandler(sb, ButtonReleaseMask, False, SBBtnUpEH,
(XtPointer) XmDropDown_popup_shell(cbw), XtListHead);
}
sb = cbw->combo.hsb;
if (sb != (Widget) NULL) {
XtInsertEventHandler(sb, ButtonPressMask, False, SBBtnDownEH,
(XtPointer) XmDropDown_popup_shell(cbw), XtListHead);
XtInsertEventHandler(sb, ButtonReleaseMask, False, SBBtnUpEH,
(XtPointer) XmDropDown_popup_shell(cbw), XtListHead);
}
}
/* Function Name: PopdownList
* Description: Pops down the list of choices.
* Arguments: w - the combo box.
* Returns: none
*/
static void
PopdownList(Widget w)
{
XmDropDownWidget cbw = (XmDropDownWidget) w;
#ifdef FIX_1371
Widget gs = XmDropDown_popup_shell(cbw);
if (gs && XmIsGrabShell(gs) && (XmDropDown_list_state(cbw) != XmDropDown_POSTED))
XtCallActionProc(gs, "GrabShellPopdown", NULL, NULL, 0);
#else
if (XmDropDown_popup_shell(cbw) != NULL) {
XSetInputFocus(XtDisplay(w), XmDropDown_focus_owner(cbw),
XmDropDown_focus_state(cbw),
XtLastTimestampProcessed(XtDisplay(w)));
/*
* The order is important here to keep from generating Xt Errors.
*/
if (!XmIsGrabShell(XmDropDown_popup_shell(cbw)))
XtRemoveGrab(XmDropDown_arrow(cbw));
XtUngrabKeyboard(w, XtLastTimestampProcessed(XtDisplay(w)));
XtPopdown(XmDropDown_popup_shell(cbw));
}
#endif
else {
XmeWarning(w, XmNnoComboShellMsg);
}
}
/* ARGSUSED */
static void
TextButtonPress(Widget w , XtPointer client, XEvent *event, Boolean *go_on)
{
XmDropDownWidget cbw = FindComboBox(w);
if (cbw == NULL)
return;
/*
* It is debatable whether or not we should eat this event. For now,
* we'll let it continue.
*/
#ifdef notdef
*go_on = False;
#endif
if (event->xany.type == ButtonPress) {
if (XmDropDown_list_state(cbw) == XmDropDown_POSTED) {
(void)ComboPost( w, NULL, NULL, NULL );
XmDropDown_list_state(cbw) = XmDropDown_BEGIN_POPUP_FROM_TEXT;
return;
}
else if (XmDropDown_list_state(cbw) == XmDropDown_UNPOSTED) {
(void)ComboUnpost( w, NULL, NULL, NULL );
}
else if (XmDropDown_list_state(cbw) == XmDropDown_BEGIN_POPUP_FROM_TEXT)
XmDropDown_list_state(cbw) = XmDropDown_UNPOSTED;
}
}
/* Function Name: PopupList
* Description: Pops up the list of choices.
* Arguments: w - the combo box.
* Returns: True if sucessful.
*/
static Boolean
PopupList(Widget w)
{
XmDropDownWidget cbw = (XmDropDownWidget) w;
Widget shell = XmDropDown_popup_shell(cbw);
Position x, y, temp;
Dimension width;
int ret, scr_width, scr_height;
Arg args[10];
Cardinal num_args;
if (shell == NULL) {
XmeWarning(w, XmNnoComboShellMsg);
return(False);
}
XtTranslateCoords(w, 0, XtHeight(w), &x, &y);
XtRealizeWidget(shell);
num_args = 0;
if (LayoutIsRtoLM(w))
temp = XmDropDown_arrow(cbw)->core.x + XmDropDown_popup_offset(cbw);
else
temp = XmDropDown_text_x(cbw) + XmDropDown_popup_offset(cbw);
x += temp;
if (!XmDropDown_customized_combo_box(cbw)) {
width = (cbw->core.width - temp -
(shell)->core.border_width);
XtSetArg(args[num_args], XmNwidth, width); num_args++;
}
else
{
width = XtWidth(shell);
}
/*
* Now that we know where on the screen we want to display the popup
* we have to make sure that it will fit on the screen. What we
* do here is check if y + height and x + width are still on the
* screen. If now we decrease x and/or until the popup would be on
* the screen. As a last check we make sure that x and y are >= 0.
*
* Lets start by getting the width and height of the screen.
*/
scr_width = WidthOfScreen(XtScreen(shell));
scr_height = HeightOfScreen(XtScreen(shell));
if( (int)(y + XtHeight(shell)) > scr_height )
{
Position tmp;
XtTranslateCoords(w, 0, 0, &tmp, &y);
y -= ((int)XtHeight(shell));
}
if( y < 0 ) y = 0;
if( (int)(x + width) > scr_width )
{
x = scr_width - ((int)width);
}
if( x < 0 ) x = 0;
XtSetArg(args[num_args], XmNx, x); num_args++;
XtSetArg(args[num_args], XmNy, y); num_args++;
XtSetValues(shell, args, num_args);
/*
* Because of an Xt bug, we need to cal the shell widget's resize
* proc ourselves.
*/
{
/* THIS WAS -
(*(XtClass(shell)->core_class.resize))(shell);
*/
XtWidgetProc resize;
_XmProcessLock();
resize = *(XtClass(shell)->core_class.resize);
_XmProcessUnlock();
(*resize) (shell);
}
if (!XmIsGrabShell(shell))
XGetInputFocus(XtDisplay(shell),
&(XmDropDown_focus_owner(cbw)), &(XmDropDown_focus_state(cbw)));
/*
* If we are in pointer root mode it is possible that the pointer is
* over our popup so that when it is popped up we have the focus.
* if we later do a XSetInputFocus a lose focus will be delivered
* to us and pop us down. I have solved this problem by temporarily
* setting the keyboard focus to the combo box's window and then
* popping up the window and setting the focus to us. This keeps
* us from losing the focus.
*
* Keyboard events could be lost, but until the window comes up we
* don't know where the events will be delivered anyway so this is
* no worse than just settting the input focus to our window.
*
* A Sync. popup may solve this problem, but it is not too big a deal.
*
* Chris D. Peterson
*/
if (!XmIsGrabShell(shell))
XSetInputFocus(XtDisplay(shell), XtWindow((Widget) cbw), RevertToParent,
XtLastTimestampProcessed(XtDisplay(w)) - 1);
#ifdef FIX_1486
_XmPopupSpringLoaded(shell);
#else
XtPopupSpringLoaded(shell);
#endif
if (!XmIsGrabShell(shell)) {
ret = XtGrabPointer(shell, True,
ButtonPressMask | ButtonReleaseMask,
GrabModeAsync, GrabModeAsync, None,
XmDropDown_popup_cursor(cbw),
XtLastTimestampProcessed(XtDisplay(w)));
if (ret != GrabSuccess) {
XtPopdown(shell);
/*
* We could not popup the list, this is because somehow things
* got so slow that we were not allowed to grab the server.
* In this case I will fail silently and the user can try again.
*/
return(False);
}
XtAddGrab(XmDropDown_arrow(cbw), False, False);
/*
* Since this is an override redirect window we know that no one
* will get in the way of thisX SetInputFocus Event.
*/
XSetInputFocus(XtDisplay(shell),
XtWindow(shell), RevertToParent, CurrentTime);
}
return(True);
}
/* Function Name: SetListFromText
* Description: Makes the list highlights match the text widget.
* Arguments: w - the combo box widget.
* no_action - just check to see if this would succeed.
* Returns: True if each item was found, or the text widget is
* empty.
*/
static Boolean
SetListFromText(Widget w, Boolean no_action)
{
Arg args[10];
Cardinal num_args;
int count = 0, vcount, tcount;
XrmValue to, from;
XmStringTable table, tptr;
XmDropDownWidget cbw = (XmDropDownWidget) w;
String ptr = XmTextFieldGetString(XmDropDown_text(cbw));
XmStringTable sel_table;
Boolean error = False;
unsigned char policy;
XmDropDownClassPartExtension *addition;
if (ptr != NULL) {
int num_items;
addition = CheckExtensions((XmDropDownWidgetClass)XtClass(cbw));
if (addition && addition->setListFromText)
{
XtFree(ptr);
return (*addition->setListFromText)(w, XmDropDown_text(cbw),
XmDropDown_list(cbw));
}
num_args = 0;
XtSetArg(args[num_args], XmNitemCount, &num_items); num_args++;
XtGetValues(XmDropDown_list(cbw), args, num_args);
/*
* Strlen can be used here because we are attempting to find the
* number of bytes in the string not the number of i18n characters.
*/
from.size = sizeof(char) * (strlen(ptr) + 1);
from.addr = ptr;
to.size = sizeof(XmStringTable);
to.addr = (XtPointer) &table;
XtConvertAndStore(XmDropDown_list(cbw), XmRString, &from,
XmRXmStringTable, &to);
/*
* If the text field contains "", the table will be NULL
*/
if (table != NULL) {
for(tptr = table, count = 0; *tptr != NULL ; tptr++) count++;
sel_table = (XmStringTable) XtMalloc(sizeof(XmString) * count);
for(tptr = table, count = 0; *tptr != NULL ; tptr++) {
if (XmListItemExists(XmDropDown_list(cbw), *tptr))
sel_table[count++] = *tptr;
else {
error = TRUE;
break;
}
}
}
else
sel_table = NULL;
XtFree((char *) ptr);
}
else {
count = 0;
sel_table = NULL;
}
if (!no_action)
XmListDeselectAllItems(XmDropDown_list(cbw));
/*
* If single select and there is more than one element in
* the list, then we have an error.
*/
num_args = 0;
XtSetArg(args[num_args], XmNselectionPolicy, &policy); num_args++;
XtSetArg(args[num_args], XmNvisibleItemCount, &vcount); num_args++;
XtSetArg(args[num_args], XmNitemCount, &tcount); num_args++;
XtGetValues(XmDropDown_list(cbw), args, num_args);
if ((((policy == XmSINGLE_SELECT) ||
(policy == XmBROWSE_SELECT)) && (count > 1)) || error)
{
XtFree((char *) sel_table);
return(FALSE);
}
num_args = 0;
XtSetArg(args[num_args], XmNselectedItems, sel_table); num_args++;
XtSetArg(args[num_args], XmNselectedItemCount, count); num_args++;
XtSetValues(XmDropDown_list(cbw), args, num_args);
/*
* Makes the first selected item the first item in the list.
*/
if (count > 0) {
int *pos_list, num, pos = 0;
XmListGetMatchPos(XmDropDown_list(cbw), sel_table[0], &pos_list, &num);
if (num > 0) {
pos = pos_list[0] - vcount/2;
if (pos < 1)
pos = 1;
else if (pos > (tcount - vcount + 1))
pos = tcount - vcount + 1;
XtFree((char *) pos_list);
}
XmListSetPos(XmDropDown_list(cbw), pos);
}
XtFree((char *) sel_table);
return(TRUE);
}
/* Function Name: SetTextFromList
* Description: Makes the text strings matched the elements
* highlighted in the list.
* Arguments: w - the combo box widget.
* Returns: True if each item was found, or the text widget is
* empty.
*/
static Boolean
SetTextFromList(Widget w)
{
XmDropDownWidget cbw = (XmDropDownWidget) w;
Arg args[10];
Cardinal num_args;
XmStringTable items;
int count;
unsigned char policy;
register int i, text_loc;
XmDropDownClassPartExtension *addition;
addition = CheckExtensions( (XmDropDownWidgetClass)XtClass(cbw) );
if (addition && addition->setTextFromList)
{
return (*addition->setTextFromList)(w,XmDropDown_text(cbw),
XmDropDown_list(cbw));
}
num_args = 0;
XtSetArg(args[num_args], XmNselectedItems, &items); num_args++;
XtSetArg(args[num_args], XmNselectedItemCount, &count); num_args++;
XtSetArg(args[num_args], XmNselectionPolicy, &policy); num_args++;
XtGetValues(XmDropDown_list(cbw), args, num_args);
if ((policy == XmMULTIPLE_SELECT) || (policy == XmEXTENDED_SELECT) ||
(count > 0))
{
XmTextFieldSetString(XmDropDown_text(cbw), "");
}
text_loc = 0;
i = 0;
while (i < count) {
register int len;
String ptr;
wchar_t temp[BUFSIZ];
ptr = XmStringUnparse(items[i], NULL, XmCHARSET_TEXT, XmMULTIBYTE_TEXT,
NULL, 0, XmOUTPUT_ALL);
if (mbstowcs(NULL, ptr, 0) == (ssize_t)(-1)) {
XmeWarning((Widget) cbw, XmNstringGetFailedMsg);
i++;
continue;
}
/*
* There must be a better way to do a strlen for I18N text.
*/
len = (int) mbstowcs(temp, ptr, BUFSIZ);
XmTextFieldInsert(XmDropDown_text(cbw), text_loc, ptr);
XtFree((char *) ptr);
text_loc += len;
if (++i >= count)
break;
XmTextFieldInsert(XmDropDown_text(cbw), text_loc, ",");
text_loc++;
}
XmTextFieldSetInsertionPosition(XmDropDown_text(cbw), 0);
return(FALSE);
}
/************************************************************
*
* Public Routines.
*
************************************************************/
/* Function Name: XmDropDownGetValue
* Description: Retreives the value from the combo box.
* Arguments: w - the combination box.
* Returns: The value in the text widget.
*/
String
XmDropDownGetValue(Widget w)
{
XmDropDownWidget cbw = (XmDropDownWidget) w;
String ptr;
_XmWidgetToAppContext(w);
_XmAppLock(app);
ptr = XmTextFieldGetString(XmDropDown_text(cbw));
_XmAppUnlock(app);
return ptr;
}
/* Function Name: XmCreateDropDown
* Description: Creation Routine for UIL and ADA.
* Arguments: parent - the parent widget.
* name - the name of the widget.
* args, num_args - the number and list of args.
* Returns: The created widget.
*/
Widget
XmCreateDropDown(Widget parent, String name,
ArgList args, Cardinal num_args)
{
return(XtCreateWidget(name, xmDropDownWidgetClass,
parent, args, num_args));
}
Widget
XmVaCreateDropDown(
Widget parent,
char *name,
...)
{
register Widget w;
va_list var;
int count;
Va_start(var,name);
count = XmeCountVaListSimple(var);
va_end(var);
Va_start(var, name);
w = XmeVLCreateWidget(name,
xmDropDownWidgetClass,
parent, False,
var, count);
va_end(var);
return w;
}
Widget
XmVaCreateManagedDropDown(
Widget parent,
char *name,
...)
{
Widget w = NULL;
va_list var;
int count;
Va_start(var, name);
count = XmeCountVaListSimple(var);
va_end(var);
Va_start(var, name);
w = XmeVLCreateWidget(name,
xmDropDownWidgetClass,
parent, True,
var, count);
va_end(var);
return w;
}
/* Function Name: XmDropDownGetLabel
* Description: Returns the "label" child of the XmDropDown
* Arguments: w - The XmDropDown Widget
* Returns: The specified child of the XmDropDown
*/
Widget XmDropDownGetLabel(Widget w)
{
if(!XtIsSubclass(w, xmDropDownWidgetClass))
return NULL;
return XmDropDown_label(w);
}
/* Function Name: XmDropDownGetArrow
* Description: Returns the "arrow" child of the XmDropDown
* Arguments: w - The XmDropDown Widget
* Returns: The specified child of the XmDropDown
*/
Widget XmDropDownGetArrow(Widget w)
{
if(!XtIsSubclass(w, xmDropDownWidgetClass))
return NULL;
return XmDropDown_arrow(w);
}
/* Function Name: XmDropDownGetText
* Description: Returns the "text" child of the XmDropDown
* Arguments: w - The XmDropDown Widget
* Returns: The specified child of the XmDropDown
*/
Widget XmDropDownGetText(Widget w)
{
if(!XtIsSubclass(w, xmDropDownWidgetClass))
return NULL;
return XmDropDown_text(w);
}
/* Function Name: XmDropDownGetList
* Description: Returns the "list" child of the XmDropDown
* Arguments: w - The XmDropDown Widget
* Returns: The specified child of the XmDropDown
*/
Widget XmDropDownGetList(Widget w)
{
if(!XtIsSubclass(w, xmDropDownWidgetClass))
return NULL;
return XtNameToWidget(w, "*list");
}
/* Function Name: XmDropDownGetChild
* Description: Returns the child widget id of the XmDropDown
* Arguments: w - The XmDropDown Widget
* Returns: The specified child of the XmDropDown
*/
Widget XmDropDownGetChild(Widget w, int num)
{
XmDropDownWidget cbw = (XmDropDownWidget) w;
Widget child;
_XmWidgetToAppContext(w);
_XmAppLock(app);
if(!XtIsSubclass(w, xmDropDownWidgetClass))
{
_XmAppUnlock(app);
return NULL;
}
switch (num)
{
XmDROPDOWN_LABEL:
child = XmDropDown_label(w);
XmDROPDOWN_TEXT:
child = XmDropDown_text(w);
XmDROPDOWN_ARROW_BUTTON:
child = XmDropDown_arrow(w);
XmDROPDOWN_LIST:
child = XmDropDown_list(w);
default:
child = NULL;
}
_XmAppUnlock(app);
return child;
}
/* aliases for deprecated functions of XmComboBox2 */
extern WidgetClass xmCombinationBox2WidgetClass XM_ALIAS(xmDropDownWidgetClass);
String XmCombinationBox2GetValue(Widget) XM_ALIAS(XmDropDownGetValue);
Widget XmCreateCombinationBox2(Widget, char *, ArgList, Cardinal) XM_ALIAS(XmCreateDropDown);
Widget XmVaCreateCombinationBox2(Widget, char *, ...) XM_ALIAS(XmVaCreateDropDown);
Widget XmVaCreateManagedCombinationBox2(Widget, char *, ...) XM_ALIAS(XmVaCreateManagedDropDown);
Widget XmCombinationBox2GetLabel(Widget) XM_ALIAS(XmDropDownGetLabel);
Widget XmCombinationBox2GetArrow(Widget) XM_ALIAS(XmDropDownGetArrow);
Widget XmCombinationBox2GetText(Widget) XM_ALIAS(XmDropDownGetText);
Widget XmCombinationBox2GetList(Widget) XM_ALIAS(XmDropDownGetList);
Widget XmCombinationBox2GetChild(Widget, int) XM_ALIAS(XmDropDownGetChild);
extern XmDropDownClassRec xmCombinationBox2ClassRec XM_ALIAS(xmDropDownClassRec);